diff --git a/.autofix.markdownlint-cli2.jsonc b/.autofix.markdownlint-cli2.jsonc new file mode 100644 index 0000000000000..5d7f87fcab44d --- /dev/null +++ b/.autofix.markdownlint-cli2.jsonc @@ -0,0 +1,8 @@ +{ + "config": { + "default": false, + "no-trailing-spaces": { + "br_spaces": 0 + } + } +} diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 03e3979de4f94..0000000000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,2756 +0,0 @@ -version: 2.1 - -parameters: - upload-to-s3: - type: string - default: '1' - - run-lint: - type: boolean - default: true - - run-build-linux: - type: boolean - default: true - - run-build-mac: - type: boolean - default: true - - run-linux-x64-publish: - type: boolean - default: false - - run-linux-ia32-publish: - type: boolean - default: false - - run-linux-arm-publish: - type: boolean - default: false - - run-linux-arm64-publish: - type: boolean - default: false - - run-osx-publish: - type: boolean - default: false - - run-osx-publish-arm64: - type: boolean - default: false - - run-mas-publish: - type: boolean - default: false - - run-mas-publish-arm64: - type: boolean - default: false - - run-linux-publish: - type: boolean - default: false - - run-macos-publish: - type: boolean - default: false - -# The config expects the following environment variables to be set: -# - "SLACK_WEBHOOK" Slack hook URL to send notifications. -# -# The publishing scripts expect access tokens to be defined as env vars, -# but those are not covered here. -# -# CircleCI docs on variables: -# https://circleci.com/docs/2.0/env-vars/ - -# Build machines configs. -docker-image: &docker-image - docker: - - image: electron.azurecr.io/build:4cec2c5ab66765caa724e37bae2bffb9b29722a5 - -machine-linux-medium: &machine-linux-medium - <<: *docker-image - resource_class: medium - -machine-linux-xlarge: &machine-linux-xlarge - <<: *docker-image - resource_class: xlarge - -machine-linux-2xlarge: &machine-linux-2xlarge - <<: *docker-image - resource_class: 2xlarge+ - -machine-mac: &machine-mac - macos: - xcode: "12.2.0" - -machine-mac-large: &machine-mac-large - resource_class: large - macos: - xcode: "12.2.0" - -machine-mac-large-arm: &machine-mac-large-arm - resource_class: large - macos: - xcode: "12.2.0" - -# Build configurations options. -env-testing-build: &env-testing-build - GN_CONFIG: //electron/build/args/testing.gn - CHECK_DIST_MANIFEST: '1' - -env-release-build: &env-release-build - GN_CONFIG: //electron/build/args/release.gn - STRIP_BINARIES: true - GENERATE_SYMBOLS: true - CHECK_DIST_MANIFEST: '1' - IS_RELEASE: true - -env-headless-testing: &env-headless-testing - DISPLAY: ':99.0' - -env-stack-dumping: &env-stack-dumping - ELECTRON_ENABLE_STACK_DUMPING: '1' - -env-browsertests: &env-browsertests - GN_CONFIG: //electron/build/args/native_tests.gn - BUILD_TARGET: electron/spec:chromium_browsertests - TESTS_CONFIG: src/electron/spec/configs/browsertests.yml - -env-unittests: &env-unittests - GN_CONFIG: //electron/build/args/native_tests.gn - BUILD_TARGET: electron/spec:chromium_unittests - TESTS_CONFIG: src/electron/spec/configs/unittests.yml - -# Build targets options. -env-ia32: &env-ia32 - GN_EXTRA_ARGS: 'target_cpu = "x86"' - NPM_CONFIG_ARCH: ia32 - TARGET_ARCH: ia32 - -env-arm: &env-arm - GN_EXTRA_ARGS: 'target_cpu = "arm"' - MKSNAPSHOT_TOOLCHAIN: //build/toolchain/linux:clang_arm - BUILD_NATIVE_MKSNAPSHOT: 1 - TARGET_ARCH: arm - -env-apple-silicon: &env-apple-silicon - GN_EXTRA_ARGS: 'target_cpu = "arm64" use_prebuilt_v8_context_snapshot = true' - TARGET_ARCH: arm64 - USE_PREBUILT_V8_CONTEXT_SNAPSHOT: 1 - -env-arm64: &env-arm64 - GN_EXTRA_ARGS: 'target_cpu = "arm64" fatal_linker_warnings = false enable_linux_installer = false' - MKSNAPSHOT_TOOLCHAIN: //build/toolchain/linux:clang_arm64 - BUILD_NATIVE_MKSNAPSHOT: 1 - TARGET_ARCH: arm64 - -env-mas: &env-mas - GN_EXTRA_ARGS: 'is_mas_build = true' - MAS_BUILD: 'true' - -env-mas-apple-silicon: &env-mas-apple-silicon - GN_EXTRA_ARGS: 'target_cpu = "arm64" is_mas_build = true use_prebuilt_v8_context_snapshot = true' - MAS_BUILD: 'true' - TARGET_ARCH: arm64 - USE_PREBUILT_V8_CONTEXT_SNAPSHOT: 1 - -env-send-slack-notifications: &env-send-slack-notifications - NOTIFY_SLACK: true - -env-global: &env-global - ELECTRON_OUT_DIR: Default - -env-linux-medium: &env-linux-medium - <<: *env-global - NUMBER_OF_NINJA_PROCESSES: 3 - -env-linux-2xlarge: &env-linux-2xlarge - <<: *env-global - NUMBER_OF_NINJA_PROCESSES: 34 - -env-linux-2xlarge-release: &env-linux-2xlarge-release - <<: *env-global - NUMBER_OF_NINJA_PROCESSES: 16 - -env-machine-mac: &env-machine-mac - <<: *env-global - NUMBER_OF_NINJA_PROCESSES: 6 - -env-mac-large: &env-mac-large - <<: *env-global - NUMBER_OF_NINJA_PROCESSES: 18 - -env-mac-large-release: &env-mac-large-release - <<: *env-global - NUMBER_OF_NINJA_PROCESSES: 8 - -env-ninja-status: &env-ninja-status - NINJA_STATUS: "[%r processes, %f/%t @ %o/s : %es] " - -env-disable-run-as-node: &env-disable-run-as-node - GN_BUILDFLAG_ARGS: 'enable_run_as_node = false' - -env-32bit-release: &env-32bit-release - # Set symbol level to 1 for 32 bit releases because of https://crbug.com/648948 - GN_BUILDFLAG_ARGS: 'symbol_level = 1' - -env-macos-build: &env-macos-build - # Disable pre-compiled headers to reduce out size, only useful for rebuilds - GN_BUILDFLAG_ARGS: 'enable_precompiled_headers = false' - -# Individual (shared) steps. -step-maybe-notify-slack-failure: &step-maybe-notify-slack-failure - run: - name: Send a Slack notification on failure - command: | - if [ "$NOTIFY_SLACK" == "true" ]; then - export MESSAGE="Build failed for *<$CIRCLE_BUILD_URL|$CIRCLE_JOB>* nightly build from *$CIRCLE_BRANCH*." - curl -g -H "Content-Type: application/json" -X POST \ - -d "{\"text\": \"$MESSAGE\", \"attachments\": [{\"color\": \"#FC5C3C\",\"title\": \"$CIRCLE_JOB nightly build results\",\"title_link\": \"$CIRCLE_BUILD_URL\"}]}" $SLACK_WEBHOOK - fi - when: on_fail - -step-maybe-notify-slack-success: &step-maybe-notify-slack-success - run: - name: Send a Slack notification on success - command: | - if [ "$NOTIFY_SLACK" == "true" ]; then - export MESSAGE="Build succeeded for *<$CIRCLE_BUILD_URL|$CIRCLE_JOB>* nightly build from *$CIRCLE_BRANCH*." - curl -g -H "Content-Type: application/json" -X POST \ - -d "{\"text\": \"$MESSAGE\", \"attachments\": [{\"color\": \"good\",\"title\": \"$CIRCLE_JOB nightly build results\",\"title_link\": \"$CIRCLE_BUILD_URL\"}]}" $SLACK_WEBHOOK - fi - when: on_success - -step-checkout-electron: &step-checkout-electron - checkout: - path: src/electron - -step-depot-tools-get: &step-depot-tools-get - run: - name: Get depot tools - command: | - git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git - -step-depot-tools-add-to-path: &step-depot-tools-add-to-path - run: - name: Add depot tools to PATH - command: echo 'export PATH="$PATH:'"$PWD"'/depot_tools"' >> $BASH_ENV - -step-gclient-sync: &step-gclient-sync - run: - name: Gclient sync - command: | - # If we did not restore a complete sync then we need to sync for realz - if [ ! -s "src/electron/.circle-sync-done" ]; then - gclient config \ - --name "src/electron" \ - --unmanaged \ - $GCLIENT_EXTRA_ARGS \ - "$CIRCLE_REPOSITORY_URL" - - ELECTRON_USE_THREE_WAY_MERGE_FOR_PATCHES=1 gclient sync --with_branch_heads --with_tags - if [ "$IS_RELEASE" != "true" ]; then - # Re-export all the patches to check if there were changes. - python src/electron/script/export_all_patches.py src/electron/patches/config.json - cd src/electron - git update-index --refresh || true - if ! git diff-index --quiet HEAD --; then - # There are changes to the patches. Make a git commit with the updated patches - git add patches - GIT_COMMITTER_NAME="Electron Bot" GIT_COMMITTER_EMAIL="electron@github.com" git commit -m "update patches" --author="Electron Bot " - # Export it - mkdir -p ../../patches - git format-patch -1 --stdout --keep-subject --no-stat --full-index > ../../patches/update-patches.patch - if (node ./script/push-patch.js 2> /dev/null > /dev/null); then - echo - echo "======================================================================" - echo "Changes to the patches when applying, we have auto-pushed the diff to the current branch" - echo "A new CI job will kick off shortly" - echo "======================================================================" - exit 1 - else - echo - echo "======================================================================" - echo "There were changes to the patches when applying." - echo "Check the CI artifacts for a patch you can apply to fix it." - echo "======================================================================" - exit 1 - fi - fi - fi - fi - -step-setup-env-for-build: &step-setup-env-for-build - run: - name: Setup Environment Variables - command: | - # To find `gn` executable. - echo 'export CHROMIUM_BUILDTOOLS_PATH="'"$PWD"'/src/buildtools"' >> $BASH_ENV - -step-setup-goma-for-build: &step-setup-goma-for-build - run: - name: Setup Goma - command: | - if [ "`uname`" == "Linux" ]; then - echo 'export NUMBER_OF_NINJA_PROCESSES=300' >> $BASH_ENV - else - echo 'export NUMBER_OF_NINJA_PROCESSES=25' >> $BASH_ENV - fi - if [ ! -z "$RAW_GOMA_AUTH" ]; then - echo $RAW_GOMA_AUTH > ~/.goma_oauth2_config - fi - git clone https://github.com/electron/build-tools.git - cd build-tools - npm install - mkdir third_party - node -e "require('./src/utils/goma.js').downloadAndPrepare()" - node -e "require('./src/utils/goma.js').ensure()" - echo 'export GN_GOMA_FILE='`node -e "console.log(require('./src/utils/goma.js').gnFilePath)"` >> $BASH_ENV - echo 'export LOCAL_GOMA_DIR='`node -e "console.log(require('./src/utils/goma.js').dir)"` >> $BASH_ENV - cd .. - -step-restore-brew-cache: &step-restore-brew-cache - restore_cache: - paths: - - /usr/local/Homebrew - keys: - - v2-brew-cache-{{ arch }} - -step-save-brew-cache: &step-save-brew-cache - save_cache: - paths: - - /usr/local/Homebrew - key: v2-brew-cache-{{ arch }} - name: Persisting brew cache - -step-get-more-space-on-mac: &step-get-more-space-on-mac - run: - name: Free up space on MacOS - command: | - if [ "`uname`" == "Darwin" ]; then - sudo mkdir -p $TMPDIR/del-target - if [ "$TARGET_ARCH" == "arm64" ]; then - # Remount the root volume as writable, don't ask questions plz - sudo mount -uw / - fi - tmpify() { - if [ -d "$1" ]; then - sudo mv "$1" $TMPDIR/del-target/$(echo $1|shasum -a 256|head -n1|cut -d " " -f1) - fi - } - - strip_arm_deep() { - opwd=$(pwd) - cd $1 - f=$(find . -perm +111 -type f) - for fp in $f - do - if [[ $(file "$fp") == *"universal binary"* ]]; then - if [[ $(file "$fp") == *"arm64e)"* ]]; then - sudo lipo -remove arm64e "$fp" -o "$fp" || true - fi - if [[ $(file "$fp") == *"arm64)"* ]]; then - sudo lipo -remove arm64 "$fp" -o "$fp" || true - fi - fi - done - - cd $opwd - } - - tmpify /Library/Developer/CoreSimulator - tmpify ~/Library/Developer/CoreSimulator - tmpify $(xcode-select -p)/Platforms/AppleTVOS.platform - tmpify $(xcode-select -p)/Platforms/iPhoneOS.platform - tmpify $(xcode-select -p)/Platforms/WatchOS.platform - tmpify $(xcode-select -p)/Platforms/WatchSimulator.platform - tmpify $(xcode-select -p)/Platforms/AppleTVSimulator.platform - tmpify $(xcode-select -p)/Platforms/iPhoneSimulator.platform - tmpify $(xcode-select -p)/Toolchains/XcodeDefault.xctoolchain/usr/metal/ios - tmpify $(xcode-select -p)/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift - tmpify $(xcode-select -p)/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift-5.0 - tmpify ~/.rubies - tmpify ~/Library/Caches/Homebrew - tmpify /usr/local/Homebrew - sudo rm -rf $TMPDIR/del-target - - if [ "$TARGET_ARCH" == "arm64" ]; then - sudo rm -rf "/System/Library/Desktop Pictures" - sudo rm -rf /System/Library/Templates/Data - sudo rm -rf /System/Library/Speech/Voices - sudo rm -rf "/System/Library/Screen Savers" - sudo rm -rf /System/Volumes/Data/Library/Developer/CommandLineTools/SDKs - sudo rm -rf "/System/Volumes/Data/Library/Application Support/Apple/Photos/Print Products" - sudo rm -rf /System/Volumes/Data/Library/Java - sudo rm -rf /System/Volumes/Data/Library/Ruby - sudo rm -rf /System/Volumes/Data/Library/Printers - sudo rm -rf /System/iOSSupport - sudo rm -rf /System/Applications/*.app - sudo rm -rf /System/Applications/Utilities/*.app - sudo rm -rf /System/Library/LinguisticData - sudo rm -rf /System/Volumes/Data/private/var/db/dyld/* - # sudo rm -rf /System/Library/Fonts/* - # sudo rm -rf /System/Library/PreferencePanes - sudo rm -rf /System/Library/AssetsV2/* - sudo rm -rf /Applications/Safari.app - sudo rm -rf ~/project/src/build/linux - sudo rm -rf ~/project/src/third_party/catapult/tracing/test_data - sudo rm -rf ~/project/src/third_party/angle/third_party/VK-GL-CTS - - # lipo off some huge binaries arm64 versions to save space - strip_arm_deep $(xcode-select -p)/../SharedFrameworks - strip_arm_deep /System/Volumes/Data/Library/Developer/CommandLineTools/usr - fi - fi - background: true - -# On macOS delete all .git directories under src/ expect for -# third_party/angle/ because of build time generation of file -# gen/angle/commit.h depends on third_party/angle/.git/HEAD -# https://chromium-review.googlesource.com/c/angle/angle/+/2074924 -# TODO: maybe better to always leave out */.git/HEAD file for all targets ? -step-delete-git-directories: &step-delete-git-directories - run: - name: Delete all .git directories under src on MacOS to free space - command: | - if [ "`uname`" == "Darwin" ]; then - cd src - ( find . -type d -name ".git" -not -path "./third_party/angle/*" ) | xargs rm -rf - fi - -# On macOS the yarn install command during gclient sync was run on a linux -# machine and therefore installed a slightly different set of dependencies -# Notably "fsevents" is a macOS only dependency, we rerun yarn install once -# we are on a macOS machine to get the correct state -step-install-npm-deps-on-mac: &step-install-npm-deps-on-mac - run: - name: Install node_modules on MacOS - command: | - if [ "`uname`" == "Darwin" ]; then - cd src/electron - node script/yarn install - fi - -# This step handles the differences between the linux "gclient sync" -# and the expected state on macOS -step-fix-sync-on-mac: &step-fix-sync-on-mac - run: - name: Fix Sync on macOS - command: | - if [ "`uname`" == "Darwin" ]; then - # Fix Clang Install (wrong binary) - rm -rf src/third_party/llvm-build - python src/tools/clang/scripts/update.py - # Fix Framework Header Installs (symlinks not retained) - rm -rf src/electron/external_binaries - python src/electron/script/update-external-binaries.py - fi - -step-install-signing-cert-on-mac: &step-install-signing-cert-on-mac - run: - name: Import and trust self-signed codesigning cert on MacOS - command: | - if [ "`uname`" == "Darwin" ]; then - cd src/electron - ./script/codesign/generate-identity.sh - fi - -step-install-gnutar-on-mac: &step-install-gnutar-on-mac - run: - name: Install gnu-tar on macos - command: | - if [ "`uname`" == "Darwin" ]; then - brew update - brew install gnu-tar - ln -fs /usr/local/bin/gtar /usr/local/bin/tar - fi - -step-gn-gen-default: &step-gn-gen-default - run: - name: Default GN gen - command: | - cd src - gn gen out/Default --args="import(\"$GN_CONFIG\") import(\"$GN_GOMA_FILE\") $GN_EXTRA_ARGS $GN_BUILDFLAG_ARGS" - -step-gn-check: &step-gn-check - run: - name: GN check - command: | - cd src - gn check out/Default //electron:electron_lib - gn check out/Default //electron:electron_app - gn check out/Default //electron:manifests - gn check out/Default //electron/shell/common/api:mojo - # Check the hunspell filenames - node electron/script/gen-hunspell-filenames.js --check - -step-electron-build: &step-electron-build - run: - name: Electron build - no_output_timeout: 30m - command: | - # On arm platforms we generate a cross-arch ffmpeg that ninja does not seem - # to realize is not correct / should be rebuilt. We delete it here so it is - # rebuilt - if [ "$TRIGGER_ARM_TEST" == "true" ]; then - rm -f src/out/Default/libffmpeg.so - fi - cd src - # Enable if things get really bad - # if [ "$TARGET_ARCH" == "arm64" ] &&[ "`uname`" == "Darwin" ]; then - # diskutil erasevolume HFS+ "xcode_disk" `hdiutil attach -nomount ram://12582912` - # mv /Applications/Xcode-12.beta.5.app /Volumes/xcode_disk/ - # ln -s /Volumes/xcode_disk/Xcode-12.beta.5.app /Applications/Xcode-12.beta.5.app - # fi - - # Lets generate a snapshot and mksnapshot and then delete all the x-compiled generated files to save space - if [ "$USE_PREBUILT_V8_CONTEXT_SNAPSHOT" == "1" ]; then - ninja -C out/Default electron:electron_mksnapshot_zip -j $NUMBER_OF_NINJA_PROCESSES - ninja -C out/Default tools/v8_context_snapshot -j $NUMBER_OF_NINJA_PROCESSES - gn desc out/Default v8:run_mksnapshot_default args > out/Default/mksnapshot_args - rm -rf out/Default/clang_x64_v8_arm64/obj - - # Regenerate because we just deleted some ninja files - gn gen out/Default --args="import(\"$GN_CONFIG\") import(\"$GN_GOMA_FILE\") $GN_EXTRA_ARGS $GN_BUILDFLAG_ARGS" - fi - ninja -C out/Default electron -j $NUMBER_OF_NINJA_PROCESSES - node electron/script/check-symlinks.js - -step-native-unittests-build: &step-native-unittests-build - run: - name: Build native test targets - no_output_timeout: 30m - command: | - cd src - ninja -C out/Default shell_browser_ui_unittests -j $NUMBER_OF_NINJA_PROCESSES - -step-maybe-electron-dist-strip: &step-maybe-electron-dist-strip - run: - name: Strip electron binaries - command: | - if [ "$STRIP_BINARIES" == "true" ] && [ "`uname`" == "Linux" ]; then - if [ x"$TARGET_ARCH" == x ]; then - target_cpu=x64 - elif [ "$TARGET_ARCH" == "ia32" ]; then - target_cpu=x86 - else - target_cpu="$TARGET_ARCH" - fi - cd src - electron/script/copy-debug-symbols.py --target-cpu="$target_cpu" --out-dir=out/Default/debug --compress - electron/script/strip-binaries.py --target-cpu="$target_cpu" - electron/script/add-debug-link.py --target-cpu="$target_cpu" --debug-dir=out/Default/debug - fi - -step-electron-dist-build: &step-electron-dist-build - run: - name: Build dist.zip - command: | - cd src - if [ "$SKIP_DIST_ZIP" != "1" ]; then - ninja -C out/Default electron:electron_dist_zip - if [ "$CHECK_DIST_MANIFEST" == "1" ]; then - if [ "`uname`" == "Darwin" ]; then - target_os=mac - target_cpu=x64 - if [ x"$MAS_BUILD" == x"true" ]; then - target_os=mac_mas - fi - if [ "$TARGET_ARCH" == "arm64" ]; then - target_cpu=arm64 - fi - elif [ "`uname`" == "Linux" ]; then - target_os=linux - if [ x"$TARGET_ARCH" == x ]; then - target_cpu=x64 - elif [ "$TARGET_ARCH" == "ia32" ]; then - target_cpu=x86 - else - target_cpu="$TARGET_ARCH" - fi - else - echo "Unknown system: `uname`" - exit 1 - fi - electron/script/zip_manifests/check-zip-manifest.py out/Default/dist.zip electron/script/zip_manifests/dist_zip.$target_os.$target_cpu.manifest - fi - fi - -step-electron-dist-store: &step-electron-dist-store - store_artifacts: - path: src/out/Default/dist.zip - destination: dist.zip - -step-electron-maybe-chromedriver-gn-gen: &step-electron-maybe-chromedriver-gn-gen - run: - name: chromedriver GN gen - command: | - cd src - if [ "$TARGET_ARCH" == "arm" ] || [ "$TARGET_ARCH" == "arm64" ]; then - gn gen out/chromedriver --args="import(\"$GN_CONFIG\") import(\"$GN_GOMA_FILE\") is_component_ffmpeg=false proprietary_codecs=false $GN_EXTRA_ARGS $GN_BUILDFLAG_ARGS" - fi - -step-electron-chromedriver-build: &step-electron-chromedriver-build - run: - name: Build chromedriver.zip - command: | - cd src - if [ "$TARGET_ARCH" == "arm" ] || [ "$TARGET_ARCH" == "arm64" ]; then - export CHROMEDRIVER_DIR="out/chromedriver" - else - export CHROMEDRIVER_DIR="out/Default" - fi - ninja -C $CHROMEDRIVER_DIR electron:electron_chromedriver -j $NUMBER_OF_NINJA_PROCESSES - if [ "`uname`" == "Linux" ]; then - electron/script/strip-binaries.py --target-cpu="$TARGET_ARCH" --file $PWD/$CHROMEDRIVER_DIR/chromedriver - fi - ninja -C $CHROMEDRIVER_DIR electron:electron_chromedriver_zip - if [ "$TARGET_ARCH" == "arm" ] || [ "$TARGET_ARCH" == "arm64" ]; then - cp out/chromedriver/chromedriver.zip out/Default - fi - -step-electron-chromedriver-store: &step-electron-chromedriver-store - store_artifacts: - path: src/out/Default/chromedriver.zip - destination: chromedriver.zip - -step-nodejs-headers-build: &step-nodejs-headers-build - run: - name: Build Node.js headers - command: | - cd src - ninja -C out/Default third_party/electron_node:headers - -step-nodejs-headers-store: &step-nodejs-headers-store - store_artifacts: - path: src/out/Default/gen/node_headers.tar.gz - destination: node_headers.tar.gz - -step-native-unittests-store: &step-native-unittests-store - store_artifacts: - path: src/out/Default/shell_browser_ui_unittests - destination: shell_browser_ui_unittests - -step-electron-publish: &step-electron-publish - run: - name: Publish Electron Dist - command: | - if [ "`uname`" == "Darwin" ]; then - rm -rf src/out/Default/obj - fi - - cd src/electron - if [ "$UPLOAD_TO_S3" == "1" ]; then - echo 'Uploading Electron release distribution to S3' - script/release/uploaders/upload.py --verbose --upload_to_s3 - else - echo 'Uploading Electron release distribution to Github releases' - script/release/uploaders/upload.py --verbose - fi - -step-persist-data-for-tests: &step-persist-data-for-tests - persist_to_workspace: - root: . - paths: - # Build artifacts - - src/out/Default/dist.zip - - src/out/Default/mksnapshot.zip - - src/out/Default/chromedriver.zip - - src/out/Default/shell_browser_ui_unittests - - src/out/Default/gen/node_headers - - src/out/ffmpeg/ffmpeg.zip - - src/electron - - src/third_party/electron_node - - src/third_party/nan - -step-electron-dist-unzip: &step-electron-dist-unzip - run: - name: Unzip dist.zip - command: | - cd src/out/Default - # -o overwrite files WITHOUT prompting - # TODO(alexeykuzmin): Remove '-o' when it's no longer needed. - unzip -o dist.zip - -step-ffmpeg-unzip: &step-ffmpeg-unzip - run: - name: Unzip ffmpeg.zip - command: | - cd src/out/ffmpeg - unzip -o ffmpeg.zip - -step-mksnapshot-unzip: &step-mksnapshot-unzip - run: - name: Unzip mksnapshot.zip - command: | - cd src/out/Default - unzip -o mksnapshot.zip - -step-chromedriver-unzip: &step-chromedriver-unzip - run: - name: Unzip chromedriver.zip - command: | - cd src/out/Default - unzip -o chromedriver.zip - -step-ffmpeg-gn-gen: &step-ffmpeg-gn-gen - run: - name: ffmpeg GN gen - command: | - cd src - gn gen out/ffmpeg --args="import(\"//electron/build/args/ffmpeg.gn\") import(\"$GN_GOMA_FILE\") $GN_EXTRA_ARGS" - -step-ffmpeg-build: &step-ffmpeg-build - run: - name: Non proprietary ffmpeg build - command: | - cd src - ninja -C out/ffmpeg electron:electron_ffmpeg_zip -j $NUMBER_OF_NINJA_PROCESSES - -step-verify-ffmpeg: &step-verify-ffmpeg - run: - name: Verify ffmpeg - command: | - cd src - python electron/script/verify-ffmpeg.py --source-root "$PWD" --build-dir out/Default --ffmpeg-path out/ffmpeg - -step-ffmpeg-store: &step-ffmpeg-store - store_artifacts: - path: src/out/ffmpeg/ffmpeg.zip - destination: ffmpeg.zip - -step-verify-mksnapshot: &step-verify-mksnapshot - run: - name: Verify mksnapshot - command: | - cd src - python electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default - -step-verify-chromedriver: &step-verify-chromedriver - run: - name: Verify ChromeDriver - command: | - cd src - python electron/script/verify-chromedriver.py --source-root "$PWD" --build-dir out/Default - -step-setup-linux-for-headless-testing: &step-setup-linux-for-headless-testing - run: - name: Setup for headless testing - command: | - if [ "`uname`" != "Darwin" ]; then - sh -e /etc/init.d/xvfb start - fi - -step-show-goma-stats: &step-show-goma-stats - run: - shell: /bin/bash - name: Check goma stats after build - command: | - set +e - set +o pipefail - $LOCAL_GOMA_DIR/goma_ctl.py stat - $LOCAL_GOMA_DIR/diagnose_goma_log.py - true - when: always - -step-mksnapshot-build: &step-mksnapshot-build - run: - name: mksnapshot build - command: | - cd src - if [ "$USE_PREBUILT_V8_CONTEXT_SNAPSHOT" != "1" ]; then - ninja -C out/Default electron:electron_mksnapshot -j $NUMBER_OF_NINJA_PROCESSES - gn desc out/Default v8:run_mksnapshot_default args > out/Default/mksnapshot_args - fi - if [ "`uname`" != "Darwin" ]; then - if [ "$TARGET_ARCH" == "arm" ]; then - electron/script/strip-binaries.py --file $PWD/out/Default/clang_x86_v8_arm/mksnapshot - electron/script/strip-binaries.py --file $PWD/out/Default/clang_x86_v8_arm/v8_context_snapshot_generator - elif [ "$TARGET_ARCH" == "arm64" ]; then - electron/script/strip-binaries.py --file $PWD/out/Default/clang_x64_v8_arm64/mksnapshot - electron/script/strip-binaries.py --file $PWD/out/Default/clang_x64_v8_arm64/v8_context_snapshot_generator - else - electron/script/strip-binaries.py --file $PWD/out/Default/mksnapshot - electron/script/strip-binaries.py --file $PWD/out/Default/v8_context_snapshot_generator - fi - fi - if [ "$USE_PREBUILT_V8_CONTEXT_SNAPSHOT" != "1" ] && [ "$SKIP_DIST_ZIP" != "1" ]; then - ninja -C out/Default electron:electron_mksnapshot_zip -j $NUMBER_OF_NINJA_PROCESSES - (cd out/Default; zip mksnapshot.zip mksnapshot_args gen/v8/embedded.S) - fi - -step-mksnapshot-store: &step-mksnapshot-store - store_artifacts: - path: src/out/Default/mksnapshot.zip - destination: mksnapshot.zip - -step-hunspell-build: &step-hunspell-build - run: - name: hunspell build - command: | - cd src - if [ "$SKIP_DIST_ZIP" != "1" ]; then - ninja -C out/Default electron:hunspell_dictionaries_zip -j $NUMBER_OF_NINJA_PROCESSES - fi - -step-hunspell-store: &step-hunspell-store - store_artifacts: - path: src/out/Default/hunspell_dictionaries.zip - destination: hunspell_dictionaries.zip - -step-maybe-generate-breakpad-symbols: &step-maybe-generate-breakpad-symbols - run: - name: Generate breakpad symbols - no_output_timeout: 30m - command: | - if [ "$GENERATE_SYMBOLS" == "true" ]; then - cd src - ninja -C out/Default electron:electron_symbols - fi - -step-maybe-zip-symbols: &step-maybe-zip-symbols - run: - name: Zip symbols - command: | - cd src - export BUILD_PATH="$PWD/out/Default" - ninja -C out/Default electron:licenses - ninja -C out/Default electron:electron_version - electron/script/zip-symbols.py -b $BUILD_PATH - -step-symbols-store: &step-symbols-store - store_artifacts: - path: src/out/Default/symbols.zip - destination: symbols.zip - -step-maybe-cross-arch-snapshot: &step-maybe-cross-arch-snapshot - run: - name: Generate cross arch snapshot (arm/arm64) - command: | - if [ "$TRIGGER_ARM_TEST" == "true" ] && [ -z "$CIRCLE_PR_NUMBER" ]; then - cd src - if [ "$TARGET_ARCH" == "arm" ]; then - export MKSNAPSHOT_PATH="clang_x86_v8_arm" - elif [ "$TARGET_ARCH" == "arm64" ]; then - export MKSNAPSHOT_PATH="clang_x64_v8_arm64" - fi - cp "out/Default/$MKSNAPSHOT_PATH/mksnapshot" out/Default - cp "out/Default/$MKSNAPSHOT_PATH/v8_context_snapshot_generator" out/Default - if [ "`uname`" == "Linux" ]; then - cp "out/Default/$MKSNAPSHOT_PATH/libffmpeg.so" out/Default - elif [ "`uname`" == "Darwin" ]; then - cp "out/Default/$MKSNAPSHOT_PATH/libffmpeg.dylib" out/Default - fi - python electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default --create-snapshot-only - mkdir cross-arch-snapshots - cp out/Default-mksnapshot-test/*.bin cross-arch-snapshots - fi - -step-maybe-cross-arch-snapshot-store: &step-maybe-cross-arch-snapshot-store - store_artifacts: - path: src/cross-arch-snapshots - destination: cross-arch-snapshots - -step-maybe-trigger-arm-test: &step-maybe-trigger-arm-test - run: - name: Trigger an arm test on VSTS if applicable - command: | - cd src - # Only run for non-fork prs - if [ "$TRIGGER_ARM_TEST" == "true" ] && [ -z "$CIRCLE_PR_NUMBER" ]; then - #Trigger VSTS job, passing along CircleCI job number and branch to build - if [ "`uname`" == "Darwin" ]; then - echo "Triggering electron-arm2-testing build on Azure DevOps" - node electron/script/release/ci-release-build.js --job=electron-arm2-testing --ci=DevOps --armTest --circleBuildNum=$CIRCLE_BUILD_NUM $CIRCLE_BRANCH - else - echo "Triggering electron-$TARGET_ARCH-testing build on VSTS" - node electron/script/release/ci-release-build.js --job=electron-$TARGET_ARCH-testing --ci=VSTS --armTest --circleBuildNum=$CIRCLE_BUILD_NUM $CIRCLE_BRANCH - fi - fi - -step-maybe-generate-typescript-defs: &step-maybe-generate-typescript-defs - run: - name: Generate type declarations - command: | - if [ "`uname`" == "Darwin" ]; then - cd src/electron - node script/yarn create-typescript-definitions - fi - -step-fix-known-hosts-linux: &step-fix-known-hosts-linux - run: - name: Fix Known Hosts on Linux - command: | - if [ "`uname`" == "Linux" ]; then - ./src/electron/.circleci/fix-known-hosts.sh - fi - -step-ninja-summary: &step-ninja-summary - run: - name: Print ninja summary - command: | - python depot_tools/post_build_ninja_summary.py -C src/out/Default - -step-ninja-report: &step-ninja-report - store_artifacts: - path: src/out/Default/.ninja_log - destination: ninja_log - -# Checkout Steps -step-generate-deps-hash: &step-generate-deps-hash - run: - name: Generate DEPS Hash - command: node src/electron/script/generate-deps-hash.js && cat src/electron/.depshash-target - -step-touch-sync-done: &step-touch-sync-done - run: - name: Touch Sync Done - command: touch src/electron/.circle-sync-done - -# Restore exact src cache based on the hash of DEPS and patches/* -# If no cache is matched EXACTLY then the .circle-sync-done file is empty -# If a cache is matched EXACTLY then the .circle-sync-done file contains "done" -step-maybe-restore-src-cache: &step-maybe-restore-src-cache - restore_cache: - keys: - - v8-src-cache-{{ checksum "src/electron/.depshash" }} - name: Restoring src cache -step-maybe-restore-src-cache-marker: &step-maybe-restore-src-cache-marker - restore_cache: - keys: - - v1-src-cache-marker-{{ checksum "src/electron/.depshash" }} - name: Restoring src cache marker - -# Restore exact or closest git cache based on the hash of DEPS and .circle-sync-done -# If the src cache was restored above then this will match an empty cache -# If the src cache was not restored above then this will match a close git cache -step-maybe-restore-git-cache: &step-maybe-restore-git-cache - restore_cache: - paths: - - ~/.gclient-cache - keys: - - v2-gclient-cache-{{ checksum "src/electron/.circle-sync-done" }}-{{ checksum "src/electron/DEPS" }} - - v2-gclient-cache-{{ checksum "src/electron/.circle-sync-done" }} - name: Conditionally restoring git cache - -step-restore-out-cache: &step-restore-out-cache - restore_cache: - paths: - - ./src/out/Default - keys: - - v9-out-cache-{{ checksum "src/electron/.depshash" }}-{{ checksum "src/electron/.depshash-target" }} - name: Restoring out cache - -step-set-git-cache-path: &step-set-git-cache-path - run: - name: Set GIT_CACHE_PATH to make gclient to use the cache - command: | - # CircleCI does not support interpolation when setting environment variables. - # https://circleci.com/docs/2.0/env-vars/#setting-an-environment-variable-in-a-shell-command - echo 'export GIT_CACHE_PATH="$HOME/.gclient-cache"' >> $BASH_ENV - -# Persist the git cache based on the hash of DEPS and .circle-sync-done -# If the src cache was restored above then this will persist an empty cache -step-save-git-cache: &step-save-git-cache - save_cache: - paths: - - ~/.gclient-cache - key: v2-gclient-cache-{{ checksum "src/electron/.circle-sync-done" }}-{{ checksum "src/electron/DEPS" }} - name: Persisting git cache - -step-save-out-cache: &step-save-out-cache - save_cache: - paths: - - ./src/out/Default - key: v9-out-cache-{{ checksum "src/electron/.depshash" }}-{{ checksum "src/electron/.depshash-target" }} - name: Persisting out cache - -step-run-electron-only-hooks: &step-run-electron-only-hooks - run: - name: Run Electron Only Hooks - command: gclient runhooks --spec="solutions=[{'name':'src/electron','url':None,'deps_file':'DEPS','custom_vars':{'process_deps':False},'managed':False}]" - -step-generate-deps-hash-cleanly: &step-generate-deps-hash-cleanly - run: - name: Generate DEPS Hash - command: (cd src/electron && git checkout .) && node src/electron/script/generate-deps-hash.js && cat src/electron/.depshash-target - -# Mark the sync as done for future cache saving -step-mark-sync-done: &step-mark-sync-done - run: - name: Mark Sync Done - command: echo DONE > src/electron/.circle-sync-done - -# Minimize the size of the cache -step-minimize-workspace-size-from-checkout: &step-minimize-workspace-size-from-checkout - run: - name: Remove some unused data to avoid storing it in the workspace/cache - command: | - rm -rf src/android_webview - rm -rf src/ios - rm -rf src/third_party/blink/web_tests - rm -rf src/third_party/blink/perf_tests - rm -rf src/third_party/WebKit/LayoutTests - rm -rf third_party/electron_node/deps/openssl - rm -rf third_party/electron_node/deps/v8 - rm -rf chrome/test/data/xr/webvr_info - -# Save the src cache based on the deps hash -step-save-src-cache: &step-save-src-cache - save_cache: - paths: - - /var/portal - key: v8-src-cache-{{ checksum "/var/portal/src/electron/.depshash" }} - name: Persisting src cache -step-make-src-cache-marker: &step-make-src-cache-marker - run: - name: Making src cache marker - command: touch .src-cache-marker -step-save-src-cache-marker: &step-save-src-cache-marker - save_cache: - paths: - - .src-cache-marker - key: v1-src-cache-marker-{{ checksum "/var/portal/src/electron/.depshash" }} - -# Check for doc only change -step-check-for-doc-only-change: &step-check-for-doc-only-change - run: - name: Check if commit is doc only change - command: | - cd src/electron - node script/yarn install --frozen-lockfile - if node script/doc-only-change.js --prNumber=$CIRCLE_PR_NUMBER --prURL=$CIRCLE_PULL_REQUEST --prBranch=$CIRCLE_BRANCH; then - #PR is doc only change; save file with value true to indicate doc only change - echo "true" > .skip-ci-build - else - #PR is not a doc only change; create empty file to indicate check has been done - touch .skip-ci-build - fi - -step-persist-doc-only-change: &step-persist-doc-only-change - persist_to_workspace: - root: . - paths: - - src/electron/.skip-ci-build - -step-maybe-early-exit-doc-only-change: &step-maybe-early-exit-doc-only-change - run: - name: Shortcircuit build if doc only change - command: | - if [ -s src/electron/.skip-ci-build ]; then - circleci-agent step halt - fi - -step-maybe-early-exit-no-doc-change: &step-maybe-early-exit-no-doc-change - run: - name: Shortcircuit job if change is not doc only - command: | - if [ ! -s src/electron/.skip-ci-build ]; then - circleci-agent step halt - fi - -step-ts-compile: &step-ts-compile - run: - name: Run TS/JS compile on doc only change - command: | - cd src - ninja -C out/Default electron:default_app_js -j $NUMBER_OF_NINJA_PROCESSES - ninja -C out/Default electron:electron_js2c -j $NUMBER_OF_NINJA_PROCESSES - -# Lists of steps. -steps-lint: &steps-lint - steps: - - *step-checkout-electron - - run: - name: Setup third_party Depot Tools - command: | - # "depot_tools" has to be checkout into "//third_party/depot_tools" so pylint.py can a "pylintrc" file. - git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git src/third_party/depot_tools - echo 'export PATH="$PATH:'"$PWD"'/src/third_party/depot_tools"' >> $BASH_ENV - - run: - name: Download GN Binary - command: | - chromium_revision="$(grep -A1 chromium_version src/electron/DEPS | tr -d '\n' | cut -d\' -f4)" - gn_version="$(curl -sL "https://chromium.googlesource.com/chromium/src/+/${chromium_revision}/DEPS?format=TEXT" | base64 -d | grep gn_version | head -n1 | cut -d\' -f4)" - - cipd ensure -ensure-file - -root . \<<-CIPD - \$ServiceURL https://chrome-infra-packages.appspot.com/ - @Subdir src/buildtools/linux64 - gn/gn/linux-amd64 $gn_version - CIPD - - echo 'export CHROMIUM_BUILDTOOLS_PATH="'"$PWD"'/src/buildtools"' >> $BASH_ENV - - run: - name: Download clang-format Binary - command: | - chromium_revision="$(grep -A1 chromium_version src/electron/DEPS | tr -d '\n' | cut -d\' -f4)" - - sha1_path='buildtools/linux64/clang-format.sha1' - curl -sL "https://chromium.googlesource.com/chromium/src/+/${chromium_revision}/${sha1_path}?format=TEXT" | base64 -d > "src/${sha1_path}" - - download_from_google_storage.py --no_resume --no_auth --bucket chromium-clang-format -s "src/${sha1_path}" - - run: - name: Run Lint - command: | - # gn.py tries to find a gclient root folder starting from the current dir. - # When it fails and returns "None" path, the whole script fails. Let's "fix" it. - touch .gclient - # Another option would be to checkout "buildtools" inside the Electron checkout, - # but then we would lint its contents (at least gn format), and it doesn't pass it. - - cd src/electron - node script/yarn install --frozen-lockfile - node script/yarn lint - - run: - name: Run Script Typechecker - command: | - cd src/electron - node script/yarn tsc -p tsconfig.script.json - -steps-checkout-and-save-cache: &steps-checkout-and-save-cache - steps: - - *step-checkout-electron - - *step-check-for-doc-only-change - - *step-persist-doc-only-change - - *step-maybe-early-exit-doc-only-change - - *step-depot-tools-get - - *step-depot-tools-add-to-path - - *step-restore-brew-cache - - *step-get-more-space-on-mac - - *step-install-gnutar-on-mac - - - *step-generate-deps-hash - - *step-touch-sync-done - - maybe-restore-portaled-src-cache: - halt-if-successful: true - - *step-maybe-restore-git-cache - - *step-set-git-cache-path - # This sync call only runs if .circle-sync-done is an EMPTY file - - *step-gclient-sync - - store_artifacts: - path: patches - - *step-save-git-cache - # These next few steps reset Electron to the correct commit regardless of which cache was restored - - run: - name: Wipe Electron - command: rm -rf src/electron - - *step-checkout-electron - - *step-run-electron-only-hooks - - *step-generate-deps-hash-cleanly - - *step-mark-sync-done - - *step-minimize-workspace-size-from-checkout - - *step-delete-git-directories - - run: - name: Move src folder to the cross-OS portal - command: | - sudo mkdir -p /var/portal - sudo chown -R $(id -u):$(id -g) /var/portal - mv ./src /var/portal - - *step-save-src-cache - - *step-make-src-cache-marker - - *step-save-src-cache-marker - -steps-electron-gn-check: &steps-electron-gn-check - steps: - - attach_workspace: - at: . - - *step-maybe-early-exit-doc-only-change - - *step-depot-tools-add-to-path - - *step-setup-env-for-build - - *step-setup-goma-for-build - - *step-gn-gen-default - - *step-gn-check - -steps-electron-ts-compile-for-doc-change: &steps-electron-ts-compile-for-doc-change - steps: - # Checkout - Copied ffrom steps-checkout - - *step-checkout-electron - - *step-check-for-doc-only-change - - *step-maybe-early-exit-no-doc-change - - *step-depot-tools-get - - *step-depot-tools-add-to-path - - *step-restore-brew-cache - - *step-install-gnutar-on-mac - - *step-get-more-space-on-mac - - *step-generate-deps-hash - - *step-touch-sync-done - - maybe-restore-portaled-src-cache - - *step-maybe-restore-git-cache - - *step-set-git-cache-path - # This sync call only runs if .circle-sync-done is an EMPTY file - - *step-gclient-sync - # These next few steps reset Electron to the correct commit regardless of which cache was restored - - run: - name: Wipe Electron - command: rm -rf src/electron - - *step-checkout-electron - - *step-run-electron-only-hooks - - *step-generate-deps-hash-cleanly - - *step-mark-sync-done - - *step-minimize-workspace-size-from-checkout - - - *step-depot-tools-add-to-path - - *step-setup-env-for-build - - *step-setup-goma-for-build - - *step-restore-brew-cache - - *step-get-more-space-on-mac - - *step-install-npm-deps-on-mac - - *step-fix-sync-on-mac - - *step-gn-gen-default - - #Compile ts/js to verify doc change didn't break anything - - *step-ts-compile - -steps-native-tests: &steps-native-tests - steps: - - attach_workspace: - at: . - - *step-depot-tools-add-to-path - - *step-setup-env-for-build - - *step-setup-goma-for-build - - *step-gn-gen-default - - - run: - name: Build tests - command: | - cd src - ninja -C out/Default $BUILD_TARGET - - *step-show-goma-stats - - - *step-setup-linux-for-headless-testing - - run: - name: Run tests - command: | - mkdir test_results - python src/electron/script/native-tests.py run \ - --config $TESTS_CONFIG \ - --tests-dir src/out/Default \ - --output-dir test_results \ - $TESTS_ARGS - - - store_artifacts: - path: test_results - destination: test_results # Put it in the root folder. - - store_test_results: - path: test_results - -steps-verify-ffmpeg: &steps-verify-ffmpeg - steps: - - attach_workspace: - at: . - - *step-depot-tools-add-to-path - - *step-electron-dist-unzip - - *step-ffmpeg-unzip - - *step-setup-linux-for-headless-testing - - - *step-verify-ffmpeg - - *step-maybe-notify-slack-failure - -steps-verify-chromedriver: &steps-verify-chromedriver - steps: - - attach_workspace: - at: . - - *step-depot-tools-add-to-path - - *step-electron-dist-unzip - - *step-chromedriver-unzip - - *step-setup-linux-for-headless-testing - - - *step-verify-chromedriver - - *step-maybe-notify-slack-failure - -steps-tests: &steps-tests - steps: - - attach_workspace: - at: . - - *step-maybe-early-exit-doc-only-change - - *step-depot-tools-add-to-path - - *step-electron-dist-unzip - - *step-mksnapshot-unzip - - *step-chromedriver-unzip - - *step-setup-linux-for-headless-testing - - *step-restore-brew-cache - - *step-fix-known-hosts-linux - - *step-install-signing-cert-on-mac - - - run: - name: Run Electron tests - environment: - MOCHA_REPORTER: mocha-multi-reporters - ELECTRON_TEST_RESULTS_DIR: junit - MOCHA_MULTI_REPORTERS: mocha-junit-reporter, tap - ELECTRON_DISABLE_SECURITY_WARNINGS: 1 - command: | - cd src - (cd electron && node script/yarn test --runners=main --trace-uncaught --enable-logging --files $(circleci tests glob spec-main/*-spec.ts | circleci tests split)) - (cd electron && node script/yarn test --runners=remote --trace-uncaught --enable-logging --files $(circleci tests glob spec/*-spec.js | circleci tests split)) - - run: - name: Check test results existence - command: | - cd src - - # Check if test results exist and are not empty. - if [ ! -s "junit/test-results-remote.xml" ]; then - exit 1 - fi - if [ ! -s "junit/test-results-main.xml" ]; then - exit 1 - fi - - store_test_results: - path: src/junit - - - *step-verify-mksnapshot - - *step-verify-chromedriver - - - *step-maybe-notify-slack-failure - -steps-test-nan: &steps-test-nan - steps: - - attach_workspace: - at: . - - *step-maybe-early-exit-doc-only-change - - *step-depot-tools-add-to-path - - *step-electron-dist-unzip - - *step-setup-linux-for-headless-testing - - *step-fix-known-hosts-linux - - run: - name: Run Nan Tests - command: | - cd src - node electron/script/nan-spec-runner.js - -steps-test-node: &steps-test-node - steps: - - attach_workspace: - at: . - - *step-maybe-early-exit-doc-only-change - - *step-depot-tools-add-to-path - - *step-electron-dist-unzip - - *step-setup-linux-for-headless-testing - - *step-fix-known-hosts-linux - - run: - name: Run Node Tests - command: | - cd src - node electron/script/node-spec-runner.js --default --jUnitDir=junit - - store_test_results: - path: src/junit - -chromium-upgrade-branches: &chromium-upgrade-branches - /chromium\-upgrade\/[0-9]+/ - -# Command Aliases -commands: - maybe-restore-portaled-src-cache: - parameters: - halt-if-successful: - type: boolean - default: false - steps: - - run: - name: Prepare for cross-OS sync restore - command: | - sudo mkdir -p /var/portal - sudo chown -R $(id -u):$(id -g) /var/portal - - when: - condition: << parameters.halt-if-successful >> - steps: - - *step-maybe-restore-src-cache-marker - - run: - name: Halt the job early if the src cache exists - command: | - if [ -f ".src-cache-marker" ]; then - circleci-agent step halt - fi - - *step-maybe-restore-src-cache - - run: - name: Fix the src cache restore point on macOS - command: | - if [ -d "/var/portal/src" ]; then - echo Relocating Cache - rm -rf src - mv /var/portal/src ./ - fi - checkout-from-cache: - steps: - - *step-checkout-electron - - *step-maybe-early-exit-doc-only-change - - *step-depot-tools-get - - *step-depot-tools-add-to-path - - *step-generate-deps-hash - - maybe-restore-portaled-src-cache - - run: - name: Ensure src checkout worked - command: | - if [ ! -d "src/third_party/blink" ]; then - echo src cache was not restored for some reason, idk what happened here... - exit 1 - fi - - run: - name: Wipe Electron - command: rm -rf src/electron - - *step-checkout-electron - - *step-run-electron-only-hooks - - *step-generate-deps-hash-cleanly - electron-build: - parameters: - attach: - type: boolean - default: false - persist: - type: boolean - default: true - persist-checkout: - type: boolean - default: false - checkout: - type: boolean - default: true - checkout-and-assume-cache: - type: boolean - default: false - build: - type: boolean - default: true - use-out-cache: - type: boolean - default: true - restore-src-cache: - type: boolean - default: true - preserve-vendor-dirs: - type: boolean - default: false - steps: - - when: - condition: << parameters.attach >> - steps: - - attach_workspace: - at: . - - *step-restore-brew-cache - - *step-install-gnutar-on-mac - - *step-save-brew-cache - - when: - condition: << parameters.checkout-and-assume-cache >> - steps: - - checkout-from-cache - - when: - condition: << parameters.checkout >> - steps: - # Checkout - Copied ffrom steps-checkout - - *step-checkout-electron - - *step-check-for-doc-only-change - - *step-persist-doc-only-change - - *step-maybe-early-exit-doc-only-change - - *step-depot-tools-get - - *step-depot-tools-add-to-path - - *step-get-more-space-on-mac - - *step-generate-deps-hash - - *step-touch-sync-done - - when: - condition: << parameters.restore-src-cache >> - steps: - - maybe-restore-portaled-src-cache - - *step-maybe-restore-git-cache - - *step-set-git-cache-path - # This sync call only runs if .circle-sync-done is an EMPTY file - - *step-gclient-sync - - store_artifacts: - path: patches - # These next few steps reset Electron to the correct commit regardless of which cache was restored - - when: - condition: << parameters.preserve-vendor-dirs >> - steps: - - run: - name: Preserve vendor dirs for release - command: | - mv src/electron/vendor/requests . - - run: - name: Wipe Electron - command: rm -rf src/electron - - *step-checkout-electron - - *step-run-electron-only-hooks - - when: - condition: << parameters.preserve-vendor-dirs >> - steps: - - run: - name: Preserve vendor dirs for release - command: | - rm -rf src/electron/vendor/requests - mv requests src/electron/vendor/requests - - *step-generate-deps-hash-cleanly - - *step-mark-sync-done - - *step-minimize-workspace-size-from-checkout - - when: - condition: << parameters.persist-checkout >> - steps: - - persist_to_workspace: - root: . - paths: - - depot_tools - - src - - - when: - condition: << parameters.build >> - steps: - - *step-depot-tools-add-to-path - - *step-setup-env-for-build - - *step-setup-goma-for-build - - *step-get-more-space-on-mac - - *step-fix-sync-on-mac - - *step-delete-git-directories - - # Electron app - - when: - condition: << parameters.use-out-cache >> - steps: - - *step-restore-out-cache - - *step-gn-gen-default - - *step-electron-build - - *step-ninja-summary - - *step-ninja-report - - *step-maybe-electron-dist-strip - - *step-electron-dist-build - - *step-electron-dist-store - - # Native test targets - - *step-native-unittests-build - - *step-native-unittests-store - - # Node.js headers - - *step-nodejs-headers-build - - *step-nodejs-headers-store - - - *step-show-goma-stats - - # mksnapshot - - *step-mksnapshot-build - - *step-mksnapshot-store - - *step-maybe-cross-arch-snapshot - - *step-maybe-cross-arch-snapshot-store - - # chromedriver - - *step-electron-maybe-chromedriver-gn-gen - - *step-electron-chromedriver-build - - *step-electron-chromedriver-store - - # ffmpeg - - *step-ffmpeg-gn-gen - - *step-ffmpeg-build - - *step-ffmpeg-store - - # hunspell - - *step-hunspell-build - - *step-hunspell-store - - # Save all data needed for a further tests run. - - when: - condition: << parameters.persist >> - steps: - - *step-persist-data-for-tests - - - when: - condition: << parameters.build >> - steps: - - *step-maybe-generate-breakpad-symbols - - *step-maybe-zip-symbols - - *step-symbols-store - - - when: - condition: << parameters.build >> - steps: - - run: - name: Remove the big things on macOS, this seems to be better on average - command: | - if [ "`uname`" == "Darwin" ]; then - mkdir -p src/out/Default - cd src/out/Default - find . -type f -size +50M -delete - mkdir -p gen/electron - cd gen/electron - # These files do not seem to like being in a cache, let us remove them - find . -type f -name '*_pkg_info' -delete - fi - - when: - condition: << parameters.use-out-cache >> - steps: - - *step-save-out-cache - - # Trigger tests on arm hardware if needed - - *step-maybe-trigger-arm-test - - - *step-maybe-notify-slack-failure - - electron-publish: - parameters: - attach: - type: boolean - default: false - checkout: - type: boolean - default: true - steps: - - when: - condition: << parameters.attach >> - steps: - - attach_workspace: - at: . - - when: - condition: << parameters.checkout >> - steps: - - *step-depot-tools-get - - *step-depot-tools-add-to-path - - *step-restore-brew-cache - - *step-get-more-space-on-mac - - when: - condition: << parameters.checkout >> - steps: - - *step-checkout-electron - - *step-gclient-sync - - *step-delete-git-directories - - *step-minimize-workspace-size-from-checkout - - *step-fix-sync-on-mac - - *step-setup-env-for-build - - *step-setup-goma-for-build - - *step-gn-gen-default - - # Electron app - - *step-electron-build - - *step-show-goma-stats - - *step-maybe-generate-breakpad-symbols - - *step-maybe-electron-dist-strip - - *step-electron-dist-build - - *step-electron-dist-store - - *step-maybe-zip-symbols - - *step-symbols-store - - # mksnapshot - - *step-mksnapshot-build - - *step-mksnapshot-store - - # chromedriver - - *step-electron-maybe-chromedriver-gn-gen - - *step-electron-chromedriver-build - - *step-electron-chromedriver-store - - # Node.js headers - - *step-nodejs-headers-build - - *step-nodejs-headers-store - - # ffmpeg - - *step-ffmpeg-gn-gen - - *step-ffmpeg-build - - *step-ffmpeg-store - - # hunspell - - *step-hunspell-build - - *step-hunspell-store - - # typescript defs - - *step-maybe-generate-typescript-defs - - # Publish - - *step-electron-publish - -# List of all jobs. -jobs: - # Layer 0: Lint. Standalone. - lint: - <<: *machine-linux-medium - environment: - <<: *env-linux-medium - <<: *steps-lint - - ts-compile-doc-change: - <<: *machine-linux-medium - environment: - <<: *env-linux-medium - <<: *env-testing-build - <<: *steps-electron-ts-compile-for-doc-change - - # Layer 1: Checkout. - linux-checkout: - <<: *machine-linux-2xlarge - environment: - <<: *env-linux-2xlarge - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True --custom-var=checkout_requests=True' - steps: - - electron-build: - persist: false - build: false - checkout: true - persist-checkout: true - restore-src-cache: false - preserve-vendor-dirs: true - - linux-checkout-fast: - <<: *machine-linux-2xlarge - environment: - <<: *env-linux-2xlarge - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' - steps: - - electron-build: - persist: false - build: false - checkout: true - persist-checkout: true - - linux-checkout-and-save-cache: - <<: *machine-linux-2xlarge - environment: - <<: *env-linux-2xlarge - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' - <<: *steps-checkout-and-save-cache - - linux-checkout-for-native-tests: - <<: *machine-linux-2xlarge - environment: - <<: *env-linux-2xlarge - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_pyyaml=True' - steps: - - electron-build: - persist: false - build: false - checkout: true - persist-checkout: true - - linux-checkout-for-native-tests-with-no-patches: - <<: *machine-linux-2xlarge - environment: - <<: *env-linux-2xlarge - GCLIENT_EXTRA_ARGS: '--custom-var=apply_patches=False --custom-var=checkout_pyyaml=True' - steps: - - electron-build: - persist: false - build: false - checkout: true - persist-checkout: true - - mac-checkout: - <<: *machine-linux-2xlarge - environment: - <<: *env-linux-2xlarge - <<: *env-testing-build - <<: *env-macos-build - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac --custom-var=checkout_requests=True' - steps: - - electron-build: - persist: false - build: false - checkout: true - persist-checkout: true - restore-src-cache: false - preserve-vendor-dirs: true - - mac-checkout-fast: - <<: *machine-linux-2xlarge - environment: - <<: *env-linux-2xlarge - <<: *env-testing-build - <<: *env-macos-build - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac' - steps: - - electron-build: - persist: false - build: false - checkout: true - persist-checkout: true - - mac-checkout-and-save-cache: - <<: *machine-linux-2xlarge - environment: - <<: *env-linux-2xlarge - <<: *env-testing-build - <<: *env-macos-build - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac' - <<: *steps-checkout-and-save-cache - - # Layer 2: Builds. - linux-x64-testing: - <<: *machine-linux-2xlarge - environment: - <<: *env-global - <<: *env-testing-build - <<: *env-ninja-status - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' - steps: - - electron-build: - persist: true - checkout: true - use-out-cache: false - - linux-x64-testing-no-run-as-node: - <<: *machine-linux-2xlarge - environment: - <<: *env-linux-2xlarge - <<: *env-testing-build - <<: *env-ninja-status - <<: *env-disable-run-as-node - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' - steps: - - electron-build: - persist: false - checkout: true - use-out-cache: false - - linux-x64-testing-gn-check: - <<: *machine-linux-medium - environment: - <<: *env-linux-medium - <<: *env-testing-build - <<: *steps-electron-gn-check - - linux-x64-release: - <<: *machine-linux-2xlarge - environment: - <<: *env-linux-2xlarge-release - <<: *env-release-build - <<: *env-send-slack-notifications - <<: *env-ninja-status - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' - steps: - - electron-build: - persist: true - checkout: true - - linux-x64-publish: - <<: *machine-linux-2xlarge - environment: - <<: *env-linux-2xlarge-release - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_requests=True' - <<: *env-release-build - UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >> - <<: *env-ninja-status - steps: - - electron-publish: - attach: false - checkout: true - - linux-x64-publish-skip-checkout: - <<: *machine-linux-2xlarge - environment: - <<: *env-linux-2xlarge-release - <<: *env-release-build - UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >> - <<: *env-ninja-status - steps: - - electron-publish: - attach: true - checkout: false - - linux-ia32-testing: - <<: *machine-linux-2xlarge - environment: - <<: *env-global - <<: *env-ia32 - <<: *env-testing-build - <<: *env-ninja-status - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' - steps: - - electron-build: - persist: true - checkout: true - use-out-cache: false - - linux-ia32-release: - <<: *machine-linux-2xlarge - environment: - <<: *env-linux-2xlarge-release - <<: *env-ia32 - <<: *env-release-build - <<: *env-send-slack-notifications - <<: *env-ninja-status - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' - steps: - - electron-build: - persist: true - checkout: true - - linux-ia32-publish: - <<: *machine-linux-2xlarge - environment: - <<: *env-linux-2xlarge-release - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_requests=True' - <<: *env-ia32 - <<: *env-release-build - <<: *env-32bit-release - UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >> - <<: *env-ninja-status - steps: - - electron-publish: - attach: false - checkout: true - - linux-ia32-publish-skip-checkout: - <<: *machine-linux-2xlarge - environment: - <<: *env-linux-2xlarge-release - <<: *env-ia32 - <<: *env-release-build - <<: *env-32bit-release - UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >> - <<: *env-ninja-status - steps: - - electron-publish: - attach: true - checkout: false - - linux-arm-testing: - <<: *machine-linux-2xlarge - environment: - <<: *env-global - <<: *env-arm - <<: *env-testing-build - <<: *env-ninja-status - TRIGGER_ARM_TEST: true - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' - steps: - - electron-build: - persist: false - checkout: true - use-out-cache: false - - linux-arm-release: - <<: *machine-linux-2xlarge - environment: - <<: *env-linux-2xlarge-release - <<: *env-arm - <<: *env-release-build - <<: *env-send-slack-notifications - <<: *env-ninja-status - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' - steps: - - electron-build: - persist: false - checkout: true - - linux-arm-publish: - <<: *machine-linux-2xlarge - environment: - <<: *env-linux-2xlarge-release - <<: *env-arm - <<: *env-release-build - <<: *env-32bit-release - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_requests=True' - UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >> - <<: *env-ninja-status - steps: - - electron-publish: - attach: false - checkout: true - - linux-arm-publish-skip-checkout: - <<: *machine-linux-2xlarge - environment: - <<: *env-linux-2xlarge-release - <<: *env-arm - <<: *env-release-build - <<: *env-32bit-release - UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >> - <<: *env-ninja-status - steps: - - electron-publish: - attach: true - checkout: false - - linux-arm64-testing: - <<: *machine-linux-2xlarge - environment: - <<: *env-global - <<: *env-arm64 - <<: *env-testing-build - <<: *env-ninja-status - TRIGGER_ARM_TEST: true - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' - steps: - - electron-build: - persist: false - checkout: true - use-out-cache: false - - linux-arm64-testing-gn-check: - <<: *machine-linux-medium - environment: - <<: *env-linux-medium - <<: *env-arm64 - <<: *env-testing-build - <<: *steps-electron-gn-check - - linux-arm64-release: - <<: *machine-linux-2xlarge - environment: - <<: *env-linux-2xlarge-release - <<: *env-arm64 - <<: *env-release-build - <<: *env-send-slack-notifications - <<: *env-ninja-status - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' - steps: - - electron-build: - persist: false - checkout: true - - linux-arm64-publish: - <<: *machine-linux-2xlarge - environment: - <<: *env-linux-2xlarge-release - <<: *env-arm64 - <<: *env-release-build - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm64=True --custom-var=checkout_requests=True' - UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >> - <<: *env-ninja-status - steps: - - electron-publish: - attach: false - checkout: true - - linux-arm64-publish-skip-checkout: - <<: *machine-linux-2xlarge - environment: - <<: *env-linux-2xlarge-release - <<: *env-arm64 - <<: *env-release-build - UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >> - <<: *env-ninja-status - steps: - - electron-publish: - attach: true - checkout: false - - osx-testing-x64: - <<: *machine-mac-large - environment: - <<: *env-mac-large - <<: *env-testing-build - <<: *env-ninja-status - <<: *env-macos-build - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac' - steps: - - electron-build: - persist: true - checkout: false - checkout-and-assume-cache: true - attach: false - - osx-testing-x64-gn-check: - <<: *machine-mac - environment: - <<: *env-machine-mac - <<: *env-testing-build - <<: *steps-electron-gn-check - - osx-release-x64: - <<: *machine-mac-large - environment: - <<: *env-mac-large - <<: *env-release-build - <<: *env-ninja-status - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac' - steps: - - electron-build: - persist: true - checkout: false - checkout-and-assume-cache: true - attach: false - - osx-publish-x64: - <<: *machine-mac-large - environment: - <<: *env-mac-large-release - <<: *env-release-build - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_requests=True' - UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >> - <<: *env-ninja-status - steps: - - electron-publish: - attach: false - checkout: true - - osx-publish-arm64: - <<: *machine-mac-large-arm - environment: - <<: *env-mac-large-release - <<: *env-release-build - <<: *env-apple-silicon - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_requests=True' - UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >> - <<: *env-ninja-status - steps: - - electron-publish: - attach: false - checkout: true - - osx-publish-x64-skip-checkout: - <<: *machine-mac-large - environment: - <<: *env-mac-large-release - <<: *env-release-build - UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >> - <<: *env-ninja-status - steps: - - electron-publish: - attach: true - checkout: false - - osx-publish-arm64-skip-checkout: - <<: *machine-mac-large-arm - environment: - <<: *env-mac-large-release - <<: *env-release-build - <<: *env-apple-silicon - UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >> - <<: *env-ninja-status - steps: - - electron-publish: - attach: true - checkout: false - - osx-testing-arm64: - <<: *machine-mac-large-arm - environment: - <<: *env-mac-large - <<: *env-testing-build - <<: *env-ninja-status - <<: *env-macos-build - <<: *env-apple-silicon - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac' - steps: - - electron-build: - persist: true - checkout: false - checkout-and-assume-cache: true - attach: false - - mas-testing-x64: - <<: *machine-mac-large - environment: - <<: *env-mac-large - <<: *env-mas - <<: *env-testing-build - <<: *env-ninja-status - <<: *env-macos-build - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac' - steps: - - electron-build: - persist: true - checkout: false - checkout-and-assume-cache: true - attach: false - - mas-testing-x64-gn-check: - <<: *machine-mac - environment: - <<: *env-machine-mac - <<: *env-mas - <<: *env-testing-build - <<: *steps-electron-gn-check - - mas-release: - <<: *machine-mac-large - environment: - <<: *env-mac-large - <<: *env-mas - <<: *env-release-build - <<: *env-ninja-status - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac' - steps: - - electron-build: - persist: true - checkout: false - checkout-and-assume-cache: true - attach: false - - mas-publish: - <<: *machine-mac-large - environment: - <<: *env-mac-large-release - <<: *env-mas - <<: *env-release-build - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_requests=True' - UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >> - <<: *env-ninja-status - steps: - - electron-publish: - attach: false - checkout: true - - mas-publish-arm64: - <<: *machine-mac-large-arm - environment: - <<: *env-mac-large-release - <<: *env-mas-apple-silicon - <<: *env-release-build - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_requests=True' - UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >> - <<: *env-ninja-status - steps: - - electron-publish: - attach: false - checkout: true - - mas-publish-x64-skip-checkout: - <<: *machine-mac-large - environment: - <<: *env-mac-large-release - <<: *env-mas - <<: *env-release-build - UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >> - steps: - - electron-publish: - attach: true - checkout: false - - mas-publish-arm64-skip-checkout: - <<: *machine-mac-large-arm - environment: - <<: *env-mac-large-release - <<: *env-mas-apple-silicon - <<: *env-release-build - UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >> - <<: *env-ninja-status - steps: - - electron-publish: - attach: true - checkout: false - - mas-testing-arm64: - <<: *machine-mac-large-arm - environment: - <<: *env-mac-large - <<: *env-testing-build - <<: *env-ninja-status - <<: *env-macos-build - <<: *env-mas-apple-silicon - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac' - steps: - - electron-build: - persist: true - checkout: false - checkout-and-assume-cache: true - attach: false - - # Layer 3: Tests. - linux-x64-unittests: - <<: *machine-linux-2xlarge - environment: - <<: *env-linux-2xlarge - <<: *env-unittests - <<: *env-headless-testing - <<: *steps-native-tests - - linux-x64-disabled-unittests: - <<: *machine-linux-2xlarge - environment: - <<: *env-linux-2xlarge - <<: *env-unittests - <<: *env-headless-testing - TESTS_ARGS: '--only-disabled-tests' - <<: *steps-native-tests - - linux-x64-chromium-unittests: - <<: *machine-linux-2xlarge - environment: - <<: *env-linux-2xlarge - <<: *env-unittests - <<: *env-headless-testing - TESTS_ARGS: '--include-disabled-tests' - <<: *steps-native-tests - - linux-x64-browsertests: - <<: *machine-linux-2xlarge - environment: - <<: *env-linux-2xlarge - <<: *env-browsertests - <<: *env-testing-build - <<: *env-headless-testing - <<: *steps-native-tests - - linux-x64-testing-tests: - <<: *machine-linux-medium - environment: - <<: *env-linux-medium - <<: *env-headless-testing - <<: *env-stack-dumping - parallelism: 3 - <<: *steps-tests - - linux-x64-testing-nan: - <<: *machine-linux-medium - environment: - <<: *env-linux-medium - <<: *env-headless-testing - <<: *env-stack-dumping - <<: *steps-test-nan - - linux-x64-testing-node: - <<: *machine-linux-2xlarge - environment: - <<: *env-linux-medium - <<: *env-headless-testing - <<: *env-stack-dumping - <<: *steps-test-node - - linux-x64-release-tests: - <<: *machine-linux-medium - environment: - <<: *env-linux-medium - <<: *env-headless-testing - <<: *env-send-slack-notifications - <<: *steps-tests - - linux-x64-verify-ffmpeg: - <<: *machine-linux-medium - environment: - <<: *env-linux-medium - <<: *env-headless-testing - <<: *env-send-slack-notifications - <<: *steps-verify-ffmpeg - - linux-ia32-testing-tests: - <<: *machine-linux-medium - environment: - <<: *env-linux-medium - <<: *env-ia32 - <<: *env-headless-testing - <<: *env-stack-dumping - parallelism: 3 - <<: *steps-tests - - linux-ia32-testing-nan: - <<: *machine-linux-medium - environment: - <<: *env-linux-medium - <<: *env-ia32 - <<: *env-headless-testing - <<: *env-stack-dumping - <<: *steps-test-nan - - linux-ia32-testing-node: - <<: *machine-linux-2xlarge - environment: - <<: *env-linux-medium - <<: *env-ia32 - <<: *env-headless-testing - <<: *env-stack-dumping - <<: *steps-test-node - - linux-ia32-release-tests: - <<: *machine-linux-medium - environment: - <<: *env-linux-medium - <<: *env-ia32 - <<: *env-headless-testing - <<: *env-send-slack-notifications - <<: *steps-tests - - linux-ia32-verify-ffmpeg: - <<: *machine-linux-medium - environment: - <<: *env-linux-medium - <<: *env-ia32 - <<: *env-headless-testing - <<: *env-send-slack-notifications - <<: *steps-verify-ffmpeg - - osx-testing-x64-tests: - <<: *machine-mac-large - environment: - <<: *env-mac-large - <<: *env-stack-dumping - parallelism: 2 - <<: *steps-tests - - osx-release-x64-tests: - <<: *machine-mac-large - environment: - <<: *env-mac-large - <<: *env-stack-dumping - <<: *env-send-slack-notifications - <<: *steps-tests - - osx-verify-ffmpeg: - <<: *machine-mac - environment: - <<: *env-machine-mac - <<: *env-send-slack-notifications - <<: *steps-verify-ffmpeg - - mas-testing-x64-tests: - <<: *machine-mac-large - environment: - <<: *env-mac-large - <<: *env-stack-dumping - parallelism: 2 - <<: *steps-tests - - mas-release-tests: - <<: *machine-mac-large - environment: - <<: *env-mac-large - <<: *env-stack-dumping - <<: *env-send-slack-notifications - <<: *steps-tests - - mas-verify-ffmpeg: - <<: *machine-mac - environment: - <<: *env-machine-mac - <<: *env-send-slack-notifications - <<: *steps-verify-ffmpeg - - # Layer 4: Summary. - linux-x64-release-summary: - <<: *machine-linux-medium - environment: - <<: *env-linux-medium - <<: *env-send-slack-notifications - steps: - - *step-maybe-notify-slack-success - - linux-ia32-release-summary: - <<: *machine-linux-medium - environment: - <<: *env-linux-medium - <<: *env-send-slack-notifications - steps: - - *step-maybe-notify-slack-success - - linux-arm-release-summary: - <<: *machine-linux-medium - environment: - <<: *env-linux-medium - <<: *env-send-slack-notifications - steps: - - *step-maybe-notify-slack-success - - linux-arm64-release-summary: - <<: *machine-linux-medium - environment: - <<: *env-linux-medium - <<: *env-send-slack-notifications - steps: - - *step-maybe-notify-slack-success - - mas-release-summary: - <<: *machine-mac - environment: - <<: *env-machine-mac - <<: *env-send-slack-notifications - steps: - - *step-maybe-notify-slack-success - - osx-release-x64-summary: - <<: *machine-mac - environment: - <<: *env-machine-mac - <<: *env-send-slack-notifications - steps: - - *step-maybe-notify-slack-success - -workflows: - version: 2.1 - - # The publish workflows below each contain one job so that they are - # compatible with how sudowoodo works today. If these workflows are - # changed to have multiple jobs, then scripts/release/ci-release-build.js - # will need to be updated and there will most likely need to be changes to - # sudowoodo - - publish-linux: - when: << pipeline.parameters.run-linux-publish >> - jobs: - - linux-checkout - - linux-x64-publish-skip-checkout: - requires: - - linux-checkout - context: release-env - - linux-ia32-publish-skip-checkout: - requires: - - linux-checkout - context: release-env - - linux-arm-publish-skip-checkout: - requires: - - linux-checkout - context: release-env - - linux-arm64-publish-skip-checkout: - requires: - - linux-checkout - context: release-env - - publish-x64-linux: - when: << pipeline.parameters.run-linux-x64-publish >> - jobs: - - linux-x64-publish: - context: release-env - - publish-ia32-linux: - when: << pipeline.parameters.run-linux-ia32-publish >> - jobs: - - linux-ia32-publish: - context: release-env - - publish-arm-linux: - when: << pipeline.parameters.run-linux-arm-publish >> - jobs: - - linux-arm-publish: - context: release-env - - publish-arm64-linux: - when: << pipeline.parameters.run-linux-arm64-publish >> - jobs: - - linux-arm64-publish: - context: release-env - - publish-osx: - when: << pipeline.parameters.run-osx-publish >> - jobs: - - osx-publish-x64: - context: release-env - - publish-mas: - when: << pipeline.parameters.run-mas-publish >> - jobs: - - mas-publish: - context: release-env - - publish-osx-arm64: - when: << pipeline.parameters.run-osx-publish-arm64 >> - jobs: - - osx-publish-arm64: - context: release-env - - publish-mas-arm64: - when: << pipeline.parameters.run-mas-publish-arm64 >> - jobs: - - mas-publish-arm64: - context: release-env - - publish-macos: - when: << pipeline.parameters.run-macos-publish >> - jobs: - - mac-checkout - - osx-publish-x64-skip-checkout: - requires: - - mac-checkout - - mas-publish-x64-skip-checkout: - requires: - - mac-checkout - - osx-publish-arm64-skip-checkout: - requires: - - mac-checkout - - mas-publish-arm64-skip-checkout: - requires: - - mac-checkout - - lint: - when: << pipeline.parameters.run-lint >> - jobs: - - lint - - build-linux: - when: << pipeline.parameters.run-build-linux >> - jobs: - - linux-checkout-fast - - linux-checkout-and-save-cache - - - linux-x64-testing - - linux-x64-testing-no-run-as-node - - linux-x64-testing-gn-check: - requires: - - linux-checkout-fast - - linux-x64-testing-tests: - requires: - - linux-x64-testing - - linux-x64-testing-nan: - requires: - - linux-x64-testing - - linux-x64-testing-node: - requires: - - linux-x64-testing - - - linux-ia32-testing - - linux-ia32-testing-tests: - requires: - - linux-ia32-testing - - linux-ia32-testing-nan: - requires: - - linux-ia32-testing - - linux-ia32-testing-node: - requires: - - linux-ia32-testing - - - linux-arm-testing - - - linux-arm64-testing - - linux-arm64-testing-gn-check: - requires: - - linux-checkout-fast - - ts-compile-doc-change - - build-mac: - when: << pipeline.parameters.run-build-mac >> - jobs: - - mac-checkout-fast - - mac-checkout-and-save-cache - - - osx-testing-x64: - requires: - - mac-checkout-and-save-cache - - - osx-testing-x64-gn-check: - requires: - - mac-checkout-fast - - - osx-testing-x64-tests: - requires: - - osx-testing-x64 - - - osx-testing-arm64: - requires: - - mac-checkout-and-save-cache - - - mas-testing-x64: - requires: - - mac-checkout-and-save-cache - - - mas-testing-x64-gn-check: - requires: - - mac-checkout-fast - - - mas-testing-x64-tests: - requires: - - mas-testing-x64 - - - mas-testing-arm64: - requires: - - mac-checkout-and-save-cache - - nightly-linux-release-test: - triggers: - - schedule: - cron: "0 0 * * *" - filters: - branches: - only: - - master - - *chromium-upgrade-branches - jobs: - - linux-checkout-fast - - linux-checkout-and-save-cache - - - linux-x64-release - - linux-x64-release-tests: - requires: - - linux-x64-release - - linux-x64-verify-ffmpeg: - requires: - - linux-x64-release - - linux-x64-release-summary: - requires: - - linux-x64-release - - linux-x64-release-tests - - linux-x64-verify-ffmpeg - - - linux-ia32-release - - linux-ia32-release-tests: - requires: - - linux-ia32-release - - linux-ia32-verify-ffmpeg: - requires: - - linux-ia32-release - - linux-ia32-release-summary: - requires: - - linux-ia32-release - - linux-ia32-release-tests - - linux-ia32-verify-ffmpeg - - - linux-arm-release - - linux-arm-release-summary: - requires: - - linux-arm-release - - - linux-arm64-release - - linux-arm64-release-summary: - requires: - - linux-arm64-release - - nightly-mac-release-test: - triggers: - - schedule: - cron: "0 0 * * *" - filters: - branches: - only: - - master - - *chromium-upgrade-branches - jobs: - - mac-checkout-fast - - mac-checkout-and-save-cache - - - osx-release-x64: - requires: - - mac-checkout-and-save-cache - - osx-release-x64-tests: - requires: - - osx-release-x64 - - osx-verify-ffmpeg: - requires: - - osx-release-x64 - - osx-release-x64-summary: - requires: - - osx-release-x64 - - osx-release-x64-tests - - osx-verify-ffmpeg - - - mas-release: - requires: - - mac-checkout-and-save-cache - - mas-release-tests: - requires: - - mas-release - - mas-verify-ffmpeg: - requires: - - mas-release - - mas-release-summary: - requires: - - mas-release - - mas-release-tests - - mas-verify-ffmpeg - - # Various slow and non-essential checks we run only nightly. - # Sanitizer jobs should be added here. - linux-checks-nightly: - triggers: - - schedule: - cron: "0 0 * * *" - filters: - branches: - only: - - master - - *chromium-upgrade-branches - jobs: - - linux-checkout-for-native-tests - - # TODO(alexeykuzmin): Enable it back. - # Tons of crashes right now, see - # https://circleci.com/gh/electron/electron/67463 -# - linux-x64-browsertests: -# requires: -# - linux-checkout-for-native-tests - - - linux-x64-unittests: - requires: - - linux-checkout-for-native-tests - - - linux-x64-disabled-unittests: - requires: - - linux-checkout-for-native-tests - - - linux-checkout-for-native-tests-with-no-patches - - - linux-x64-chromium-unittests: - requires: - - linux-checkout-for-native-tests-with-no-patches diff --git a/.circleci/fix-known-hosts.sh b/.circleci/fix-known-hosts.sh deleted file mode 100755 index d6d36e791ad5e..0000000000000 --- a/.circleci/fix-known-hosts.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -set -e - -mkdir -p ~/.ssh -echo "|1|B3r+7aO0/x90IdefihIjxIoJrrk=|OJddGDfhbuLFc1bUyy84hhIw57M= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ== -|1|rGlEvW55DtzNZp+pzw9gvyOyKi4=|LLWr+7qlkAlw3YGGVfLHHxB/kR0= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==" >> ~/.ssh/known_hosts diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000000000..6fb5e40a261ff --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,4 @@ +--- +Checks: '-modernize-use-nullptr' +InheritParentConfig: true +... diff --git a/.claude/.gitignore b/.claude/.gitignore new file mode 100644 index 0000000000000..93c0f73fa4110 --- /dev/null +++ b/.claude/.gitignore @@ -0,0 +1 @@ +settings.local.json diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000000000..e3087d06721da --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,25 @@ +{ + "permissions": { + "allow": [ + "Bash(e sync)", + "Bash(e patches --list-targets:*)", + "Bash(git add:*)", + "Bash(git am:*)", + "Bash(git commit:*)", + "Bash(git log:*)", + "Bash(git show:*)", + "Bash(e patches:*)", + "Bash(e sync:*)", + "Skill(electron-chromium-upgrade)", + "Skill(electron-node-upgrade)", + "Read(*)", + "Bash(echo:*)", + "Bash(e build:*)", + "Bash(tee:*)", + "Bash(git diff:*)", + "Bash(git rev-parse:*)" + ], + "deny": [], + "ask": [] + } +} diff --git a/.claude/skills/chrome-release-cls/SKILL.md b/.claude/skills/chrome-release-cls/SKILL.md new file mode 100644 index 0000000000000..3cbf703f5f6a1 --- /dev/null +++ b/.claude/skills/chrome-release-cls/SKILL.md @@ -0,0 +1,106 @@ +--- +name: chrome-release-cls +description: Given a Chrome Releases blog post URL (chromereleases.googleblog.com), extract every CVE/bug and find the underlying Gerrit CL that fixed it by searching the local Chromium checkout and sub-repos. Use when asked to map Chrome security release notes to fixing CLs, or to find which commits correspond to CVEs in a Chrome stable update. +--- + +# Chrome Release → Fixing CL Mapper + +Maps every security fix in a Chrome Releases blog post to the Gerrit CL(s) that fixed it. + +## Input + +`$ARGUMENTS` — a `https://chromereleases.googleblog.com/...` URL. If empty, ask the user for one. + +## Procedure + +### 1. Extract CVE → bug ID pairs from the blog post + +The blog HTML buries bug IDs inside `` tags, so strip tags first. Run: + +```bash +curl -sL "$URL" | python3 -c ' +import sys, re, html +t = re.sub(r"<[^>]+>", " ", sys.stdin.read()) +t = re.sub(r"\s+", " ", html.unescape(t)) +seen = set() +for m in re.finditer(r"\[\s*(\d{6,})\s*\]\s*(Critical|High|Medium|Low)\s*(CVE-\d{4}-\d+):\s*([^.]+?)\.", t): + if m.group(3) in seen: continue + seen.add(m.group(3)) + print(f"{m.group(3)}|{m.group(1)}|{m.group(2)}|{m.group(4).strip()}") +' > /tmp/cve_bugs.txt +cat /tmp/cve_bugs.txt +``` + +If this yields nothing, the page may have changed format — fall back to `grep -oE 'CVE-[0-9]{4}-[0-9]+'` and `grep -oE 'crbug\.com/[0-9]+'` and pair them by order. + +### 2. Find the fixing CL for each bug + +Search git history in the Chromium checkout and relevant sub-repos for commits whose `Bug:` or `Fixed:` footer references the bug ID, then extract the `Reviewed-on:` Gerrit URL. + +Repo selection by component keyword: +- ANGLE → `third_party/angle` +- Skia, Graphite → `third_party/skia` +- PDFium → `third_party/pdfium` +- Dawn → `third_party/dawn` +- V8, Turbofan, Maglev, Turboshaft → `v8` +- everything else → `.` (chromium/src) + +Always also fall back to `.` if the hinted repo has no match. + +```bash +cd /root/src/electron/src # chromium root (parent of electron/) + +lookup() { + local bug="$1" repos="$2" + for repo in $repos . v8 third_party/skia third_party/angle third_party/pdfium third_party/dawn; do + local hits + hits=$(git -C "$repo" log --all --since='6 months ago' -E \ + --grep="(Bug|Fixed):.*\\b${bug}\\b" --format='%H' 2>/dev/null | sort -u) + [[ -z "$hits" ]] && continue + while read -r h; do + git -C "$repo" log -1 --format='%B' "$h" | grep '^Reviewed-on:' | sed 's/^/ /' + echo " ↳ $(git -C "$repo" log -1 --format='%s' "$h")" + done <<<"$hits" + return 0 + done + echo " (not found locally)" +} +``` + +Drive it from `/tmp/cve_bugs.txt`. Prefer the **non-`[M1xx]`-prefixed** commit subject as the canonical main CL; the `[M1xx]` ones are branch cherry-picks. + +### 3. Handle misses + +For any bug with no local hit: +- `git -C fetch origin` then re-search `--remotes` (fix may be newer than the checkout). +- Query Gerrit directly: `curl -s "https://chromium-review.googlesource.com/changes/?q=bug:${BUG}&n=10" | tail -n +2 | python3 -m json.tool` (also try `skia-review`, `pdfium-review`, `dawn-review`, `aomedia-review`). +- **`b/` bug format (Skia, Graphite, Dawn):** These repos reference bugs as `b/` in commit messages rather than `Bug: ` footers. The Gerrit `bug:` query will return nothing. Use `message:` search instead: + ```bash + curl -s "https://skia-review.googlesource.com/changes/?q=message:${BUG}&n=5" | tail -n +2 + ``` + Apply the same pattern for `dawn-review.googlesource.com` when the component is Dawn. +- **Tracing main CLs from merges:** When only `[M1xx]` merge CLs are found, query the CL detail for `cherry_pick_of_change` to find the original main CL number: + ```bash + curl -s "https://chromium-review.googlesource.com/changes/${CL_NUM}?o=CURRENT_REVISION" | tail -n +2 | python3 -c " + import sys, json + d = json.load(sys.stdin) + print(d.get('cherry_pick_of_change', 'none')) + " + ``` +- If still nothing and the bug was reported very recently (especially by "Google Threat Intelligence" or marked in-the-wild), the CL is likely still access-restricted — report it as such rather than guessing. + +### 4. Special cases + +- **Roll CLs — skip and find the upstream fix:** For components whose fixes land in upstream repos (PDFium, Dawn, Skia, Graphite, libaom, libvpx, ffmpeg), the chromium-review hit will be a `Roll src/third_party/...` commit. Do not report the roll CL as the fix. Instead, query the component's own Gerrit instance directly for the actual fixing CL: + - PDFium → `pdfium-review.googlesource.com` (use `bug:` or `message:` query) + - Dawn → `dawn-review.googlesource.com` (use `message:` query — uses `b/` format) + - Skia / Graphite → `skia-review.googlesource.com` (use `message:` query — uses `b/` format) + - libaom → `aomedia-review.googlesource.com` + + Only if the upstream Gerrit instance returns no results should you fall back to reporting the roll CL — in that case, include the roll CL and note that the actual fix is upstream but the specific CL could not be identified. +- Multiple `Reviewed-on:` lines in one commit body: cherry-picks keep the original line plus a new one. The **first** `Reviewed-on:` is the original CL. +- A bug may have multiple distinct fix CLs (fix + follow-up hardening) — list all of them. + +### 5. Output + +Produce a markdown table per severity level: `CVE | Bug | Component | Fix CL (main)`. Link bugs as `https://crbug.com/`. Save raw output (including all branch merges) to `/tmp/cve_cls.txt` and mention the path. diff --git a/.claude/skills/chrome-release-verify/SKILL.md b/.claude/skills/chrome-release-verify/SKILL.md new file mode 100644 index 0000000000000..4f1f085a379b3 --- /dev/null +++ b/.claude/skills/chrome-release-verify/SKILL.md @@ -0,0 +1,123 @@ +--- +name: chrome-release-verify +description: End-to-end Chrome security backport for an Electron release branch. Given a Chrome Releases blog URL and a branch (e.g. 41-x-y), determines which CVE fixes are missing from the *actual synced source*, writes the cherry-pick patches locally, validates them with `e sync --3` + `lint --patches`, then pushes a single PR. Use when asked to backport a Chrome security release to N-x-y, "is CVE-X already in N-x-y?", or to produce/validate the cherry-pick set for a release branch. +--- + +# Chrome Release → Validated Backport PR + +Input: `$ARGUMENTS` = ` ` (e.g. `41-x-y https://chromereleases.googleblog.com/2026/04/stable-channel-update-for-desktop_15.html`). Ask if either is missing. + +The flow is **local-first**: nothing is pushed until every patch applies via `e sync --3` and passes `lint --patches`. + +## 1. Map CVE → bug → fix CL + +Run `/chrome-release-cls ` (or its inline procedure) to produce `/tmp/cve_bugs.txt` (`CVE|bug|severity|desc`) and a per-bug canonical fix CL. For each CL also note `repo` (path under `src/`: `.`, `v8`, `third_party/{skia,angle,pdfium,dawn}`, `third_party/libaom/source/libaom`) and `gerrit-host`. + +**Prefer the target-milestone merge CL** if one exists (e.g. on `41-x-y` ≈ M146, prefer the `[M146]` cherry-pick over the main CL) — it's already rebased and far less likely to conflict. Find it via `git log --all --grep` on the Change-Id, or Gerrit `?q=bug:`. If Chrome did *not* merge a fix to the target milestone, that's a strong signal the vulnerable code doesn't exist there — flag it for skip rather than forcing a port. + +## 2. Prepare a synced worktree + +Reuse `bp-` from `e show configs` if present, else `e worktree add bp- ~/src/electron-bp- --source --no-sync`. + +```bash +cd /src/electron +git fetch origin +git checkout -B security-backport// origin/ +e use bp- +e sync 2>&1 | tee /tmp/bp_sync.log +``` + +If sync fails with `NotADirectoryError: '/src/.git/objects/info/alternates'`, remove `GIT_CACHE_PATH` from the bp config's `env` and retry. + +## 3. Verify IN-TREE vs NEEDS-BACKPORT + +For each bug, three checks against the **synced** repo: + +1. `git -C "$repo" log HEAD --since='1 year ago' -E --grep="\b${bug}\b" --format='%h %s'` +2. Fetch Change-Id from Gerrit, then `git log HEAD --grep="^Change-Id: ${cid}$"` +3. `grep -rlE "(\b${bug}\b|${cid})" /src/electron/patches/` + +Any hit ⇒ IN-TREE. All empty ⇒ NEEDS-BACKPORT. + +For each NEEDS-BACKPORT CL, also fetch its file list (`/changes/~/revisions/current/files`) and **skip** if every file is under `chrome/browser/`, `chrome/android/`, `ios/`, or `components/**/android/` — Electron doesn't compile those. + +Report the table now (`CVE | Sev | Bug | Component | Verdict | CL`) and the proposed backport set; get user sign-off before continuing. + +## 4. Write patches locally (no push yet) + +For each backport CL, fetch the raw patch and write it into `patches//`: + +```bash +curl -s "https://${host}.googlesource.com/changes/${proj//\//%2F}~${cl}/revisions/current/patch" \ + | base64 -d > "patches/${dir}/cherry-pick-${short}.patch" +echo "cherry-pick-${short}.patch" >> "patches/${dir}/.patches" +``` + +For repos with no Gerrit host `e cherry-pick` supports (e.g. **libaom** on aomedia), instead `git cherry-pick` the upstream commits onto the synced sub-repo HEAD and `git format-patch` the result. + +For any newly-created `patches//`, append to `patches/config.json` **preserving the compact one-line-per-entry style**: + +```json + { "patch_dir": "src/electron/patches/", "repo": "src/third_party/" } +``` + +## 5. Validate with `e sync --3` + +```bash +e sync --3 2>&1 | tee /tmp/bp_sync3.log +``` + +On `Patch failed at NNNN `: + +- `cd` into the failing repo, inspect `git diff` for conflict markers. +- **Test-only files** (e.g. `web_tests/VirtualTestSuites`, `*_unittest.cc` context drift): take ours (`git checkout --ours -- `) if the security-relevant hunks merged cleanly. +- **Substantive code conflicts**: check whether a target-milestone merge CL exists and swap to it. If none exists upstream and the surrounding code is structurally different, **drop the patch** (delete the file, remove from `.patches` and `config.json`) and note it for a separate manual-port PR — do not improvise security-fix semantics. +- After resolving: `git add && git -c commit.gpgsign=false am --continue`, then `e patches ` to export the resolved patch, then re-run `e sync --3`. Repeat until clean. + +## 6. Export → lint → re-apply loop + +```bash +e patches all +node script/lint.js --patches # must exit 0 +``` + +If lint reports findings (typically trailing whitespace on `+` content lines), fixing them **changes the bytes the patch writes**, which invalidates the `index ..` blob hashes that `e patches` baked in. Hand-editing a `.patch` and pushing it as-is will pass lint locally but fail CI's Apply Patches re-export check with a one-line `index` hash diff. + +So whenever lint (or you) modifies any `.patch` file after export, round-trip once more: + +```bash +# fix the lint findings in patches/**/*.patch, then: +e sync # re-apply the edited patches (no --3 needed; they applied cleanly last time) +e patches all # re-export so index blob hashes match the edited content +node script/lint.js --patches # must now exit 0 +git diff --quiet -- patches/ || { echo "patches changed again — repeat the loop"; } +``` + +Repeat until `lint --patches` exits 0 **and** `git diff -- patches/` is empty after the final `e patches all`. Only then is the patch set CI-stable. + +## 7. Commit, push, PR + +```bash +git add patches/ +git commit -m "chore: cherry-pick changes from " +git push origin HEAD +gh pr create --repo electron/electron --base --head \ + --title "chore: cherry-pick changes from " \ + --label "" --label backport-check-skip --label semver/patch --label "security 🔒" \ + --body-file /tmp/pr_body.md +``` + +PR body format: + +```markdown +Backports the following changes: + +* [``]() from ([](https://crbug.com/), CVE-YYYY-NNNN) +* ... + +Notes: Security: backported fixes for CVE-YYYY-NNNN, CVE-YYYY-NNNN, .... +``` + +Short commit links to the **Gerrit CL**; bug links to `crbug.com`; CVE comes from the blog mapping (the patch's own `Bug:` footer may differ); `Notes:` is the last line. Mention any dropped patches (with reason) above the `Notes:` line. + +Restore `e use ` when done. diff --git a/.claude/skills/electron-chromium-upgrade/SKILL.md b/.claude/skills/electron-chromium-upgrade/SKILL.md new file mode 100644 index 0000000000000..72e7f0fb80c36 --- /dev/null +++ b/.claude/skills/electron-chromium-upgrade/SKILL.md @@ -0,0 +1,184 @@ +--- +name: electron-chromium-upgrade +description: Guide for performing Chromium version upgrades in the Electron project. Use when working on the roller/chromium/main branch to fix patch conflicts during `e sync --3`. Covers the patch application workflow, conflict resolution, analyzing upstream Chromium changes, and proper commit formatting for patch fixes. +--- + +# Electron Chromium Upgrade: Phase One + +## Summary + +Run `e sync --3` repeatedly, fixing patch conflicts as they arise, until it succeeds. Then export patches and commit changes atomically. + +## Success Criteria + +Phase One is complete when: +- `e sync --3` exits with code 0 (no patch failures) +- All changes are committed per the commit guidelines + +Do not stop until these criteria are met. + +**CRITICAL** Do not delete or skip patches unless 100% certain the patch is no longer needed. Complicated conflicts or hard to resolve issues should be presented to the user after you have exhausted all other options. Do not delete the patch just because you can't solve it. + +**CRITICAL** Never use `git am --skip` and then manually recreate a patch by making a new commit. This destroys the original patch's authorship, commit message, and position in the series. If `git am --continue` reports "No changes", investigate why — the changes were likely absorbed by a prior conflict resolution's 3-way merge. Present this situation to the user rather than skipping and recreating. + +## Context + +The `roller/chromium/main` branch is created by automation to update Electron's Chromium dependency SHA. No work has been done to handle breaking changes between the old and new versions. + +**Key directories:** +- Current directory: Electron repo (always run `e` commands here) +- `..` (parent): Chromium repo (where most patches apply) +- `patches/`: Patch files organized by target +- `docs/development/patches.md`: Patch system documentation + +## Pre-flight Checks + +Run these once at the start of each upgrade session: + +1. **Clear rerere cache** (if enabled): `git rerere clear` in both the electron and `..` repos. Stale recorded resolutions from a prior attempt can silently apply wrong merges. +2. **Ensure pre-commit hooks are installed**: Check that `.git/hooks/pre-commit` exists. If not, run `yarn husky` to install it. The hook runs `lint-staged` which handles clang-format for C++ files. + +## Workflow + +1. Run `e sync --3` (the `--3` flag enables 3-way merge, always required) +2. If succeeds → skip to step 5 +3. If patch fails: + - Identify target repo and patch from error output + - Analyze failure (see references/patch-analysis.md) + - Fix conflict in target repo's working directory + - Run `git am --continue` in affected repo + - Repeat until all patches for that repo apply + - IMPORTANT: Once `git am --continue` succeeds you MUST run `e patches {target}` to export fixes + - Return to step 1 +4. When `e sync --3` succeeds, run `e patches all` +5. **Read `references/phase-one-commit-guidelines.md` NOW**, then commit changes following those instructions exactly. + +## Commands Reference + +| Command | Purpose | +|---------|---------| +| `e sync --3` | Clone deps and apply patches with 3-way merge | +| `git am --continue` | Continue after resolving conflict (run in target repo) | +| `e patches {target}` | Export commits from target repo to patch files | +| `e patches all` | Export all patches from all targets | +| `e patches {target} --commit-updates` | Export patches and auto-commit trivial changes | +| `e patches --list-targets` | List targets and config paths | + +## Patch System Mental Model + +``` +patches/{target}/*.patch → [e sync --3] → target repo commits + ← [e patches] ← +``` + +## When to Edit Patches + +| Situation | Action | +|-----------|--------| +| During active `git am` conflict | Fix in target repo, then `git am --continue` | +| Modifying patch outside conflict | Edit `.patch` file directly | +| Creating new patch (rare, avoid) | Commit in target repo, then `e patches {target}` | + +Fix existing patches 99% of the time rather than creating new ones. + +## Patch Fixing Rules + +1. **Preserve authorship**: Keep original author in TODO comments (from patch `From:` field) +2. **Never change TODO assignees**: `TODO(name)` must retain original name +3. **Update descriptions**: If upstream changed (e.g., `DCHECK` → `CHECK_IS_TEST`), update patch commit message to reflect current state +4. **Never skip-and-recreate a patch**: If `git am --continue` says "No changes — did you forget to use 'git add'?", do NOT run `git am --skip` and create a replacement commit. The patch's changes were already absorbed by a prior 3-way merge resolution. This means an earlier conflict resolution pulled in too many changes. Present the situation to the user for guidance — the correct fix may require re-doing an earlier resolution more carefully to keep each patch's changes separate. + +# Electron Chromium Upgrade: Phase Two + +## Summary + +Run `e build -k 999 -- --quiet` repeatedly, fixing build issues as they arise, until it succeeds. Then run `e start --version` to validate Electron launches and commit changes atomically. + +Run Phase Two immediately after Phase One is complete. + +## Success Criteria + +Phase Two is complete when: +- `e build -k 999 -- --quiet` exits with code 0 (no build failures) +- `e start --version` has been run to check Electron launches +- All changes are committed per the commit guidelines + +Do not stop until these criteria are met. Do not delete code or features, never comment out code in order to take short cut. Make all existing code, logic and intention work. + +## Context + +The `roller/chromium/main` branch is created by automation to update Electron's Chromium dependency SHA. No work has been done to handle breaking changes between the old and new versions. Chromium APIs frequently are renamed or refactored. In every case the code in Electron must be updated to account for the change in Chromium, strongly avoid making changes to the code in chromium to fix Electrons build. + +**Key directories:** +- Current directory: Electron repo (always run `e` commands here) +- `..` (parent): Chromium repo (do not touch this code to fix build issues, just read it to obtain context) + +## Workflow + +1. Run `e build -k 999 -- --quiet` (the `--quiet` flag suppresses per-target status lines, showing only errors and the final result) +2. If succeeds → skip to step 6 +3. If build fails: + - Identify underlying file in "electron" from the compilation error message + - Analyze failure + - Fix build issue by adapting Electron's code for the change in Chromium + - Run `e build -t {target_that_failed}.o` to build just the failed target we were specifically fixing + - You can identify the target_that_failed from the failure line in the build log. E.g. `FAILED: 2e506007-8d5d-4f38-bdd1-b5cd77999a77 "./obj/electron/chromium_src/chrome/process_singleton_posix.o" CXX obj/electron/chromium_src/chrome/process_singleton_posix.o` the target name is `obj/electron/chromium_src/chrome/process_singleton_posix.o` + - **Read `references/phase-two-commit-guidelines.md` NOW**, then commit changes following those instructions exactly. + - Return to step 1 +4. **CRITICAL**: After ANY commit (especially patch commits), immediately run `git status` in the electron repo + - Look for other modified `.patch` files that only have index/hunk header changes + - These are dependent patches affected by your fix + - Commit them immediately with: `git commit -am "chore: update patches (trivial only)"` +5. Return to step 1 +6. When `e build` succeeds, run `e start --version` +7. Check if you have any pending changes in the Chromium repo by running `git status` + - If you have changes follow the instructions below in "A. Patch Fixes" to correctly commit those modifications into the appropriate patch file + +## Commands Reference + +| Command | Purpose | +|---------|---------| +| `e build -k 999 -- --quiet` | Build Electron, continue on errors, suppress status lines | +| `e build -t {target}.o` | Build just one specific target to verify a fix | +| `e start --version` | Validate Electron launches after successful build | + +## Two Types of Build Fixes + +### A. Patch Fixes (for files in chromium_src or patched Chromium files) + +When the error is in a file that Electron patches (check with `grep -l "filename" patches/chromium/*.patch`): + +1. Edit the file in the Chromium source tree (e.g., `/src/chrome/browser/...`) +2. Create a fixup commit targeting the original patch commit: + ```bash + cd .. # to chromium repo + git add + git commit --fixup= + GIT_SEQUENCE_EDITOR=: git rebase --autosquash --autostash -i ^ + ``` +3. Export the updated patch: `e patches chromium` +4. Commit the updated patch file following `references/phase-one-commit-guidelines.md`. + +To find the original patch commit to fixup: `git log --oneline | grep -i "keyword from patch name"` + +The base commit for rebase is the Chromium commit before patches were applied. Find it by checking the `refs/patches/upstream-head` ref. + +### B. Electron Code Fixes (for files in shell/, electron/, etc.) + +When the error is in Electron's own source code: + +1. Edit files directly in the electron repo +2. Commit directly (no patch export needed) + +# Critical: Read Before Committing + +- Before ANY Phase One commits: Read `references/phase-one-commit-guidelines.md` +- Before ANY Phase Two commits: Read `references/phase-two-commit-guidelines.md` + +# Skill Directory Structure +This skill has additional reference files in `references/`: +- patch-analysis.md - How to analyze patch failures +- phase-one-commit-guidelines.md - Commit format for Phase One +- phase-two-commit-guidelines.md - Commit format for Phase Two + +Read these when referenced in the workflow steps. diff --git a/.claude/skills/electron-chromium-upgrade/references/patch-analysis.md b/.claude/skills/electron-chromium-upgrade/references/patch-analysis.md new file mode 100644 index 0000000000000..d0504734aff51 --- /dev/null +++ b/.claude/skills/electron-chromium-upgrade/references/patch-analysis.md @@ -0,0 +1,119 @@ +# Analyzing Patch Failures + +## Investigation Steps + +1. **Read the patch file** at `patches/{target}/{patch_name}.patch` + +2. **Examine current state** of the file in Chromium at mentioned line numbers + +3. **Check recent upstream changes:** + ```bash + cd .. # or relevant target repo + git log --oneline -10 -- {file} + ``` + +4. **Find Chromium CL** in commit messages: + ``` + Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/{CL_NUMBER} + ``` + +## Critical: Resolve by Intent, Not by Mechanical Merge + +When resolving a patch conflict, do NOT blindly preserve the patch's old code. Instead: + +1. **Understand the upstream CL's full scope** — not just the conflicting hunk. + Run `git show --stat` and read diffs for all affected files. + Upstream may have removed structs, members, or methods that the patch + references in other hunks or files. + +2. **Re-read the patch commit message** to understand its *intent* — what + behavior does it need to preserve or add? + +3. **Implement the intent against the new upstream code.** If the patch's + purpose is "add a feature flag guard", add only the guard — don't also + restore old code inside the guard that upstream separately removed. + +### Lesson: Upstream Removals Break Patch References + +- **Trigger:** Patch conflict involves an upstream refactor (not just context drift) +- **Strategy:** After identifying the upstream CL, check its full diff for + removed types, members, and methods. If the patch's old code references + something removed, the resolution must use the new upstream mechanism. +- **Evidence:** An upstream CL removed a `HeadlessModeWindow` struct from a + header, but the conflict was only in a `.mm` file. Mechanically keeping the + patch's old line (`headless_mode_window_ = ...`) produced code referencing + a nonexistent type — caught only on review, not at patch-apply time. + +### Lesson: Separate Patch Purpose from Patch Implementation + +- **Trigger:** Conflict between "upstream simplified code" vs "patch has older code" +- **Strategy:** Identify the *minimal* change the patch needs. If the patch + wraps code in a conditional, only add the conditional — don't restore old + code that was inside the conditional but was separately cleaned up upstream. +- **Evidence:** An occlusion patch needed only a feature flag check, but the + old patch also contained a version check that upstream intentionally removed. + Mechanically preserving the old patch code re-added the removed check. + +### Lesson: Finish the Adaptation at Conflict Time + +- **Trigger:** A patch conflict involves an upstream API removal or replacement +- **Strategy:** When resolving the conflict, fully adapt the patch to use the + new API in the same commit. Don't remove the old code and leave behind stale + references that will "be fixed in Phase Two." Each patch fix commit should be + a complete resolution. +- **Evidence:** A safestorage patch conflicted because Chromium removed Keychain V1. + The conflict was resolved by removing V1 hunks, but the remaining code still + called V1 methods (`FindGenericPassword` with 3 args, `ItemDelete` with + `SecKeychainItemRef`). These should have been adapted to V2 APIs in the same + commit, not deferred. + +## Common Failure Patterns + +| Pattern | Cause | Solution | +|---------|-------|----------| +| Context lines don't match | Surrounding code changed | Update context in patch | +| File not found | File renamed/moved | Update patch target path | +| Function not found | Refactored upstream | Find new function name | +| `DCHECK` → `CHECK_IS_TEST` | Macro change | Update to new macro | +| Deleted code | Feature removed | Verify patch still needed | + +## Using Git Blame + +To find the CL that changed specific lines: + +```bash +cd .. +git blame -L {start},{end} -- {file} +git log -1 {commit_sha} # Look for Reviewed-on: line +``` + +## Verifying Patch Necessity + +Before deleting a patch, verify: +1. The patched functionality was intentionally removed upstream +2. Electron doesn't need the patch for other reasons +3. No other code depends on the patched behavior + +When in doubt, keep the patch and adapt it. + +## Phase Two: Build-Time Patch Issues + +Sometimes patches that applied successfully in Phase One cause build errors in Phase Two. This can happen when: + +1. **Incomplete types**: A patch disables a header include, but new upstream code uses the type +2. **Missing members**: A patch modifies a class, but upstream added new code referencing the original + +### Finding Which Patch Affects a File + +```bash +grep -l "filename.cc" patches/chromium/*.patch +``` + +Matching Existing Patch Patterns + +When fixing build errors in patched files, examine the existing patch to understand its style: +- Does it use #if 0 / #endif guards? +- Does it use #if BUILDFLAG(...) conditionals? +- What's the pattern for disabled functionality? + +Apply fixes consistent with the existing patch style. diff --git a/.claude/skills/electron-chromium-upgrade/references/phase-one-commit-guidelines.md b/.claude/skills/electron-chromium-upgrade/references/phase-one-commit-guidelines.md new file mode 100644 index 0000000000000..c628a2127e694 --- /dev/null +++ b/.claude/skills/electron-chromium-upgrade/references/phase-one-commit-guidelines.md @@ -0,0 +1,102 @@ +# Phase One Commit Guidelines + +Only follow these instructions if there are uncommitted changes to `patches/` after Phase One succeeds. + +Ignore other instructions about making commit messages, our guidelines are CRITICALLY IMPORTANT and must be followed. + +## Each Commit Must Be Complete + +When resolving a patch conflict, fully adapt the patch to the new upstream code in the same commit. If the upstream change removes an API the patch uses, update the patch to use the replacement API now — don't leave stale references knowing they'll need fixing later. The goal is that each commit represents a finished resolution, not a partial one that defers known work to a future phase. + +## Commit Message Style + +**Titles** follow the 60/80-character guideline: simple changes fit within 60 characters, otherwise the limit is 80 characters. + +Always include a `Co-Authored-By` trailer identifying the AI model that assisted (e.g., `Co-Authored-By: `). + +### Patch conflict fixes + +Use `fix(patch):` prefix. The title should name the upstream change, not your response to it: + +``` +fix(patch): {topic headline} + +Ref: {Chromium CL link} + +Co-Authored-By: +``` + +Only add a description body if it provides clarity beyond the title. For straightforward context drift or simple API renames, the title + Ref is sufficient. + +Examples: +- `fix(patch): constant moved to header` +- `fix(patch): headless mode refactor upstream` +- `fix(patch): V1 Keychain removal` + +### Upstreamed patch removal + +When patches are no longer needed (applied cleanly with "already applied" or confirmed upstreamed), group ALL removals into a single commit: + +``` +chore: remove upstreamed patch +``` + +or (if multiple): + +``` +chore: remove upstreamed patches +``` + +If the patch file did NOT contain a `Reviewed-on: https://chromium-review.googlesource.com/c/chromium/...` link, add a `Ref:` in the commit. If it did (i.e. cherry-picks), no `Ref:` is needed. + +### Trivial patch updates + +After all fix commits, stage remaining trivial changes (index, line numbers, context only): + +```bash +git add patches +git commit -m "chore: update patches (trivial only)" +``` + +**Conflict resolution can produce trivial results.** A `git am` conflict doesn't always mean the patch content changed — context drift alone can cause a conflict. After resolving and exporting, inspect the patch diff: if only index hashes, line numbers, and context lines changed (not the patch's own `+`/`-` lines), it's trivial and belongs here, not in a `fix(patch):` commit. + +## Atomic Commits + +Each patch conflict fix gets its own commit with its own Ref. + +IMPORTANT: Try really hard to find the CL reference per the instructions below. Each change you made should in theory have been in response to a change made in Chromium that you identified or can identify. Try for a while to identify and include the ref in the commit message. Do not give up easily. + +## Finding CL References + +Use `git log` or `git blame` on Chromium source files. Look for: + +``` +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/XXXXXXX +``` + +If no CL found after searching: `Ref: Unable to locate CL` + +## Example Commits + +### Patch conflict fix (simple — title is sufficient) + +``` +fix(patch): constant moved to header + +Ref: https://chromium-review.googlesource.com/c/chromium/src/+/7536483 + +Co-Authored-By: +``` + +### Patch conflict fix (complex — description adds value) + +``` +fix(patch): V1 Keychain removal + +Upstream deleted the V1 Keychain API. Removed V1 hunks and adapted +keychain_password_mac.mm to use KeychainV2 APIs. + +Ref: https://chromium-review.googlesource.com/c/chromium/src/+/7540447 + +Co-Authored-By: +``` diff --git a/.claude/skills/electron-chromium-upgrade/references/phase-two-commit-guidelines.md b/.claude/skills/electron-chromium-upgrade/references/phase-two-commit-guidelines.md new file mode 100644 index 0000000000000..d28e8a2f6f33e --- /dev/null +++ b/.claude/skills/electron-chromium-upgrade/references/phase-two-commit-guidelines.md @@ -0,0 +1,84 @@ +# Phase Two Commit Guidelines + +Only follow these instructions if there are uncommitted changes in the Electron repo after any fixes are made during Phase Two that result a target that was failing, successfully building. + +Ignore other instructions about making commit messages, our guidelines are CRITICALLY IMPORTANT and must be followed. + +## Commit Message Style + +**Titles** follow the 60/80-character guideline: simple changes fit within 60 characters, otherwise the limit is 80 characters. Exception: upstream Chromium CL titles are used verbatim even if longer. + +Always include a `Co-Authored-By` trailer identifying the AI model that assisted (e.g., `Co-Authored-By: `). + +## Two Commit Types + +### For Electron Source Changes (shell/, electron/, etc.) + +``` +{CL-Number}: {upstream CL's original title} + +Ref: {Chromium CL link} + +Co-Authored-By: +``` + +Use the **upstream CL's original commit title** — do not paraphrase or rewrite it. To find it: `git log -1 --format=%s `. + +Only add a description body if it provides clarity beyond what the title already says (e.g., when Electron's adaptation is non-obvious). For simple renames, method additions, or straightforward API updates, the title + Ref link is sufficient. + +Each change should have its own commit and its own Ref. Logically group into commits that make sense rather than one giant commit. You may include multiple "Ref" links if required. + +For a CL link in the format `https://chromium-review.googlesource.com/c/chromium/src/+/2958369` the "CL-Number" is `2958369`. + +IMPORTANT: Try really hard to find the CL reference. Each change you made should in theory have been in response to a change in Chromium. Do not give up easily. + +### For Patch Updates (patches/chromium/*.patch) + +Use the same fixup workflow as Phase One and follow `references/phase-one-commit-guidelines.md` for the commit message format (`fix(patch):` prefix, topic style). + +## Dependent Patch Header Updates + +After any patch modification, check for other affected patches: + +```bash +git status +# If other .patch files show as modified with only index, line number, and context changes: +git add patches/ +git commit -m "chore: update patches (trivial only)" +``` + +## Finding CL References + +Use git log or git blame on Chromium source files. Look for: + +``` +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/XXXXXXX +``` + +If no CL found after searching: `Ref: Unable to locate CL` + +## Example Commits + +### Electron Source Fix (simple — title is self-explanatory) + +``` +7535923: Rename ozone buildflags + +Ref: https://chromium-review.googlesource.com/c/chromium/src/+/7535923 + +Co-Authored-By: +``` + +### Electron Source Fix (complex — description adds value) + +``` +7534194: Convert some functions in ui::Clipboard to async + +Adapted ExtractCustomPlatformNames calls to use RunLoop pattern +consistent with existing ReadImage implementation, since upstream +converted the API from synchronous return to callback-based. + +Ref: https://chromium-review.googlesource.com/c/chromium/src/+/7534194 + +Co-Authored-By: +``` diff --git a/.claude/skills/electron-node-upgrade/SKILL.md b/.claude/skills/electron-node-upgrade/SKILL.md new file mode 100644 index 0000000000000..9ffd0b55d2292 --- /dev/null +++ b/.claude/skills/electron-node-upgrade/SKILL.md @@ -0,0 +1,323 @@ +--- +name: electron-node-upgrade +description: Guide for performing Node.js version upgrades in the Electron project. Use when working on the roller/node/main branch to fix patch conflicts during `e sync --3`. Covers the patch application workflow, conflict resolution, analyzing upstream Node.js changes, building, running the Node.js test suite, and proper commit formatting for patch fixes. +--- + +# Electron Node.js Upgrade: Phase One + +## Summary + +Run `e sync --3` repeatedly, fixing patch conflicts as they arise, until it succeeds. Then export patches and commit changes atomically. + +## Success Criteria + +Phase One is complete when: +- `e sync --3` exits with code 0 (no patch failures) +- All changes are committed per the commit guidelines + +Do not stop until these criteria are met. + +**CRITICAL** Do not delete or skip patches unless 100% certain the patch is no longer needed. For major version upgrades, patches that shim deprecated V8 APIs or backport upstream changes are often deletable because the new Node.js version already incorporates them — but verify before removing. Complicated conflicts or hard to resolve issues should be presented to the user after you have exhausted all other options. Do not delete the patch just because you can't solve it. + +**CRITICAL** Never use `git am --skip` and then manually recreate a patch by making a new commit. This destroys the original patch's authorship, commit message, and position in the series. If `git am --continue` reports "No changes", investigate why — the changes were likely absorbed by a prior conflict resolution's 3-way merge. Present this situation to the user rather than skipping and recreating. + +## Context + +The `roller/node/main` branch is created by automation to update Electron's Node.js dependency version in `DEPS`. No work has been done to handle breaking changes between the old and new versions. + +There are two types of Node.js version updates: +- **Bumps** (patch/minor): Automated by `electron-roller[bot]` with commit title `chore: bump node to v{version}`. Trivial patch index updates are handled automatically by `patchup[bot]`. These often land cleanly, but may require manual patch fixes. +- **Major upgrades** (e.g., v22 → v24): Manual, large PRs with commit title `chore: upgrade Node.js to v{X}.{Y}.{Z}`. These typically involve deleting obsolete patches, adapting many others, and updating `@types/node` in `package.json`. + +**Key directories:** +- Current directory: Electron repo (always run `e` commands here) +- `../third_party/electron_node`: Node.js repo (where patches apply) +- `patches/node/`: Patch files for Node.js +- `docs/development/patches.md`: Patch system documentation + +## Pre-flight Checks + +Run these once at the start of each upgrade session: + +1. **Clear rerere cache** (if enabled): `git rerere clear` in both the electron and `../third_party/electron_node` repos. Stale recorded resolutions from a prior attempt can silently apply wrong merges. +2. **Ensure pre-commit hooks are installed**: Check that `.git/hooks/pre-commit` exists. If not, run `yarn husky` to install it. The hook runs `lint-staged` which handles clang-format for C++ files. + +## Workflow + +1. Run `e sync --3` (the `--3` flag enables 3-way merge, always required) +2. If succeeds → skip to step 5 +3. If patch fails: + - Identify target repo and patch from error output + - Analyze failure (see references/patch-analysis.md) + - Fix conflict in `../third_party/electron_node` working directory + - Run `git am --continue` in `../third_party/electron_node` + - Repeat until all patches for that repo apply + - IMPORTANT: Once `git am --continue` succeeds you MUST run `e patches node` to export fixes + - Return to step 1 +4. When `e sync --3` succeeds, run `e patches all` +5. **Read `references/phase-one-commit-guidelines.md` NOW**, then commit changes following those instructions exactly. + +## Commands Reference + +| Command | Purpose | +|---------|---------| +| `e sync --3` | Clone deps and apply patches with 3-way merge | +| `git am --continue` | Continue after resolving conflict (run in node repo) | +| `e patches node` | Export commits from node repo to patch files | +| `e patches all` | Export all patches from all targets | +| `e patches node --commit-updates` | Export patches and auto-commit trivial changes | +| `e patches --list-targets` | List targets and config paths | + +## Patch System Mental Model + +``` +patches/node/*.patch → [e sync --3] → ../third_party/electron_node commits + ← [e patches] ← +``` + +## When to Edit Patches + +| Situation | Action | +|-----------|--------| +| During active `git am` conflict | Fix in node repo, then `git am --continue` | +| Modifying patch outside conflict | Edit `.patch` file directly | +| Creating new patch (rare, avoid) | Commit in node repo, then `e patches node` | + +Fix existing patches 99% of the time rather than creating new ones. + +## Patch Fixing Rules + +1. **Preserve authorship**: Keep original author in TODO comments (from patch `From:` field) +2. **Never change TODO assignees**: `TODO(name)` must retain original name +3. **Update descriptions**: If upstream changed APIs or macros, update patch commit message to reflect current state +4. **Never skip-and-recreate a patch**: If `git am --continue` says "No changes — did you forget to use 'git add'?", do NOT run `git am --skip` and create a replacement commit. The patch's changes were already absorbed by a prior 3-way merge resolution. This means an earlier conflict resolution pulled in too many changes. Present the situation to the user for guidance — the correct fix may require re-doing an earlier resolution more carefully to keep each patch's changes separate. + +# Electron Node.js Upgrade: Phase Two + +## Summary + +Run `e build -k 999 -- --quiet` repeatedly, fixing build issues as they arise, until it succeeds. Then run `e start --version` to validate Electron launches and commit changes atomically. + +Run Phase Two immediately after Phase One is complete. + +## Success Criteria + +Phase Two is complete when: +- `e build -k 999 -- --quiet` exits with code 0 (no build failures) +- `e start --version` has been run to check Electron launches +- All changes are committed per the commit guidelines + +Do not stop until these criteria are met. Do not delete code or features, never comment out code in order to take short cut. Make all existing code, logic and intention work. + +## Context + +The `roller/node/main` branch is created by automation to update Electron's Node.js dependency version in `DEPS`. No work has been done to handle breaking changes between the old and new versions. Node.js APIs (especially internal V8 integration, OpenSSL/BoringSSL compatibility, and build system files) frequently change between versions. In every case the code in Electron must be updated to account for the change in Node.js, strongly avoid making changes to the code in Node.js to fix Electron's build. + +**Key directories:** +- Current directory: Electron repo (always run `e` commands here) +- `../third_party/electron_node`: Node.js repo (do not touch this code to fix build issues, just read it to obtain context) + +## Workflow + +1. Run `e build -k 999 -- --quiet` (the `--quiet` flag suppresses per-target status lines, showing only errors and the final result) +2. If succeeds → skip to step 6 +3. If build fails: + - Identify underlying file in "electron" from the compilation error message + - Analyze failure + - Fix build issue by adapting Electron's code for the change in Node.js + - Run `e build -t {target_that_failed}.o` to build just the failed target we were specifically fixing + - You can identify the target_that_failed from the failure line in the build log. E.g. `FAILED: 2e506007-8d5d-4f38-bdd1-b5cd77999a77 "./obj/electron/shell/browser/api/electron_api_utility_process.o" CXX obj/electron/shell/browser/api/electron_api_utility_process.o` the target name is `obj/electron/shell/browser/api/electron_api_utility_process.o` + - **Read `references/phase-two-commit-guidelines.md` NOW**, then commit changes following those instructions exactly. + - Return to step 1 +4. **CRITICAL**: After ANY commit (especially patch commits), immediately run `git status` in the electron repo + - Look for other modified `.patch` files that only have index/hunk header changes + - These are dependent patches affected by your fix + - Commit them immediately with: `git commit -am "chore: update patches (trivial only)"` +5. Return to step 1 +6. When `e build` succeeds, run `e start --version` +7. Check if you have any pending changes in the Node.js repo by running `git status` in `../third_party/electron_node` + - If you have changes follow the instructions below in "A. Patch Fixes" to correctly commit those modifications into the appropriate patch file + +## Commands Reference + +| Command | Purpose | +|---------|---------| +| `e build -k 999 -- --quiet` | Build Electron, continue on errors, suppress status lines | +| `e build -t {target}.o` | Build just one specific target to verify a fix | +| `e start --version` | Validate Electron launches after successful build | + +## Two Types of Build Fixes + +### A. Patch Fixes (for files in patched Node.js files) + +When the error is in a file that Electron patches (check with `grep -l "filename" patches/node/*.patch`): + +1. Edit the file in the Node.js source tree (`../third_party/electron_node/...`) +2. Create a fixup commit targeting the original patch commit: + ```bash + cd ../third_party/electron_node + git add + git commit --fixup= + GIT_SEQUENCE_EDITOR=: git rebase --autosquash --autostash -i ^ + ``` +3. Export the updated patch: `e patches node` +4. Commit the updated patch file following `references/phase-one-commit-guidelines.md`. + +To find the original patch commit to fixup: `git log --oneline | grep -i "keyword from patch name"` + +The base commit for rebase is the Node.js commit before patches were applied. Find it by checking the `refs/patches/upstream-head` ref. + +### B. Electron Code Fixes (for files in shell/, electron/, etc.) + +When the error is in Electron's own source code: + +1. Edit files directly in the electron repo +2. Commit directly (no patch export needed) + +# Electron Node.js Upgrade: Phase Three + +## Summary + +Run the Node.js test suite via `script/node-spec-runner.js`, fix failing tests, and commit fixes until all tests pass. Certain tests are permanently disabled (listed in `script/node-disabled-tests.json`) and should not be run. + +Run Phase Three immediately after Phase Two is complete. + +## Success Criteria + +Phase Three is complete when: +- `node script/node-spec-runner.js --default` exits with zero failures +- All changes are committed per the commit guidelines + +Do not stop until these criteria are met. + +## Context + +Electron runs a subset of Node.js's upstream test suite using a custom runner (`script/node-spec-runner.js`). Tests are executed with the built Electron binary via `ELECTRON_RUN_AS_NODE=true`. Many tests need adaptation because Electron uses BoringSSL (not OpenSSL) and Chromium's V8 (which may differ from Node.js's bundled V8). + +**Key files:** +- `script/node-spec-runner.js` — Test runner script +- `script/node-disabled-tests.json` — Permanently disabled tests (do not try to fix these) +- `../third_party/electron_node/test/` — Node.js test files (where patches apply) +- `patches/node/fix_crypto_tests_to_run_with_bssl.patch` — BoringSSL crypto test adaptations +- `patches/node/test_formally_mark_some_tests_as_flaky.patch` — Flaky test list + +## Workflow + +1. Run `node script/node-spec-runner.js --default` from the electron repo +2. If all tests pass → Phase Three is complete +3. If tests fail: + - Identify the failing test file(s) from the output + - Analyze each failure (see "Common Failure Patterns" below) + - Fix the test in `../third_party/electron_node/test/...` + - Re-run the specific failing test to verify: `node script/node-spec-runner.js {test-path}` + - The test path is relative to the node `test/` directory, e.g. `test/parallel/test-crypto-key-objects-raw.js` + - Do NOT use `--default` when running specific tests — it adds the full suite flags + - Do NOT run tests directly with `ELECTRON_RUN_AS_NODE` — the runner handles environment setup (e.g. temporarily switching `package.json` from ESM to CommonJS) + - Commit the fix using the fixup workflow and commit guidelines + - Return to step 1 + +## Commands Reference + +| Command | Purpose | +|---------|---------| +| `node script/node-spec-runner.js --default` | Run full Node.js test suite | +| `node script/node-spec-runner.js test/parallel/test-foo.js` | Run a single test | +| `NODE_REGENERATE_SNAPSHOTS=1 node script/node-spec-runner.js test/test-runner/test-foo.mjs` | Regenerate snapshot for a snapshot-based test | + +## Common Failure Patterns + +### BoringSSL incompatibilities + +Electron uses BoringSSL (via Chromium) instead of OpenSSL. Many crypto features are missing or behave differently: + +| Unsupported in BoringSSL | Guard pattern | +|--------------------------|---------------| +| ChaCha20-Poly1305 | `if (!process.features.openssl_is_boringssl)` | +| AES-CCM (aes-128-ccm, aes-256-ccm) | `if (ciphers.includes('aes-128-ccm'))` | +| AES-KW (key wrapping) | `if (!process.features.openssl_is_boringssl)` | +| DSA keys | `if (!process.features.openssl_is_boringssl)` | +| Ed448 / X448 curves | `if (!process.features.openssl_is_boringssl)` | +| DH key PEM loading | `if (!process.features.openssl_is_boringssl)` | +| PQC algorithms (ML-KEM, ML-DSA, SLH-DSA) | `if (hasOpenSSL(3, 5))` (already guards these) | + +When guarding tests, prefer checking cipher availability (`ciphers.includes(algo)`) over blanket BoringSSL checks where possible, as it's more precise and self-documenting. + +New upstream tests that exercise these features will need guards added to the `fix_crypto_tests_to_run_with_bssl` patch. + +### Snapshot test mismatches + +Some tests compare output against committed `.snapshot` files using `assert.strictEqual` — these are NOT wildcard comparisons. When Chromium's V8 produces different output (e.g. different stack traces due to V8 enhancements), the snapshot must be regenerated: + +```bash +NODE_REGENERATE_SNAPSHOTS=1 node script/node-spec-runner.js test/test-runner/test-foo.mjs +``` + +Then inspect the diff to verify the changes are expected, and commit the updated snapshot into the appropriate patch. + +### V8 behavioral differences + +Chromium's V8 may be ahead of Node.js's bundled V8. This can cause: +- Different stack trace formats (e.g. thenable async stack frames) +- Different error messages +- Features available in Chromium V8 that aren't in stock Node.js V8 (or vice versa) + +## Two Types of Test Fixes + +### A. Patch Fixes (most common for test failures) + +Most test fixes go into existing patches in `patches/node/`. Use the fixup workflow: + +1. Edit the test file in `../third_party/electron_node/test/...` +2. Find the relevant patch commit: `git log --oneline | grep -i "keyword"` + - Crypto/BoringSSL tests → `fix crypto tests to run with bssl` + - Snapshot tests → the specific snapshot patch (e.g. `test: accomodate V8 thenable`) + - Flaky tests → `test: formally mark some tests as flaky` +3. Create a fixup commit: + ```bash + cd ../third_party/electron_node + git add test/path/to/test.js + git commit --fixup= + GIT_SEQUENCE_EDITOR=: git rebase --autosquash --autostash -i ^ + ``` +4. Export: `e patches node` +5. **Read `references/phase-three-commit-guidelines.md` NOW**, then commit the updated patch file. + +### B. New Patches (rare) + +Only create a new patch when the fix doesn't belong in any existing patch. The new patch commit in `../third_party/electron_node` must include a description explaining why the patch exists and when it can be removed — the lint check enforces this. + +## Adding to Disabled Tests + +Only add a test to `script/node-disabled-tests.json` as a **last resort** — when the test is fundamentally incompatible with Electron's architecture (not just a BoringSSL difference that can be guarded). Tests disabled here are completely skipped and never run. + +# Critical: Read Before Committing + +- Before ANY Phase One commits: Read `references/phase-one-commit-guidelines.md` +- Before ANY Phase Two commits: Read `references/phase-two-commit-guidelines.md` +- Before ANY Phase Three commits: Read `references/phase-three-commit-guidelines.md` + +# High-Churn Patches + +These patches consistently require the most work during Node.js upgrades: + +- **`fix_handle_boringssl_and_openssl_incompatibilities.patch`** — Electron uses BoringSSL (via Chromium) while Node.js expects OpenSSL. This patch is large and complex, and upstream OpenSSL API changes frequently break it. +- **`fix_crypto_tests_to_run_with_bssl.patch`** — Companion to the above; adapts Node.js crypto tests for BoringSSL. Can grow significantly during major upgrades. +- **`support_v8_sandboxed_pointers.patch`** — V8 sandbox pointer support requires careful adaptation when V8 APIs change. +- **`build_add_gn_build_files.patch`** — The GN build file patch is large and touches many build targets. Upstream build system changes frequently conflict. + +# Major Version Upgrades + +Major Node.js version transitions (e.g., v22 → v24) are significantly more involved than patch bumps: + +1. **Expect patch deletions.** Electron uses Chromium's V8, which is often ahead of the V8 version bundled in Node.js. Many patches exist to bridge this gap — shimming newer V8 APIs that Chromium's V8 has but Node.js' older V8 doesn't. When Node.js bumps to a newer major version, its V8 catches up to Chromium's, and those bridge patches can be deleted. In the v22 → v24 upgrade, 17 patches were deleted for this reason. +2. **Update `@types/node`** in `package.json` to match the new major version. +3. **Post-upgrade regressions are expected.** Even after the upgrade lands, follow-up fix PRs for edge cases (ESM path handling, certificate loading, platform-specific issues) are normal. + +# Skill Directory Structure +This skill has additional reference files in `references/`: +- patch-analysis.md - How to analyze patch failures +- phase-one-commit-guidelines.md - Commit format for Phase One +- phase-two-commit-guidelines.md - Commit format for Phase Two +- phase-three-commit-guidelines.md - Commit format for Phase Three + +Read these when referenced in the workflow steps. diff --git a/.claude/skills/electron-node-upgrade/references/patch-analysis.md b/.claude/skills/electron-node-upgrade/references/patch-analysis.md new file mode 100644 index 0000000000000..50c5eb2f34061 --- /dev/null +++ b/.claude/skills/electron-node-upgrade/references/patch-analysis.md @@ -0,0 +1,112 @@ +# Analyzing Patch Failures + +## Investigation Steps + +1. **Read the patch file** at `patches/node/{patch_name}.patch` + +2. **Examine current state** of the file in the Node.js repo at mentioned line numbers + +3. **Check recent upstream changes:** + ```bash + cd ../third_party/electron_node + git log --oneline -10 -- {file} + ``` + +4. **Find Node.js PR** in commit messages: + ``` + PR-URL: https://github.com/nodejs/node/pull/{PR_NUMBER} + ``` + +## Critical: Resolve by Intent, Not by Mechanical Merge + +When resolving a patch conflict, do NOT blindly preserve the patch's old code. Instead: + +1. **Understand the upstream commit's full scope** — not just the conflicting hunk. + Run `git show --stat` and read diffs for all affected files. + Upstream may have removed structs, members, or methods that the patch + references in other hunks or files. + +2. **Re-read the patch commit message** to understand its *intent* — what + behavior does it need to preserve or add? + +3. **Implement the intent against the new upstream code.** If the patch's + purpose is "add BoringSSL compatibility", add only the compatibility + layer — don't also restore old code that upstream separately removed. + +### Lesson: Upstream Removals Break Patch References + +- **Trigger:** Patch conflict involves an upstream refactor (not just context drift) +- **Strategy:** After identifying the upstream commit, check its full diff for + removed types, members, and methods. If the patch's old code references + something removed, the resolution must use the new upstream mechanism. + +### Lesson: Separate Patch Purpose from Patch Implementation + +- **Trigger:** Conflict between "upstream simplified code" vs "patch has older code" +- **Strategy:** Identify the *minimal* change the patch needs. If the patch + wraps code in a conditional, only add the conditional — don't restore old + code that was inside the conditional but was separately cleaned up upstream. + +### Lesson: Finish the Adaptation at Conflict Time + +- **Trigger:** A patch conflict involves an upstream API removal or replacement +- **Strategy:** When resolving the conflict, fully adapt the patch to use the + new API in the same commit. Don't remove the old code and leave behind stale + references that will "be fixed in Phase Two." Each patch fix commit should be + a complete resolution. + +## Common Failure Patterns + +| Pattern | Cause | Solution | +|---------|-------|----------| +| Context lines don't match | Surrounding code changed | Update context in patch | +| File not found | File renamed/moved | Update patch target path | +| Function not found | Refactored upstream | Find new function name | +| OpenSSL → BoringSSL mismatch | Crypto API change | Update to BoringSSL-compatible API | +| GYP/GN build change | Build system refactor | Adapt build patch to new structure | +| Deleted code | Feature removed | Verify patch still needed | +| V8 API bridge patch conflicts | Node.js caught up to Chromium's V8 | Patch may be deletable — verify the API is now in Node.js' V8 natively | + +## Using Git Blame + +To find the commit that changed specific lines: + +```bash +cd ../third_party/electron_node +git blame -L {start},{end} -- {file} +git log -1 {commit_sha} # Look for PR-URL: line +``` + +## Verifying Patch Necessity + +Before deleting a patch, verify: +1. The patched functionality was intentionally removed upstream +2. Electron doesn't need the patch for other reasons +3. No other code depends on the patched behavior + +**V8 bridge patches:** Electron uses Chromium's V8, which is often ahead of the V8 bundled in Node.js. Many patches exist to bridge this version gap — adapting Node.js code to work with newer V8 APIs that Chromium's V8 exposes. During major Node.js upgrades, Node.js' V8 catches up to Chromium's, and these bridge patches often become unnecessary. Check whether the API the patch shims is now available natively in the new Node.js version's V8. + +When in doubt, keep the patch and adapt it. + +## Phase Two: Build-Time Patch Issues + +Sometimes patches that applied successfully in Phase One cause build errors in Phase Two. This can happen when: + +1. **Incomplete types**: A patch disables a header include, but new upstream code uses the type +2. **Missing members**: A patch modifies a class, but upstream added new code referencing the original + +### Finding Which Patch Affects a File + +```bash +grep -l "filename.cc" patches/node/*.patch +``` + +### Matching Existing Patch Patterns + +When fixing build errors in patched files, examine the existing patch to understand its style: +- Does it use `#if 0` / `#endif` guards? +- Does it use `#if BUILDFLAG(...)` conditionals? +- Does it use `#ifndef` / `#ifdef` guards for BoringSSL vs OpenSSL? +- What's the pattern for disabled functionality? + +Apply fixes consistent with the existing patch style. diff --git a/.claude/skills/electron-node-upgrade/references/phase-one-commit-guidelines.md b/.claude/skills/electron-node-upgrade/references/phase-one-commit-guidelines.md new file mode 100644 index 0000000000000..f11d69faaf67f --- /dev/null +++ b/.claude/skills/electron-node-upgrade/references/phase-one-commit-guidelines.md @@ -0,0 +1,111 @@ +# Phase One Commit Guidelines + +Only follow these instructions if there are uncommitted changes to `patches/` after Phase One succeeds. + +Ignore other instructions about making commit messages, our guidelines are CRITICALLY IMPORTANT and must be followed. + +## Each Commit Must Be Complete + +When resolving a patch conflict, fully adapt the patch to the new upstream code in the same commit. If the upstream change removes an API the patch uses, update the patch to use the replacement API now — don't leave stale references knowing they'll need fixing later. The goal is that each commit represents a finished resolution, not a partial one that defers known work to a future phase. + +## Commit Message Style + +**Titles** follow the 60/80-character guideline: simple changes fit within 60 characters, otherwise the limit is 80 characters. + +Always include a `Co-Authored-By` trailer identifying the AI model that assisted (e.g., `Co-Authored-By: `). + +### Patch conflict fixes + +Use `fix(patch):` prefix. The title should name the upstream change, not your response to it: + +``` +fix(patch): {topic headline} + +Ref: {Node.js commit or issue link} + +Co-Authored-By: +``` + +Only add a description body if it provides clarity beyond the title. For straightforward context drift or simple API renames, the title + Ref is sufficient. + +Examples: +- `fix(patch): stop using v8::PropertyCallbackInfo::This()` +- `fix(patch): BoringSSL and OpenSSL incompatibilities` +- `fix(patch): refactor module_wrap.cc FixedArray::Get params` + +### Upstreamed patch removal + +When patches are no longer needed (applied cleanly with "already applied" or confirmed upstreamed), group ALL removals into a single commit: + +``` +chore: remove upstreamed patch +``` + +or (if multiple): + +``` +chore: remove upstreamed patches +``` + +Most Node.js patches in Electron are Electron-authored (no upstream `PR-URL:`). If the patch originated from an upstream Node.js PR, no extra `Ref:` is needed. Otherwise, add a `Ref:` pointing to the relevant Node.js issue or commit if one exists. + +### Trivial patch updates + +After all fix commits, stage remaining trivial changes (index, line numbers, context only): + +```bash +git add patches +git commit -m "chore: update patches (trivial only)" +``` + +**Conflict resolution can produce trivial results.** A `git am` conflict doesn't always mean the patch content changed — context drift alone can cause a conflict. After resolving and exporting, inspect the patch diff: if only index hashes, line numbers, and context lines changed (not the patch's own `+`/`-` lines), it's trivial and belongs here, not in a `fix(patch):` commit. + +## Atomic Commits + +Each patch conflict fix gets its own commit with its own Ref. + +IMPORTANT: Try really hard to find the PR or commit reference per the instructions below. Each change you made should in theory have been in response to a change made in Node.js that you identified or can identify. Try for a while to identify and include the ref in the commit message. Do not give up easily. + +## Finding Commit/Issue References + +Use `git log` or `git blame` on Node.js source files in `../third_party/electron_node`. Look for: + +``` +PR-URL: https://github.com/nodejs/node/pull/XXXXX +``` + +or issue references in the patch itself: + +``` +Refs: https://github.com/nodejs/node/issues/XXXXX +``` + +Note: Most Node.js patches in Electron are Electron-authored and won't have upstream references. In that case, check `git log` in the Node.js repo to find which upstream commit caused the conflict. + +If no reference found after searching: `Ref: Unable to locate reference` + +## Example Commits + +### Patch conflict fix (simple — title is sufficient) + +``` +fix(patch): stop using v8::PropertyCallbackInfo::This() + +Ref: https://github.com/nodejs/node/issues/60616 + +Co-Authored-By: +``` + +### Patch conflict fix (complex — description adds value) + +``` +fix(patch): BoringSSL and OpenSSL incompatibilities + +Upstream updated OpenSSL APIs that diverge from BoringSSL. Adapted +the compatibility shims in crypto patches to use the BoringSSL +equivalents. + +Ref: Unable to locate reference + +Co-Authored-By: +``` diff --git a/.claude/skills/electron-node-upgrade/references/phase-three-commit-guidelines.md b/.claude/skills/electron-node-upgrade/references/phase-three-commit-guidelines.md new file mode 100644 index 0000000000000..386a48552fc8c --- /dev/null +++ b/.claude/skills/electron-node-upgrade/references/phase-three-commit-guidelines.md @@ -0,0 +1,80 @@ +# Phase Three Commit Guidelines + +Only follow these instructions if there are uncommitted changes after fixing a test failure during Phase Three. + +Ignore other instructions about making commit messages, our guidelines are CRITICALLY IMPORTANT and must be followed. + +## Commit Message Style + +**Titles** follow the 60/80-character guideline: simple changes fit within 60 characters, otherwise the limit is 80 characters. + +Always include a `Co-Authored-By` trailer identifying the AI model that assisted (e.g., `Co-Authored-By: `). + +## Commit Types + +### Patch updates (most test fixes) + +Test fixes go into existing patches via the fixup workflow. Use `fix(patch):` prefix with a descriptive topic: + +``` +fix(patch): {topic headline} + +Ref: {Node.js commit or issue link} + +Co-Authored-By: +``` + +Examples: +- `fix(patch): guard DH key test for BoringSSL` +- `fix(patch): adapt new crypto tests for BoringSSL` +- `fix(patch): correct thenable snapshot for Chromium V8` +- `fix(patch): skip AES-KW tests with BoringSSL` + +Group related test fixes into a single commit when they address the same root cause (e.g., multiple crypto tests all needing BoringSSL guards for the same missing cipher). Don't create one commit per test file if they share the same fix pattern. + +### Snapshot regeneration + +When a snapshot test fails because Chromium's V8 produces different output, regenerate it: + +```bash +NODE_REGENERATE_SNAPSHOTS=1 node script/node-spec-runner.js test/test-runner/test-foo.mjs +``` + +Then commit the updated snapshot patch with a title describing what changed: + +``` +fix(patch): correct {name} snapshot for Chromium V8 + +Ref: {V8 CL or issue link if known} + +Co-Authored-By: +``` + +### Trivial patch updates + +After any patch modification, check for dependent patches that only have index/hunk header changes: + +```bash +git status +# If other .patch files show as modified with only trivial changes: +git add patches/ +git commit -m "chore: update patches (trivial only)" +``` + +## Finding References + +For BoringSSL-related test fixes, the reference is typically the upstream Node.js PR that added the new test: + +```bash +cd ../third_party/electron_node +git log --oneline -5 -- test/parallel/test-crypto-foo.js +git log -1 --format="%B" | grep "PR-URL" +``` + +For V8 behavioral differences, reference the Chromium CL: + +``` +Ref: https://chromium-review.googlesource.com/c/v8/v8/+/NNNNNNN +``` + +If no reference found after searching: `Ref: Unable to locate reference` diff --git a/.claude/skills/electron-node-upgrade/references/phase-two-commit-guidelines.md b/.claude/skills/electron-node-upgrade/references/phase-two-commit-guidelines.md new file mode 100644 index 0000000000000..7ab4066acd58c --- /dev/null +++ b/.claude/skills/electron-node-upgrade/references/phase-two-commit-guidelines.md @@ -0,0 +1,96 @@ +# Phase Two Commit Guidelines + +Only follow these instructions if there are uncommitted changes in the Electron repo after any fixes are made during Phase Two that result a target that was failing, successfully building. + +Ignore other instructions about making commit messages, our guidelines are CRITICALLY IMPORTANT and must be followed. + +## Commit Message Style + +**Titles** follow the 60/80-character guideline: simple changes fit within 60 characters, otherwise the limit is 80 characters. Exception: upstream Node.js PR titles are used verbatim even if longer. + +Always include a `Co-Authored-By` trailer identifying the AI model that assisted (e.g., `Co-Authored-By: `). + +## Two Commit Types + +### For Electron Source Changes (shell/, electron/, etc.) + +When the upstream Node.js commit has a `PR-URL:`: + +``` +node#{PR-Number}: {upstream PR's original title} + +Ref: {Node.js PR link} + +Co-Authored-By: +``` + +When there is no `PR-URL:` but there is an issue reference or commit: + +``` +fix: {description of the adaptation} + +Ref: {Node.js issue or commit link} + +Co-Authored-By: +``` + +Use the **upstream commit's original title** when available — do not paraphrase or rewrite it. To find it: check the commit message in `../third_party/electron_node` for `PR-URL:` or `Refs:` lines. + +Only add a description body if it provides clarity beyond what the title already says (e.g., when Electron's adaptation is non-obvious). For simple renames, method additions, or straightforward API updates, the title + Ref link is sufficient. + +Each change should have its own commit and its own Ref. Logically group into commits that make sense rather than one giant commit. You may include multiple "Ref" links if required. + +IMPORTANT: Try really hard to find a reference. Each change you made should in theory have been in response to a change in Node.js. Check `git log` and `git blame` in the Node.js repo. Do not give up easily. + +### For Patch Updates (patches/node/*.patch) + +Use the same fixup workflow as Phase One and follow `references/phase-one-commit-guidelines.md` for the commit message format (`fix(patch):` prefix, topic style). + +## Dependent Patch Header Updates + +After any patch modification, check for other affected patches: + +```bash +git status +# If other .patch files show as modified with only index, line number, and context changes: +git add patches/ +git commit -m "chore: update patches (trivial only)" +``` + +## Finding References + +Use `git log` or `git blame` on Node.js source files in `../third_party/electron_node`. Look for: + +``` +PR-URL: https://github.com/nodejs/node/pull/XXXXX +Refs: https://github.com/nodejs/node/issues/XXXXX +``` + +Note: Many Node.js patches in Electron are Electron-authored and won't have upstream `PR-URL:` lines. Check the patch's own commit message for `Refs:` lines, or use `git log` in the Node.js repo to find which upstream commit caused the build break. + +If no reference found after searching: `Ref: Unable to locate reference` + +## Example Commits + +### Electron Source Fix (with upstream PR) + +``` +node#61898: src: stop using v8::PropertyCallbackInfo::This() + +Ref: https://github.com/nodejs/node/pull/61898 + +Co-Authored-By: +``` + +### Electron Source Fix (with issue reference, no PR) + +``` +fix: adapt to v8::PropertyCallbackInfo::This() removal + +Updated NodeBindings to use HolderV2() after upstream Node.js +stopped using the deprecated This() API. + +Ref: https://github.com/nodejs/node/issues/60616 + +Co-Authored-By: +``` diff --git a/.devcontainer/README.md b/.devcontainer/README.md new file mode 100644 index 0000000000000..9cfac3588531b --- /dev/null +++ b/.devcontainer/README.md @@ -0,0 +1,68 @@ +# Electron Dev on Codespaces + +Welcome to the Codespaces Electron Developer Environment. + +## Quick Start + +Upon creation of your codespace you should have [build tools](https://github.com/electron/build-tools) installed and an initialized gclient checkout of Electron. In order to build electron you'll need to run the following command. + +```bash +e build +``` + +The initial build will take ~8 minutes. Incremental builds are substantially quicker. If you pull changes from upstream that touch either the `patches` folder or the `DEPS` folder you will have to run `e sync` in order to keep your checkout up to date. + +## Directory Structure + +Codespaces doesn't lean very well into gclient based checkouts, the directory structure is slightly strange. There are two locations for the `electron` checkout that both map to the same files under the hood. + +```graphql +# Primary gclient checkout container +/workspaces/gclient/* + └─ src/* - # Chromium checkout + └─ electron - # Electron checkout +# Symlinked Electron checkout (identical to the above) +/workspaces/electron +``` + +## Reclient + +If you are a maintainer [with Reclient access](../docs/development/reclient.md) you'll need to ensure you're authenticated when you spin up a new codespaces instance. You can validate this by checking `e d rbe info` - your build-tools configuration should have `Access` type `Cache & Execute`: + +```console +Authentication Status: Authenticated +Since: 2024-05-28 10:29:33 +0200 CEST +Expires: 2024-08-26 10:29:33 +0200 CEST +... +Access: Cache & Execute +``` + +To authenticate if you're not logged in, run `e d rbe login` and follow the link to authenticate. + +## Running Electron + +You can run Electron in a few ways. If you just want to see if it launches: + +```bash +# Enter an interactive JS prompt headlessly +xvfb-run e start -i +``` + +But if you want to actually see Electron you will need to use the built-in VNC capability. If you click "Ports" in codespaces and then open the `VNC web client` forwarded port you should see a web based VNC portal in your browser. When you are asked for a password use `builduser`. + +Once in the VNC UI you can open `Applications -> System -> XTerm` which will open a VNC based terminal app and then you can run `e start` like normal and Electron will open in your VNC session. + +## Running Tests + +You run tests via build-tools and `xvfb`. + +```bash +# Run all tests +xvfb-run e test + +# Run the main process tests +xvfb-run e test --runners=main + +# Run the old remote tests +xvfb-run e test --runners=remote +``` diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000000000..e8dd302c65e08 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,51 @@ +{ + "name": "Electron Core Development Environment", + "dockerComposeFile": "docker-compose.yml", + "service": "buildtools", + "onCreateCommand": ".devcontainer/on-create-command.sh", + "updateContentCommand": ".devcontainer/update-content-command.sh", + "workspaceFolder": "/workspaces/gclient/src/electron", + "forwardPorts": [6080, 5901], + "portsAttributes": { + "6080": { + "label": "VNC web client (noVNC)", + "onAutoForward": "silent" + }, + "5901": { + "label": "VNC TCP port", + "onAutoForward": "silent" + } + }, + "hostRequirements": { + "storage": "128gb", + "cpus": 16 + }, + "remoteUser": "builduser", + "customizations": { + "codespaces": { + "openFiles": [ + ".devcontainer/README.md" + ] + }, + "vscode": { + "extensions": [ + "joeleinbinder.mojom-language", + "rafaelmaiolla.diff", + "surajbarkale.ninja", + "ms-vscode.cpptools", + "mutantdino.resourcemonitor", + "dsanders11.vscode-electron-build-tools", + "oxc.oxc-vscode", + "shakram02.bash-beautify", + "marshallofsound.gnls-electron" + ], + "settings": { + "editor.tabSize": 2, + "bashBeautify.tabSize": 2, + "typescript.tsdk": "node_modules/typescript/lib", + "javascript.preferences.quoteStyle": "single", + "typescript.preferences.quoteStyle": "single" + } + } + } +} \ No newline at end of file diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml new file mode 100644 index 0000000000000..cc38966e37120 --- /dev/null +++ b/.devcontainer/docker-compose.yml @@ -0,0 +1,19 @@ +version: '3' + +services: + buildtools: + image: ghcr.io/electron/devcontainer:eac3529546ea8f3aa356d31e345715eef342233b + + volumes: + - ..:/workspaces/gclient/src/electron:cached + + - /var/run/docker.sock:/var/run/docker.sock + + command: /bin/sh -c "while sleep 1000; do :; done" + + user: builduser + + cap_add: + - SYS_PTRACE + security_opt: + - seccomp:unconfined diff --git a/.devcontainer/on-create-command.sh b/.devcontainer/on-create-command.sh new file mode 100755 index 0000000000000..6a441b3a0fe85 --- /dev/null +++ b/.devcontainer/on-create-command.sh @@ -0,0 +1,73 @@ +#!/bin/bash + +set -eo pipefail + +buildtools=$HOME/.electron_build_tools +gclient_root=/workspaces/gclient +buildtools_configs=/workspaces/buildtools-configs + +export PATH="$PATH:$buildtools/src" + +# Create the persisted buildtools config folder +mkdir -p $buildtools_configs +mkdir -p $gclient_root/.git-cache +rm -f $buildtools/configs +ln -s $buildtools_configs $buildtools/configs + +# Write the gclient config if it does not already exist +if [ ! -f $gclient_root/.gclient ]; then + echo "Creating gclient config" + + echo "solutions = [ + { \"name\" : \"src/electron\", + \"url\" : \"https://github.com/electron/electron\", + \"deps_file\" : \"DEPS\", + \"managed\" : False, + \"custom_deps\" : { + }, + \"custom_vars\": {}, + }, + ] + " >$gclient_root/.gclient +fi + +# Write the default buildtools config file if it does +# not already exist +if [ ! -f $buildtools/configs/evm.testing.json ]; then + echo "Creating build-tools testing config" + + write_config() { + echo " + { + \"root\": \"/workspaces/gclient\", + \"remotes\": { + \"electron\": { + \"origin\": \"https://github.com/electron/electron.git\" + } + }, + \"gen\": { + \"args\": [ + \"import(\\\"//electron/build/args/testing.gn\\\")\", + \"use_remoteexec = true\", + \"use_siso=true\" + ], + \"out\": \"Testing\" + }, + \"env\": { + \"CHROMIUM_BUILDTOOLS_PATH\": \"/workspaces/gclient/src/buildtools\", + \"GIT_CACHE_PATH\": \"/workspaces/gclient/.git-cache\" + }, + \"\$schema\": \"file:///home/builduser/.electron_build_tools/evm-config.schema.json\", + \"configValidationLevel\": \"strict\", + \"remoteBuild\": \"siso\", + \"preserveSDK\": 5 + } + " >$buildtools/configs/evm.testing.json + } + + write_config + + e use testing +else + echo "build-tools testing config already exists" +fi diff --git a/.devcontainer/update-content-command.sh b/.devcontainer/update-content-command.sh new file mode 100755 index 0000000000000..012eef97140ba --- /dev/null +++ b/.devcontainer/update-content-command.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +set -eo pipefail + +buildtools=$HOME/.electron_build_tools + +export PATH="$PATH:$buildtools/src" + +# Sync latest +e d gclient sync --with_branch_heads --with_tags diff --git a/.dockerignore b/.dockerignore index fa43feee9940a..7307e769482a1 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,3 +1,2 @@ * !tools/xvfb-init.sh -!build/install-build-deps.sh diff --git a/.env.example b/.env.example index eb3df4b6bdf9c..333d92c3eda23 100644 --- a/.env.example +++ b/.env.example @@ -1,7 +1,4 @@ # These env vars are only necessary for creating Electron releases. # See docs/development/releasing.md -APPVEYOR_CLOUD_TOKEN= -CIRCLE_TOKEN= ELECTRON_GITHUB_TOKEN= -VSTS_TOKEN= \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 55d0f1712134a..0000000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "extends": "standard", - "parser": "@typescript-eslint/parser", - "plugins": ["@typescript-eslint"], - "env": { - "browser": true - }, - "rules": { - "semi": ["error", "always"], - "no-var": "error", - "no-unused-vars": "off", - "no-global-assign": "off", - "guard-for-in": "error", - "@typescript-eslint/no-unused-vars": ["error", { - "vars": "all", - "args": "after-used", - "ignoreRestSiblings": true - }], - "prefer-const": ["error", { - "destructuring": "all" - }], - "standard/no-callback-literal": "off", - "node/no-deprecated-api": "off" - }, - "parserOptions": { - "ecmaVersion": 6, - "sourceType": "module" - }, - "overrides": [ - { - "files": "*.js", - "rules": { - "@typescript-eslint/no-unused-vars": "off" - } - }, - { - "files": "*.ts", - "rules": { - "no-undef": "off", - "no-redeclare": "off", - "@typescript-eslint/no-redeclare": ["error"], - "no-use-before-define": "off" - } - }, - { - "files": "*.d.ts", - "rules": { - "no-useless-constructor": "off", - "@typescript-eslint/no-unused-vars": "off" - } - } - ] -} diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 0000000000000..198363a8ae8fb --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,5 @@ +# Atom --> Electron rename +d9321f4df751fa32813fab1b6387bbd61bd681d0 +34c4c8d5088fa183f56baea28809de6f2a427e02 +# Enable JS Semicolons +5d657dece4102e5e5304d42e8004b6ad64c0fcda diff --git a/.gitattributes b/.gitattributes index 88189455c32c1..f4542e6b25f8f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,14 +1,34 @@ # `git apply` and friends don't understand CRLF, even on windows. Force those # files to be checked out with LF endings even if core.autocrlf is true. *.patch text eol=lf +DEPS text eol=lf +yarn.lock text eol=lf +script/zip_manifests/*.manifest text eol=lf patches/**/.patches merge=union # Source code and markdown files should always use LF as line ending. +*.c text eol=lf *.cc text eol=lf -*.mm text eol=lf +*.cpp text eol=lf +*.csv text eol=lf +*.grd text eol=lf +*.grdp text eol=lf +*.gn text eol=lf +*.gni text eol=lf *.h text eol=lf -*.js text eol=lf -*.ts text eol=lf +*.html text eol=lf +*.idl text eol=lf +*.in text eol=lf +*.js text eol=lf +*.json text eol=lf +*.json5 text eol=lf +*.md text eol=lf +*.mm text eol=lf +*.mojom text eol=lf +*.patches text eol=lf +*.proto text eol=lf *.py text eol=lf *.ps1 text eol=lf -*.md text eol=lf +*.sh text eol=lf +*.ts text eol=lf +*.txt text eol=lf diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ab2ac48d731a5..21d670175f8b7 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -4,18 +4,23 @@ # https://git-scm.com/docs/gitignore # Upgrades WG -/patches/ @electron/wg-upgrades +/patches/ @electron/patch-owners DEPS @electron/wg-upgrades # Releases WG +/docs/breaking-changes.md @electron/wg-releases /npm/ @electron/wg-releases /script/release @electron/wg-releases # Security WG +/lib/browser/devtools.ts @electron/wg-security +/lib/browser/guest-view-manager.ts @electron/wg-security /lib/browser/rpc-server.ts @electron/wg-security +/lib/renderer/security-warnings.ts @electron/wg-security -# Remote Change Disliker -/lib/browser/remote/ @nornagon -/lib/renderer/remote/ @nornagon -/lib/renderer/api/remote.ts @nornagon -/docs/api/remote.md @nornagon +# Infra WG +/.claude/ @electron/wg-infra +/.github/actions/ @electron/wg-infra +/.github/workflows/*-publish.yml @electron/wg-infra +/.github/workflows/build.yml @electron/wg-infra +/.github/workflows/pipeline-*.yml @electron/wg-infra diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md deleted file mode 100644 index a1a336a131e19..0000000000000 --- a/.github/ISSUE_TEMPLATE/Bug_report.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve Electron - ---- - - - -### Preflight Checklist - - -* [ ] I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/master/CONTRIBUTING.md) for this project. -* [ ] I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/master/CODE_OF_CONDUCT.md) that this project adheres to. -* [ ] I have searched the issue tracker for an issue that matches the one I want to file, without success. - -### Issue Details - -* **Electron Version:** - * -* **Operating System:** - * -* **Last Known Working Electron version:** - * - -### Expected Behavior - - -### Actual Behavior - - -### To Reproduce - - - - - - - - -### Screenshots - - -### Additional Information - diff --git a/.github/ISSUE_TEMPLATE/Feature_request.md b/.github/ISSUE_TEMPLATE/Feature_request.md deleted file mode 100644 index 20fc958e2ce57..0000000000000 --- a/.github/ISSUE_TEMPLATE/Feature_request.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for Electron - ---- - - - -### Preflight Checklist - - -* [ ] I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/master/CONTRIBUTING.md) for this project. -* [ ] I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/master/CODE_OF_CONDUCT.md) that this project adheres to. -* [ ] I have searched the issue tracker for a feature request that matches the one I want to file, without success. - -### Problem Description - - -### Proposed Solution - - -### Alternatives Considered - - -### Additional Information - diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000000000..77349e98b06ce --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,91 @@ +name: Bug Report +description: Report a bug in Electron +type: 'bug' +labels: "bug :beetle:" +body: +- type: checkboxes + attributes: + label: Preflight Checklist + description: Please ensure you've completed all of the following. + options: + - label: I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/main/CONTRIBUTING.md) for this project. + required: true + - label: I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/main/CODE_OF_CONDUCT.md) that this project adheres to. + required: true + - label: I have searched the [issue tracker](https://www.github.com/electron/electron/issues) for a bug report that matches the one I want to file, without success. + required: true +- type: input + attributes: + label: Electron Version + description: | + What version of Electron are you using? + + Note: Please only report issues for [currently supported versions of Electron](https://www.electronjs.org/docs/latest/tutorial/electron-timelines#timeline). + placeholder: 32.0.0 + validations: + required: true +- type: dropdown + attributes: + label: What operating system(s) are you using? + multiple: true + options: + - Windows + - macOS + - Ubuntu + - Other Linux + - Other (specify below) + validations: + required: true +- type: input + attributes: + label: Operating System Version + description: What operating system version are you using? On Windows, click Start button > Settings > System > About. On macOS, click the Apple Menu > About This Mac. On Linux, use lsb_release or uname -a. + placeholder: "e.g. Windows 10 version 1909, macOS Catalina 10.15.7, or Ubuntu 20.04" + validations: + required: true +- type: dropdown + attributes: + label: What arch are you using? + options: + - x64 + - ia32 + - arm64 (including Apple Silicon) + - Other (specify below) + validations: + required: true +- type: input + attributes: + label: Last Known Working Electron version + description: What is the last version of Electron this worked in, if applicable? + placeholder: 16.0.0 +- type: dropdown + attributes: + label: Does the issue also appear in Chromium / Google Chrome? + description: If it does, please report the issue in the [Chromium issue tracker](https://issues.chromium.org/issues), not against Electron. Electron will inherit the fix once Chromium resolves the issue. + options: + - I don't know how to test + - "Yes" + - "No" + validations: + required: true +- type: textarea + attributes: + label: Expected Behavior + description: A clear and concise description of what you expected to happen. + validations: + required: true +- type: textarea + attributes: + label: Actual Behavior + description: A clear description of what actually happens. + validations: + required: true +- type: input + attributes: + label: Testcase Gist URL + description: Electron maintainers need a standalone test case to reproduce and fix your issue. Please use [Electron Fiddle](https://github.com/electron/fiddle) to create one and to publish it as a [GitHub gist](https://gist.github.com). Then put the gist URL here. Issues without testcase gists receive less attention and might be closed without a maintainer taking a closer look. To maximize how much attention your issue receives, please include a testcase gist right from the start. + placeholder: https://gist.github.com/... +- type: textarea + attributes: + label: Additional Information + description: If your problem needs further explanation, or if the issue you're seeing cannot be reproduced in a gist, please add more information here. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000000..aa3d859873ad0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: Discord Chat + url: https://discord.gg/APGC3k5yaH + about: Have questions? Try asking on our Discord - this issue tracker is for reporting bugs or feature requests only + - name: Open Collective + url: https://opencollective.com/electron + about: Help support Electron by contributing to our Open Collective diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000000000..5bca8a2be4eb4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,40 @@ +name: Feature Request +description: Suggest an idea for Electron +type: 'enhancement' +labels: "enhancement :sparkles:" +body: +- type: checkboxes + attributes: + label: Preflight Checklist + description: Please ensure you've completed all of the following. + options: + - label: I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/main/CONTRIBUTING.md) for this project. + required: true + - label: I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/main/CODE_OF_CONDUCT.md) that this project adheres to. + required: true + - label: I have searched the [issue tracker](https://www.github.com/electron/electron/issues) for a feature request that matches the one I want to file, without success. + required: true +- type: textarea + attributes: + label: Problem Description + description: Please add a clear and concise description of the problem you are seeking to solve with this feature request. + validations: + required: true +- type: textarea + attributes: + label: Proposed Solution + description: Describe the solution you'd like in a clear and concise manner. + validations: + required: true +- type: textarea + attributes: + label: Alternatives Considered + description: A clear and concise description of any alternative solutions or features you've considered. + validations: + required: true +- type: textarea + attributes: + label: Additional Information + description: Add any other context about the problem here. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/mac_app_store_private_api_rejection.md b/.github/ISSUE_TEMPLATE/mac_app_store_private_api_rejection.md deleted file mode 100644 index cefd5800e2a73..0000000000000 --- a/.github/ISSUE_TEMPLATE/mac_app_store_private_api_rejection.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -name: Mac App Store Private API Rejection -about: Your app was rejected from the Mac App Store for using private API's - ---- - - - -### Preflight Checklist - - -* [ ] I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/master/CONTRIBUTING.md) for this project. -* [ ] I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/master/CODE_OF_CONDUCT.md) that this project adheres to. - -### Issue Details - -* **Electron Version:** - * - -### Rejection Email - - -### Additional Information - diff --git a/.github/ISSUE_TEMPLATE/mac_app_store_private_api_rejection.yml b/.github/ISSUE_TEMPLATE/mac_app_store_private_api_rejection.yml new file mode 100644 index 0000000000000..df6f0fc972877 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/mac_app_store_private_api_rejection.yml @@ -0,0 +1,30 @@ +name: Report Mac App Store Private API Rejection +description: Your app was rejected from the Mac App Store for using private API's +title: "[MAS Rejection]: " +body: +- type: checkboxes + attributes: + label: Preflight Checklist + description: Please ensure you've completed all of the following. + options: + - label: I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/main/CONTRIBUTING.md) for this project. + required: true + - label: I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/main/CODE_OF_CONDUCT.md) that this project adheres to. + required: true +- type: input + attributes: + label: Electron Version + description: What version of Electron are you using? + placeholder: 12.0.0 + validations: + required: true +- type: textarea + attributes: + label: Rejection Email + description: Paste the contents of your rejection email here, censoring any private information such as app names. + validations: + required: true +- type: textarea + attributes: + label: Additional Information + description: Add any other context about the problem here. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 811ad5aea3efd..ea5e97697b4f4 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,20 +1,27 @@ #### Description of Change + #### Checklist -- [ ] PR description included and stakeholders cc'd +- [ ] I have built and tested this change +- [ ] I have filled out the PR description +- [ ] [I have reviewed and verified the changes](https://github.com/electron/governance/blob/main/policy/ai.md) - [ ] `npm test` passes -- [ ] tests are [changed or added](https://github.com/electron/electron/blob/master/docs/development/testing.md) -- [ ] relevant documentation is changed or added -- [ ] [PR release notes](https://github.com/electron/clerk/blob/master/README.md) describe the change in a way relevant to app developers, and are [capitalized, punctuated, and past tense](https://github.com/electron/clerk/blob/master/README.md#examples). +- [ ] tests are [changed or added](https://github.com/electron/electron/blob/main/docs/development/testing.md) +- [ ] relevant API documentation, tutorials, and examples are updated and follow the [documentation style guide](https://github.com/electron/electron/blob/main/docs/development/style-guide.md) +- [ ] [PR release notes](https://github.com/electron/clerk/blob/main/README.md) describe the change in a way relevant to app developers, and are [capitalized, punctuated, and past tense](https://github.com/electron/clerk/blob/main/README.md#examples). #### Release Notes -Notes: +Notes: diff --git a/.github/actions/build-electron/action.yml b/.github/actions/build-electron/action.yml new file mode 100644 index 0000000000000..dec1ab5983ba2 --- /dev/null +++ b/.github/actions/build-electron/action.yml @@ -0,0 +1,356 @@ +name: 'Build Electron' +description: 'Builds Electron & Friends' +inputs: + target-arch: + description: 'Target arch' + required: true + target-platform: + description: 'Target platform, should be linux, win, macos' + required: true + artifact-platform: + description: 'Artifact platform, should be linux, win, darwin or mas' + required: true + step-suffix: + description: 'Suffix for build steps' + required: false + default: '' + is-release: + description: 'Is release build' + required: true + generate-symbols: + description: 'Generate symbols' + required: true + upload-to-storage: + description: 'Upload to storage' + required: true + is-asan: + description: 'The ASan Linux build' + required: false + upload-out-gen-artifacts: + description: 'Whether to upload the out/${dir}/gen artifacts' + required: false +runs: + using: "composite" + steps: + - name: Set GN_EXTRA_ARGS for MacOS x64 Builds + shell: bash + if: ${{ inputs.target-arch == 'x64' && inputs.target-platform == 'macos' }} + run: | + GN_APPENDED_ARGS="$GN_EXTRA_ARGS target_cpu=\"x64\" v8_snapshot_toolchain=\"//build/toolchain/mac:clang_x64\"" + echo "GN_EXTRA_ARGS=$GN_APPENDED_ARGS" >> $GITHUB_ENV + - name: Set GN_EXTRA_ARGS for Windows + shell: bash + if: ${{ inputs.target-platform == 'win' }} + run: | + # Resolve .obj paths to absolute in linker response files to work + # around BindFlt concurrency bug in Windows containers. + # https://github.com/microsoft/Windows-Containers/issues/635 + GN_APPENDED_ARGS="$GN_EXTRA_ARGS win_abs_link_wrapper=\"//electron/build/win/abs_link_wrapper.py\"" + if [ "${{ inputs.target-arch }}" != "x64" ]; then + GN_APPENDED_ARGS="$GN_APPENDED_ARGS target_cpu=\"${{ inputs.target-arch }}\"" + fi + echo "GN_EXTRA_ARGS=$GN_APPENDED_ARGS" >> $GITHUB_ENV + - name: Add Clang problem matcher + shell: bash + run: echo "::add-matcher::src/electron/.github/problem-matchers/clang.json" + - name: Download previous object checksums + shell: bash + if: ${{ (github.event_name == 'push' || github.event_name == 'pull_request') && inputs.is-asan != 'true' }} + env: + GITHUB_TOKEN: ${{ github.token }} + ARTIFACT_NAME: object-checksums.${{ inputs.artifact-platform }}_${{ inputs.target-arch }}.json + SEARCH_BRANCH: ${{ case(github.event_name == 'push', github.ref_name, github.event.pull_request.base.ref) }} + REPO: ${{ github.repository }} + OUTPUT_PATH: src/previous-object-checksums.json + run: node src/electron/.github/actions/build-electron/download-previous-object-checksums.mjs + - name: Build Electron ${{ inputs.step-suffix }} + if: ${{ inputs.target-platform != 'win' }} + shell: bash + run: | + rm -rf "src/out/Default/Electron Framework.framework" + rm -rf src/out/Default/Electron*.app + + cd src/electron + # TODO(codebytere): remove this once we figure out why .git/packed-refs is initially missing + git pack-refs + cd .. + + if [ "`uname`" = "Darwin" ]; then + ulimit -n 10000 + sudo launchctl limit maxfiles 65536 200000 + fi + + if [ "${{ inputs.is-release }}" = "true" ]; then + NINJA_SUMMARIZE_BUILD=1 e build --target electron:release_build + else + NINJA_SUMMARIZE_BUILD=1 e build --target electron:testing_build + fi + cp out/Default/.ninja_log out/electron_ninja_log + node electron/script/check-symlinks.js + + # Build stats and object checksums + BUILD_STATS_ARGS="out/Default/siso.INFO --out-dir out/Default --output-object-checksums object-checksums.${{ inputs.artifact-platform }}_${{ inputs.target-arch }}.json" + if [ -f previous-object-checksums.json ]; then + BUILD_STATS_ARGS="$BUILD_STATS_ARGS --input-object-checksums previous-object-checksums.json" + fi + if ! [ -z "$DD_API_KEY" ]; then + BUILD_STATS_ARGS="$BUILD_STATS_ARGS --upload-stats" + else + echo "Skipping build-stats.mjs upload because DD_API_KEY is not set" + fi + node electron/script/build-stats.mjs $BUILD_STATS_ARGS || true + - name: Build Electron (Windows) ${{ inputs.step-suffix }} + if: ${{ inputs.target-platform == 'win' }} + shell: powershell + run: | + cd src\electron + git pack-refs + cd .. + + # Pre-create the ThinLTO cache directory so lld-link does not need to + # call CreateDirectoryW through the bindflt filter driver, which can + # return ERROR_INVALID_PARAMETER under concurrent I/O on ARC runners. + # + # The path mirrors `cache_dir` in Chromium's + # build/config/compiler/BUILD.gn (the `/lldltocache:` ldflag passed + # to lld-link). Dynamic discovery via `gn desc` isn't viable here: + # `e init` doesn't populate `out/Default`, and `gn gen` can't run + # before `e build` because gn.exe isn't installed on the runner + # until a later hook. If upstream ever relocates `cache_dir`, this + # pre-create silently stops covering the race and the + # `LLVM ERROR: can't create cache directory` symptom returns — at + # which point update the path here. + New-Item -ItemType Directory -Force -Path out\Default\thinlto-cache | Out-Null + + $env:NINJA_SUMMARIZE_BUILD = 1 + if ("${{ inputs.is-release }}" -eq "true") { + e build --target electron:release_build + } else { + e build --target electron:testing_build + } + if ($LASTEXITCODE -ne 0) { + Write-Host "e build failed with exit code $LASTEXITCODE" + exit $LASTEXITCODE + } + Copy-Item out\Default\.ninja_log out\electron_ninja_log + node electron\script\check-symlinks.js + + # Build stats and object checksums + $statsArgs = @("out\Default\siso.exe.INFO", "--out-dir", "out\Default", "--output-object-checksums", "object-checksums.${{ inputs.artifact-platform }}_${{ inputs.target-arch }}.json") + if (Test-Path previous-object-checksums.json) { + $statsArgs += @("--input-object-checksums", "previous-object-checksums.json") + } + if ($env:DD_API_KEY) { + $statsArgs += "--upload-stats" + } else { + Write-Host "Skipping build-stats.mjs upload because DD_API_KEY is not set" + } + try { + & node electron\script\build-stats.mjs @statsArgs ; $LASTEXITCODE = 0 + } catch { + Write-Host "Build stats failed, continuing..." + } + - name: Verify dist.zip ${{ inputs.step-suffix }} + shell: bash + run: | + cd src + if [ "${{ inputs.is-asan }}" != "true" ]; then + target_os=${{ inputs.target-platform == 'macos' && 'mac' || inputs.target-platform }} + if [ "${{ inputs.artifact-platform }}" = "mas" ]; then + target_os="${target_os}_mas" + fi + electron/script/zip_manifests/check-zip-manifest.py out/Default/dist.zip electron/script/zip_manifests/dist_zip.$target_os.${{ inputs.target-arch }}.manifest + fi + - name: Fixup Mksnapshot ${{ inputs.step-suffix }} + shell: bash + run: | + cd src + ELECTRON_DEPOT_TOOLS_DISABLE_LOG=1 e d gn desc out/Default v8:run_mksnapshot_default args > out/Default/mksnapshot_args + # Remove unused args from mksnapshot_args + SEDOPTION="-i" + if [ "`uname`" = "Darwin" ]; then + SEDOPTION="-i ''" + fi + sed $SEDOPTION '/.*builtins-pgo/d' out/Default/mksnapshot_args + sed $SEDOPTION '/--turbo-profiling-input/d' out/Default/mksnapshot_args + sed $SEDOPTION '/--reorder-builtins/d' out/Default/mksnapshot_args + sed $SEDOPTION '/--warn-about-builtin-profile-data/d' out/Default/mksnapshot_args + sed $SEDOPTION '/--abort-on-bad-builtin-profile-data/d' out/Default/mksnapshot_args + + if [ "${{ inputs.target-platform }}" = "win" ]; then + cd out/Default + powershell Compress-Archive -update mksnapshot_args mksnapshot.zip + powershell mkdir mktmp\\gen\\v8 + powershell Copy-Item gen\\v8\\embedded.S mktmp\\gen\\v8 + powershell Compress-Archive -update -Path mktmp\\gen mksnapshot.zip + else + (cd out/Default; zip mksnapshot.zip mksnapshot_args gen/v8/embedded.S) + fi + - name: Generate Cross-Arch Snapshot (arm/arm64) ${{ inputs.step-suffix }} + shell: bash + if: ${{ (inputs.target-arch == 'arm' || inputs.target-arch == 'arm64') && inputs.target-platform == 'linux' }} + run: | + cd src + if [ "${{ inputs.target-arch }}" = "arm" ]; then + MKSNAPSHOT_PATH="clang_x86_v8_arm" + elif [ "${{ inputs.target-arch }}" = "arm64" ]; then + MKSNAPSHOT_PATH="clang_x64_v8_arm64" + fi + + cp "out/Default/$MKSNAPSHOT_PATH/mksnapshot" out/Default + cp "out/Default/$MKSNAPSHOT_PATH/v8_context_snapshot_generator" out/Default + cp "out/Default/$MKSNAPSHOT_PATH/libffmpeg.so" out/Default + + python3 electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default --create-snapshot-only + mkdir cross-arch-snapshots + cp out/Default-mksnapshot-test/*.bin cross-arch-snapshots + # Clean up so that ninja does not get confused + rm -f out/Default/libffmpeg.so + - name: Build Chromedriver ${{ inputs.step-suffix }} + shell: bash + run: | + cd src + e build --target electron:electron_chromedriver_zip + + if [ "${{ inputs.is-asan }}" != "true" ]; then + target_os=${{ inputs.target-platform == 'macos' && 'mac' || inputs.target-platform }} + if [ "${{ inputs.artifact-platform }}" = "mas" ]; then + target_os="${target_os}_mas" + fi + electron/script/zip_manifests/check-zip-manifest.py out/Default/chromedriver.zip electron/script/zip_manifests/chromedriver_zip.$target_os.${{ inputs.target-arch }}.manifest + fi + - name: Create installed_software.json ${{ inputs.step-suffix }} + shell: powershell + if: ${{ inputs.is-release == 'true' && inputs.target-platform == 'win' }} + run: | + cd src + Get-CimInstance -Namespace root\cimv2 -Class Win32_product | Select vendor, description, @{l='install_location';e='InstallLocation'}, @{l='install_date';e='InstallDate'}, @{l='install_date_2';e='InstallDate2'}, caption, version, name, @{l='sku_number';e='SKUNumber'} | ConvertTo-Json | Out-File -Encoding utf8 -FilePath .\installed_software.json + - name: Profile Windows Toolchain ${{ inputs.step-suffix }} + shell: bash + if: ${{ inputs.is-release == 'true' && inputs.target-platform == 'win' }} + run: | + cd src + python3 electron/build/profile_toolchain.py --output-json=out/Default/windows_toolchain_profile.json + - name: Add msdia140.dll to Path ${{ inputs.step-suffix }} + shell: bash + if: ${{ inputs.is-release == 'true' && inputs.target-platform == 'win' }} + run: | + # Needed for msdia140.dll on 64-bit windows + cd src + export PATH="$PATH:$(pwd)/third_party/llvm-build/Release+Asserts/bin" + - name: Zip Symbols ${{ inputs.step-suffix }} + shell: bash + run: | + cd src + export BUILD_PATH="$(pwd)/out/Default" + if [ "${{ inputs.is-release }}" = "true" ]; then + DELETE_DSYMS_AFTER_ZIP=1 electron/script/zip-symbols.py -b $BUILD_PATH + else + electron/script/zip-symbols.py -b $BUILD_PATH + fi + - name: Generate FFMpeg ${{ inputs.step-suffix }} + shell: bash + if: ${{ inputs.is-release == 'true' }} + run: | + cd src + # Reuse the hermetic mac_sdk_path that `e build` wrote for out/Default so + # out/ffmpeg builds against the same SDK instead of the runner's system Xcode. + # The path has to live under root_build_dir, so copy the symlink tree and + # rewrite Default -> ffmpeg. + MAC_SDK_ARG="" + if [ "$(uname)" = "Darwin" ]; then + mkdir -p out/ffmpeg + cp -a out/Default/xcode_links out/ffmpeg/ + MAC_SDK_ARG=$(sed -n 's|^\(mac_sdk_path = "//out/\)Default/|\1ffmpeg/|p' out/Default/args.gn) + fi + gn gen out/ffmpeg --args="import(\"//electron/build/args/ffmpeg.gn\") use_remoteexec=true use_siso=true $MAC_SDK_ARG $GN_EXTRA_ARGS" + e build --target electron:electron_ffmpeg_zip -C ../../out/ffmpeg + - name: Remove Clang problem matcher + shell: bash + run: echo "::remove-matcher owner=clang::" + - name: Generate TypeScript Definitions ${{ inputs.step-suffix }} + if: ${{ inputs.is-release == 'true' }} + shell: bash + run: | + cd src/electron + node script/yarn.js create-typescript-definitions + - name: Publish Electron Dist ${{ inputs.step-suffix }} + if: ${{ inputs.is-release == 'true' }} + shell: bash + id: github-upload + run: | + rm -rf src/out/Default/obj + cd src/electron + if [ "${{ inputs.upload-to-storage }}" = "1" ]; then + echo 'Uploading Electron release distribution to Azure' + script/release/uploaders/upload.py --verbose --upload_to_storage + else + echo 'Uploading Electron release distribution to GitHub releases' + script/release/uploaders/upload.py --verbose + fi + - name: Generate artifact attestation + if: ${{ inputs.is-release == 'true' }} + uses: actions/attest-build-provenance@96278af6caaf10aea03fd8d33a09a777ca52d62f # v3.2.0 + with: + subject-path: ${{ steps.github-upload.outputs.UPLOADED_PATHS }} + - name: Generate siso report + if: ${{ inputs.target-platform != 'win' && !cancelled() }} + shell: bash + run: | + cd src + e d siso report -C out/Default > siso_report.txt + SISO_REPORT_PATH=$(grep -o '/.*siso-report-[^ ]*' siso_report.txt) + echo "SISO_REPORT_PATH=$SISO_REPORT_PATH" >> $GITHUB_ENV + cat siso_report.txt + echo "SISO REPORT AT $SISO_REPORT_PATH" + - name: Generate siso report (Windows) + if: ${{ inputs.target-platform == 'win' && !cancelled() }} + shell: powershell + run: | + cd src + e d siso report -C out\Default > siso_report.txt + $SISO_REPORT_PATH = Get-Content "siso_report.txt" | Select-String "report file:\s*(.+)" | ForEach-Object { + $_.Matches.Groups[1].Value.Trim() + } + echo "SISO_REPORT_PATH=$SISO_REPORT_PATH" + echo "SISO_REPORT_PATH=$SISO_REPORT_PATH" >> $env:GITHUB_ENV + - name: Generate Artifact Key + if: always() && !cancelled() + shell: bash + run: | + if [ "${{ inputs.is-asan }}" = "true" ]; then + ARTIFACT_KEY=${{ inputs.artifact-platform }}_${{ inputs.target-arch }}_asan + else + ARTIFACT_KEY=${{ inputs.artifact-platform }}_${{ inputs.target-arch }} + fi + echo "ARTIFACT_KEY=$ARTIFACT_KEY" >> $GITHUB_ENV + # The current generated_artifacts_<< artifact.key >> name was taken from CircleCI + # to ensure we don't break anything, but we may be able to improve that. + - name: Move all Generated Artifacts to Upload Folder ${{ inputs.step-suffix }} + if: always() && !cancelled() + shell: bash + run: ./src/electron/script/actions/move-artifacts.sh + - name: Upload Generated Artifacts ${{ inputs.step-suffix }} + if: always() && !cancelled() + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0 + with: + name: generated_artifacts_${{ env.ARTIFACT_KEY }} + path: ./generated_artifacts_${{ inputs.artifact-platform }}_${{ inputs.target-arch }} + - name: Upload Src Artifacts ${{ inputs.step-suffix }} + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0 + with: + name: src_artifacts_${{ env.ARTIFACT_KEY }} + path: ./src_artifacts_${{ inputs.artifact-platform }}_${{ inputs.target-arch }} + - name: Upload Out Gen Artifacts ${{ inputs.step-suffix }} + if: ${{ inputs.upload-out-gen-artifacts == 'true' }} + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f #v7.0.0 + with: + name: out_gen_artifacts_${{ env.ARTIFACT_KEY }} + path: ./src/out/Default/gen + - name: Upload Object Checksums ${{ inputs.step-suffix }} + if: ${{ always() && !cancelled() && inputs.is-asan != 'true' }} + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: object_checksums_${{ inputs.artifact-platform }}_${{ inputs.target-arch }} + path: ./src/object-checksums.${{ inputs.artifact-platform }}_${{ inputs.target-arch }}.json + archive: false diff --git a/.github/actions/build-electron/download-previous-object-checksums.mjs b/.github/actions/build-electron/download-previous-object-checksums.mjs new file mode 100644 index 0000000000000..250ae3cfef071 --- /dev/null +++ b/.github/actions/build-electron/download-previous-object-checksums.mjs @@ -0,0 +1,82 @@ +import { Octokit } from '@octokit/rest'; + +import { writeFileSync } from 'node:fs'; + +const token = process.env.GITHUB_TOKEN; +const repo = process.env.REPO; +const artifactName = process.env.ARTIFACT_NAME; +const branch = process.env.SEARCH_BRANCH; +const outputPath = process.env.OUTPUT_PATH; + +const required = { GITHUB_TOKEN: token, REPO: repo, ARTIFACT_NAME: artifactName, SEARCH_BRANCH: branch, OUTPUT_PATH: outputPath }; +const missing = Object.entries(required).filter(([, v]) => !v).map(([k]) => k); +if (missing.length > 0) { + console.error(`Missing required environment variables: ${missing.join(', ')}`); + process.exit(1); +} + +const [owner, repoName] = repo.split('/'); +const octokit = new Octokit({ auth: token }); + +async function main () { + console.log(`Searching for artifact '${artifactName}' on branch '${branch}'...`); + + // Resolve the "Build" workflow name to an ID, mirroring how `gh run list --workflow` works + // under the hood (it uses /repos/{owner}/{repo}/actions/workflows/{id}/runs). + const { data: workflows } = await octokit.actions.listRepoWorkflows({ owner, repo: repoName }); + const buildWorkflow = workflows.workflows.find((w) => w.name === 'Build'); + if (!buildWorkflow) { + console.log('Could not find "Build" workflow, continuing without previous checksums'); + return; + } + + const { data: runs } = await octokit.actions.listWorkflowRuns({ + owner, + repo: repoName, + workflow_id: buildWorkflow.id, + branch, + status: 'completed', + event: 'push', + per_page: 20, + exclude_pull_requests: true + }); + + for (const run of runs.workflow_runs) { + const { data: artifacts } = await octokit.actions.listWorkflowRunArtifacts({ + owner, + repo: repoName, + run_id: run.id, + name: artifactName + }); + + if (artifacts.artifacts.length > 0) { + const artifact = artifacts.artifacts[0]; + console.log(`Found artifact in run ${run.id} (artifact ID: ${artifact.id}), downloading...`); + + // Non-archived artifacts are still downloaded from the /zip endpoint + const response = await octokit.actions.downloadArtifact({ + owner, + repo: repoName, + artifact_id: artifact.id, + archive_format: 'zip' + }); + + if (response.headers['content-type'] !== 'application/json') { + console.error(`Unexpected content type for artifact download: ${response.headers['content-type']}`); + console.error('Expected application/json, continuing without previous checksums'); + return; + } + + writeFileSync(outputPath, JSON.stringify(response.data)); + console.log('Downloaded previous object checksums successfully'); + return; + } + } + + console.log(`No previous object checksums found in last ${runs.workflow_runs.length} runs, continuing without them`); +} + +main().catch((err) => { + console.error('Failed to download previous object checksums, continuing without them:', err.message); + process.exit(0); +}); diff --git a/.github/actions/build-git-cache/action.yml b/.github/actions/build-git-cache/action.yml new file mode 100644 index 0000000000000..6a50666a50fbd --- /dev/null +++ b/.github/actions/build-git-cache/action.yml @@ -0,0 +1,83 @@ +name: 'Build Git Cache' +description: 'Runs a gclient sync to build the git cache for Electron' +inputs: + target-platform: + description: 'Target platform, should be linux, win, macos' +runs: + using: "composite" + steps: + - name: Set GIT_CACHE_PATH to make gclient to use the cache + shell: bash + run: | + echo "GIT_CACHE_PATH=$(pwd)/git-cache" >> $GITHUB_ENV + - name: Set Chromium Git Cookie + uses: ./src/electron/.github/actions/set-chromium-cookie + - name: Install Build Tools + uses: ./src/electron/.github/actions/install-build-tools + - name: Set up cache drive + shell: bash + run: | + if [ "${{ inputs.target-platform }}" = "win" ]; then + echo "CACHE_DRIVE=/mnt/win-cache" >> $GITHUB_ENV + else + echo "CACHE_DRIVE=/mnt/cross-instance-cache" >> $GITHUB_ENV + fi + - name: Check cross instance cache disk space + shell: bash + run: | + # if there is less than 35 GB free space then creating the cache might fail so exit early + freespace=`df -m $CACHE_DRIVE | grep -w $CACHE_DRIVE | awk '{print $4}'` + freespace_human=`df -h $CACHE_DRIVE | grep -w $CACHE_DRIVE | awk '{print $4}'` + if [ $freespace -le 35000 ]; then + echo "The cross mount cache has $freespace_human free space which is not enough - exiting" + exit 1 + else + echo "The cross mount cache has $freespace_human free space - continuing" + fi + - name: Restore gitcache + shell: bash + run: | + GIT_CACHE_TAR="$CACHE_DRIVE/gitcache.tar" + if [ ! -f "$GIT_CACHE_TAR" ]; then + echo "Git cache tar file does not exist, skipping restore" + exit 0 + fi + echo "Restoring git cache from $GIT_CACHE_TAR to $GIT_CACHE_PATH" + mkdir -p $GIT_CACHE_PATH + tar -xf $GIT_CACHE_TAR -C $GIT_CACHE_PATH + - name: Gclient Sync + shell: bash + run: | + e d gclient config \ + --name "src/electron" \ + --unmanaged \ + ${GCLIENT_EXTRA_ARGS} \ + "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY" + + if [ "$TARGET_OS" != "" ]; then + echo "target_os=['$TARGET_OS']" >> ./.gclient + fi + + ELECTRON_USE_THREE_WAY_MERGE_FOR_PATCHES=1 e d gclient sync --with_branch_heads --with_tags --nohooks -vv + - name: Compress Git Cache Directory + shell: bash + run: | + echo "Uncompressed gitcache size: $(du -sh $GIT_CACHE_PATH | cut -f1 -d' ')" + cd $GIT_CACHE_PATH + tar -cf ../gitcache.tar . + cd .. + echo "Compressed gitcache to $(du -sh gitcache.tar | cut -f1 -d' ')" + # remove the old cache file if it exists + if [ -f $CACHE_DRIVE/gitcache.tar ]; then + echo "Removing old gitcache.tar from $CACHE_DRIVE" + rm $CACHE_DRIVE/gitcache.tar + fi + cp ./gitcache.tar $CACHE_DRIVE/ + - name: Wait for active SSH sessions + shell: bash + if: always() && !cancelled() + run: | + while [ -f /var/.ssh-lock ] + do + sleep 60 + done diff --git a/.github/actions/build-image-sha/action.yml b/.github/actions/build-image-sha/action.yml new file mode 100644 index 0000000000000..dc60f2457c8cf --- /dev/null +++ b/.github/actions/build-image-sha/action.yml @@ -0,0 +1,24 @@ +name: 'Build Image SHA' +description: 'Single source of truth for the ghcr.io/electron/build image SHA' +inputs: + override: + description: 'Optional override SHA (e.g. from a workflow_dispatch input)' + required: false + default: '' +outputs: + build-image-sha: + description: 'The electron/build image SHA to use' + value: ${{ steps.set.outputs.build-image-sha }} +runs: + using: 'composite' + steps: + - id: set + shell: bash + env: + OVERRIDE: ${{ inputs.override }} + run: | + if [ -n "$OVERRIDE" ]; then + echo "build-image-sha=$OVERRIDE" >> "$GITHUB_OUTPUT" + else + echo "build-image-sha=daad061f4b99a0ae1c841be4aa09188280a9c8a4" >> "$GITHUB_OUTPUT" + fi diff --git a/.github/actions/checkout/action.yml b/.github/actions/checkout/action.yml new file mode 100644 index 0000000000000..0770c0bafce6b --- /dev/null +++ b/.github/actions/checkout/action.yml @@ -0,0 +1,227 @@ +name: 'Checkout' +description: 'Checks out Electron and stores it in the AKS Cache' +inputs: + generate-sas-token: + description: 'Whether to generate and persist a SAS token for the item in the cache' + required: false + default: 'false' + use-cache: + description: 'Whether to persist the cache to the shared drive' + required: false + default: 'true' + target-platform: + description: 'Target platform, should be linux, win, macos' +runs: + using: "composite" + steps: + - name: Set GIT_CACHE_PATH to make gclient to use the cache + shell: bash + run: | + echo "GIT_CACHE_PATH=$(pwd)/git-cache" >> $GITHUB_ENV + - name: Install Dependencies + uses: ./src/electron/.github/actions/install-dependencies + - name: Set Chromium Git Cookie + uses: ./src/electron/.github/actions/set-chromium-cookie + - name: Install Build Tools + uses: ./src/electron/.github/actions/install-build-tools + - name: Generate DEPS Hash + shell: bash + run: | + node src/electron/script/generate-deps-hash.js + DEPSHASH="v2-src-cache-$(cat src/electron/.depshash)" + echo "DEPSHASH=$DEPSHASH" >> $GITHUB_ENV + echo "CACHE_FILE=$DEPSHASH.tar" >> $GITHUB_ENV + if [ "${{ inputs.target-platform }}" = "win" ]; then + echo "CACHE_DRIVE=/mnt/win-cache" >> $GITHUB_ENV + else + echo "CACHE_DRIVE=/mnt/cross-instance-cache" >> $GITHUB_ENV + fi + - name: Generate SAS Key + if: ${{ inputs.generate-sas-token == 'true' }} + shell: bash + run: | + curl --unix-socket /var/run/sas/sas.sock --fail "http://foo/$CACHE_FILE?platform=${{ inputs.target-platform }}&getAccountName=true" > sas-token + - name: Save SAS Key + if: ${{ inputs.generate-sas-token == 'true' }} + uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 + with: + path: sas-token + key: sas-key-${{ inputs.target-platform }}-${{ github.run_number }}-${{ github.run_attempt }} + enableCrossOsArchive: true + - name: Check If Cache Exists + id: check-cache + shell: bash + run: | + if [[ "${{ inputs.use-cache }}" == "false" ]]; then + echo "Not using cache this time..." + echo "cache_exists=false" >> $GITHUB_OUTPUT + else + cache_path=$CACHE_DRIVE/$CACHE_FILE + echo "Using cache key: $DEPSHASH" + echo "Checking for cache in: $cache_path" + if [ ! -f "$cache_path" ] || [ `du $cache_path | cut -f1` = "0" ]; then + echo "cache_exists=false" >> $GITHUB_OUTPUT + echo "Cache Does Not Exist for $DEPSHASH" + else + echo "cache_exists=true" >> $GITHUB_OUTPUT + echo "Cache Already Exists for $DEPSHASH, Skipping.." + fi + fi + - name: Check cross instance cache disk space + if: steps.check-cache.outputs.cache_exists == 'false' && inputs.use-cache == 'true' + shell: bash + run: | + # if there is less than 35 GB free space then creating the cache might fail so exit early + freespace=`df -m $CACHE_DRIVE | grep -w $CACHE_DRIVE | awk '{print $4}'` + freespace_human=`df -h $CACHE_DRIVE | grep -w $CACHE_DRIVE | awk '{print $4}'` + if [ $freespace -le 35000 ]; then + echo "The cross mount cache has $freespace_human free space which is not enough - exiting" + exit 1 + else + echo "The cross mount cache has $freespace_human free space - continuing" + fi + - name: Add patch conflict problem matcher + shell: bash + run: echo "::add-matcher::src/electron/.github/problem-matchers/patch-conflict.json" + - name: Restore gitcache + if: steps.check-cache.outputs.cache_exists == 'false' + shell: bash + run: | + GIT_CACHE_TAR="$CACHE_DRIVE/gitcache.tar" + if [ ! -f "$GIT_CACHE_TAR" ]; then + echo "Git cache tar file does not exist, skipping restore" + exit 0 + fi + echo "Restoring git cache from $GIT_CACHE_TAR to $GIT_CACHE_PATH" + mkdir -p $GIT_CACHE_PATH + tar -xf $GIT_CACHE_TAR -C $GIT_CACHE_PATH + - name: Gclient Sync + if: steps.check-cache.outputs.cache_exists == 'false' + shell: bash + run: | + e d gclient config \ + --name "src/electron" \ + --unmanaged \ + ${GCLIENT_EXTRA_ARGS} \ + "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY" + + if [ "$TARGET_OS" != "" ]; then + echo "target_os=['$TARGET_OS']" >> ./.gclient + fi + + ELECTRON_DEPOT_TOOLS_WIN_TOOLCHAIN=0 DEPOT_TOOLS_WIN_TOOLCHAIN=0 ELECTRON_USE_THREE_WAY_MERGE_FOR_PATCHES=1 e d gclient sync --with_branch_heads --with_tags + if [[ "${{ inputs.is-release }}" != "true" ]]; then + # Re-export all the patches to check if there were changes. + python3 src/electron/script/export_all_patches.py src/electron/patches/config.json + cd src/electron + git update-index --refresh || true + if ! git diff-index --quiet HEAD --; then + # There are changes to the patches. Make a git commit with the updated patches + if node ./script/patch-up.js; then + echo + echo "======================================================================" + echo "Changes to the patches when applying, we have auto-pushed the diff to the current branch" + echo "A new CI job will kick off shortly" + echo "======================================================================" + exit 1 + else + git add patches + GIT_COMMITTER_NAME="PatchUp" GIT_COMMITTER_EMAIL="73610968+patchup[bot]@users.noreply.github.com" git commit -m "chore: update patches" --author="PatchUp <73610968+patchup[bot]@users.noreply.github.com>" + # Export it + mkdir -p ../../patches + git format-patch -1 --stdout --keep-subject --no-stat --full-index > ../../patches/update-patches.patch + echo + echo "======================================================================" + echo "There were changes to the patches when applying." + echo "Check the CI artifacts for a patch you can apply to fix it." + echo "======================================================================" + echo + cat ../../patches/update-patches.patch + exit 1 + fi + else + echo "No changes to patches detected" + fi + fi + - name: Remove patch conflict problem matchers + shell: bash + run: | + echo "::remove-matcher owner=merge-conflict::" + echo "::remove-matcher owner=patch-conflict::" + echo "::remove-matcher owner=patch-needs-update::" + - name: Upload patches stats + if: ${{ inputs.target-platform == 'linux' && github.ref == 'refs/heads/main' }} + shell: bash + run: | + node src/electron/script/patches-stats.mjs --upload-stats || true + # delete all .git directories under src/ except for + # third_party/angle/ and third_party/dawn/ because of build time generation of files + # gen/angle/commit.h depends on third_party/angle/.git/HEAD + # https://chromium-review.googlesource.com/c/angle/angle/+/2074924 + # and dawn/common/Version_autogen.h depends on third_party/dawn/.git/HEAD + # https://dawn-review.googlesource.com/c/dawn/+/83901 + # TODO: maybe better to always leave out */.git/HEAD file for all targets ? + - name: Delete .git directories under src to free space + if: ${{ steps.check-cache.outputs.cache_exists == 'false' && inputs.use-cache == 'true' }} + shell: bash + run: | + cd src + ( find . -type d -name ".git" -not -path "./third_party/angle/*" -not -path "./third_party/dawn/*" -not -path "./electron/*" ) | xargs rm -rf + - name: Minimize Cache Size for Upload + if: ${{ steps.check-cache.outputs.cache_exists == 'false' && inputs.use-cache == 'true' }} + shell: bash + run: | + rm -rf src/android_webview + rm -rf src/ios/chrome + rm -rf src/third_party/blink/perf_tests + rm -rf src/chrome/test/data/xr/webvr_info + rm -rf src/third_party/angle/third_party/VK-GL-CTS/src + rm -rf src/third_party/swift-toolchain + rm -rf src/third_party/swiftshader/tests/regres/testlists + cp src/electron/.github/actions/checkout/action.yml ./ + rm -rf src/electron + mkdir -p src/electron/.github/actions/checkout + mv action.yml src/electron/.github/actions/checkout + - name: Compress Src Directory + if: ${{ steps.check-cache.outputs.cache_exists == 'false' && inputs.use-cache == 'true' }} + shell: bash + run: | + echo "Uncompressed src size: $(du -sh src | cut -f1 -d' ')" + # Named .tar but zstd-compressed; the sas-sidecar's filename allowlist + # only permits .tar/.tgz so we keep the extension and decode on restore. + tar -cf - src | zstd -T0 --long=30 -f -o $CACHE_FILE + echo "Compressed src to $(du -sh $CACHE_FILE | cut -f1 -d' ')" + - name: Persist Src Cache + if: ${{ steps.check-cache.outputs.cache_exists == 'false' && inputs.use-cache == 'true' }} + shell: bash + run: | + final_cache_path=$CACHE_DRIVE/$CACHE_FILE + # Upload to a run-unique temp name first so concurrent readers never + # observe a partially-written file, and an interrupted copy can't leave + # a truncated file at the final path. Orphaned temp files get swept by + # the clean-orphaned-cache-uploads workflow. + tmp_cache_path=$final_cache_path.upload-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT} + echo "Uploading to temp path: $tmp_cache_path" + cp ./$CACHE_FILE $tmp_cache_path + + echo "Using cache key: $DEPSHASH" + if [ -f "$final_cache_path" ]; then + echo "Cache already persisted at $final_cache_path by a concurrent run; discarding ours" + rm -f $tmp_cache_path + else + mv -f $tmp_cache_path $final_cache_path + echo "Cache key persisted in $final_cache_path" + fi + + if [ ! -f "$final_cache_path" ]; then + echo "Cache key not found" + exit 1 + fi + - name: Wait for active SSH sessions + shell: bash + if: always() && !cancelled() + run: | + while [ -f /var/.ssh-lock ] + do + sleep 60 + done diff --git a/.github/actions/cipd-install/action.yml b/.github/actions/cipd-install/action.yml new file mode 100644 index 0000000000000..ceec0eaeb13e2 --- /dev/null +++ b/.github/actions/cipd-install/action.yml @@ -0,0 +1,71 @@ +name: 'CIPD install' +description: 'Installs the specified CIPD package' +inputs: + cipd-root-prefix-path: + description: 'Path to prepend to installation directory' + default: '' + dependency: + description: 'Name of dependency to install' + deps-file: + description: 'Location of DEPS file that defines the dependency' + installation-dir: + description: 'Location to install dependency' + target-platform: + description: 'Target platform, should be linux, win, macos' + package: + description: 'Package to install' + dependency-version: + description: 'Version of the dependency to install' + default: '' +runs: + using: "composite" + steps: + - name: Delete wrong ${{ inputs.dependency }} + shell: bash + env: + CIPD_ROOT_PREFIX: ${{ inputs.cipd-root-prefix-path }} + INSTALLATION_DIR: ${{ inputs.installation-dir }} + run : | + rm -rf "${CIPD_ROOT_PREFIX}${INSTALLATION_DIR}" + - name: Create ensure file for ${{ inputs.dependency }} + if: ${{ inputs.dependency-version == '' }} + shell: bash + env: + PACKAGE: ${{ inputs.package }} + DEPS_FILE: ${{ inputs.deps-file }} + INSTALLATION_DIR: ${{ inputs.installation-dir }} + DEPENDENCY: ${{ inputs.dependency }} + run: | + echo "$PACKAGE" $(e d gclient getdep --deps-file="$DEPS_FILE" -r "${INSTALLATION_DIR}:${PACKAGE}") > "${DEPENDENCY}_ensure_file" + cat "${DEPENDENCY}_ensure_file" + + - name: Create ensure file for ${{ inputs.dependency }} from dependency-version + if: ${{ inputs.dependency-version != '' }} + shell: bash + env: + PACKAGE: ${{ inputs.package }} + DEPENDENCY_VERSION: ${{ inputs.dependency-version }} + DEPENDENCY: ${{ inputs.dependency }} + run: | + echo "$PACKAGE $DEPENDENCY_VERSION" > "${DEPENDENCY}_ensure_file" + cat "${DEPENDENCY}_ensure_file" + - name: CIPD installation of ${{ inputs.dependency }} (macOS) + if: ${{ inputs.target-platform != 'win' }} + shell: bash + env: + CIPD_ROOT_PREFIX: ${{ inputs.cipd-root-prefix-path }} + INSTALLATION_DIR: ${{ inputs.installation-dir }} + DEPENDENCY: ${{ inputs.dependency }} + run: | + echo "ensuring $DEPENDENCY" + e d cipd ensure --root "${CIPD_ROOT_PREFIX}${INSTALLATION_DIR}" -ensure-file "${DEPENDENCY}_ensure_file" + - name: CIPD installation of ${{ inputs.dependency }} (Windows) + if: ${{ inputs.target-platform == 'win' }} + shell: powershell + env: + CIPD_ROOT_PREFIX: ${{ inputs.cipd-root-prefix-path }} + INSTALLATION_DIR: ${{ inputs.installation-dir }} + DEPENDENCY: ${{ inputs.dependency }} + run: | + echo "ensuring $env:DEPENDENCY on Windows" + e d cipd ensure --root "$env:CIPD_ROOT_PREFIX$env:INSTALLATION_DIR" -ensure-file "$($env:DEPENDENCY)_ensure_file" diff --git a/.github/actions/fix-sync/action.yml b/.github/actions/fix-sync/action.yml new file mode 100644 index 0000000000000..b5d7f2949b7a9 --- /dev/null +++ b/.github/actions/fix-sync/action.yml @@ -0,0 +1,155 @@ +name: 'Fix Sync' +description: 'Ensures proper binaries are in place' +# This action is required to correct for differences between "gclient sync" +# on Linux and the expected state on macOS/windows. This requires: +# 1. Fixing Clang Install (wrong binary) +# 2. Fixing esbuild (wrong binary) +# 3. Fixing rustc (wrong binary) +# 4. Fixing gn (wrong binary) +# 5. Fix reclient (wrong binary) +# 6. Fixing dsymutil (wrong binary) +# 7. Ensuring we are using the correct ninja and adding it to PATH +# 8. Fixing angle (wrong remote) +# 9. Install windows toolchain on Windows +# 10. Fix node binary on Windows +# 11. Fix rc binary on Windows +inputs: + target-platform: + description: 'Target platform, should be linux, win, macos' +runs: + using: "composite" + steps: + - name: Fix llvm toolchain + if: ${{ inputs.target-platform != 'linux' }} + shell: bash + run : | + rm -rf src/third_party/llvm-build + python3 src/tools/clang/scripts/update.py + # Refs https://chromium-review.googlesource.com/c/chromium/src/+/6667681 + python3 src/tools/clang/scripts/update.py --package objdump + python3 src/tools/clang/scripts/update.py --package clang-tidy + - name: Fix esbuild + if: ${{ inputs.target-platform != 'linux' }} + uses: ./src/electron/.github/actions/cipd-install + with: + cipd-root-prefix-path: src/third_party/devtools-frontend/src/ + dependency: esbuild + deps-file: src/third_party/devtools-frontend/src/DEPS + installation-dir: third_party/esbuild + target-platform: ${{ inputs.target-platform }} + package: infra/3pp/tools/esbuild/${platform} + - name: Fix rollup + if: ${{ inputs.target-platform != 'linux' }} + uses: ./src/electron/.github/actions/cipd-install + with: + cipd-root-prefix-path: src/third_party/devtools-frontend/src/ + dependency: rollup_libs + deps-file: src/third_party/devtools-frontend/src/DEPS + installation-dir: third_party/rollup_libs + target-platform: ${{ inputs.target-platform }} + package: infra/3pp/tools/rollup_libs/${platform} + - name: Sync native rollup libs + if: ${{ inputs.target-platform != 'linux' }} + shell: bash + run : | + cd src/third_party/devtools-frontend/src + python3 scripts/deps/sync_rollup_libs.py + - name: Fix rustc + if: ${{ inputs.target-platform != 'linux' }} + shell: bash + run : | + rm -rf src/third_party/rust-toolchain + python3 src/tools/rust/update_rust.py + - name: Fix gn (macOS) + if: ${{ inputs.target-platform == 'macos' }} + uses: ./src/electron/.github/actions/cipd-install + with: + dependency: gn + deps-file: src/DEPS + installation-dir: src/buildtools/mac + target-platform: ${{ inputs.target-platform }} + package: gn/gn/mac-${arch} + - name: Fix gn (Windows) + if: ${{ inputs.target-platform == 'win' }} + uses: ./src/electron/.github/actions/cipd-install + with: + dependency: gn + deps-file: src/DEPS + installation-dir: src/buildtools/win + target-platform: ${{ inputs.target-platform }} + package: gn/gn/windows-amd64 + - name: Fix reclient + if: ${{ inputs.target-platform != 'linux' }} + uses: ./src/electron/.github/actions/cipd-install + with: + dependency: reclient + deps-file: src/DEPS + installation-dir: src/buildtools/reclient + target-platform: ${{ inputs.target-platform }} + package: infra/rbe/client/${platform} + - name: Configure reclient configs + if: ${{ inputs.target-platform != 'linux' }} + shell: bash + run : | + python3 src/buildtools/reclient_cfgs/configure_reclient_cfgs.py --rbe_instance "projects/rbe-chrome-untrusted/instances/default_instance" --reproxy_cfg_template reproxy.cfg.template --rewrapper_cfg_project "" --skip_remoteexec_cfg_fetch + - name: Fix dsymutil (macOS) + if: ${{ inputs.target-platform == 'macos' }} + shell: bash + run : | + # Fix dsymutil + if [ "${{ inputs.target-platform }}" = "macos" ]; then + if [ "${{ env.TARGET_ARCH }}" == "arm64" ]; then + DSYM_SHA_FILE=src/tools/clang/dsymutil/bin/dsymutil.arm64.sha1 + else + DSYM_SHA_FILE=src/tools/clang/dsymutil/bin/dsymutil.x64.sha1 + fi + python3 src/third_party/depot_tools/download_from_google_storage.py --no_resume --no_auth --bucket chromium-browser-clang -s $DSYM_SHA_FILE -o src/tools/clang/dsymutil/bin/dsymutil + fi + - name: Fix ninja + if: ${{ inputs.target-platform != 'linux' }} + uses: ./src/electron/.github/actions/cipd-install + with: + dependency: ninja + deps-file: src/DEPS + installation-dir: src/third_party/ninja + target-platform: ${{ inputs.target-platform }} + package: infra/3pp/tools/ninja/${platform} + - name: Set ninja in path + if: ${{ inputs.target-platform != 'linux' }} + shell: bash + run : | + echo "$(pwd)/src/third_party/ninja" >> $GITHUB_PATH + - name: Fix siso + uses: ./src/electron/.github/actions/cipd-install + with: + dependency: siso + deps-file: src/DEPS + installation-dir: src/third_party/siso/cipd + target-platform: ${{ inputs.target-platform }} + package: build/siso/${platform} + - name: Fixup angle git + if: ${{ inputs.target-platform != 'linux' }} + shell: bash + run : | + cd src/third_party/angle + rm -f .git/objects/info/alternates + git remote set-url origin https://github.com/google/angle.git + cp .git/config .git/config.backup + git remote remove origin + mv .git/config.backup .git/config + git fetch + - name: Get Windows toolchain + if: ${{ inputs.target-platform == 'win' }} + shell: powershell + run: e d vpython3 src\build\vs_toolchain.py update --force + - name: Download nodejs + if: ${{ inputs.target-platform == 'win' }} + shell: powershell + run: | + $nodedeps = e d gclient getdep --deps-file=src/DEPS -r src/third_party/node/win | ConvertFrom-JSON + python3 src\third_party\depot_tools\download_from_google_storage.py --no_resume --no_auth --bucket chromium-nodejs -o src\third_party\node\win\node.exe $nodedeps.object_name + - name: Install rc + if: ${{ inputs.target-platform == 'win' }} + shell: bash + run: | + python3 src/third_party/depot_tools/download_from_google_storage.py --no_resume --no_auth --bucket chromium-browser-clang/rc -s src/build/toolchain/win/rc/win/rc.exe.sha1 diff --git a/.github/actions/free-space-macos/action.yml b/.github/actions/free-space-macos/action.yml new file mode 100644 index 0000000000000..11ca7633a9ae8 --- /dev/null +++ b/.github/actions/free-space-macos/action.yml @@ -0,0 +1,91 @@ +name: 'Free Space macOS' +description: 'Checks out Electron and stores it in the AKS Cache' +runs: + using: "composite" + steps: + - name: Free Space on MacOS + shell: bash + run: | + echo "Disk usage before cleanup:" + df -h + sudo mkdir -p $TMPDIR/del-target + + tmpify() { + if [ -d "$1" ]; then + sudo mv "$1" $TMPDIR/del-target/$(echo $1|shasum -a 256|head -n1|cut -d " " -f1) + fi + } + + strip_universal_deep() { + if [ -d "$1" ]; then + opwd=$(pwd) + cd $1 + f=$(find . -perm +111 -type f) + for fp in $f + do + if [[ $(file "$fp") == *"universal binary"* ]]; then + if [ "`arch`" == "arm64" ]; then + if [[ $(file "$fp") == *"x86_64"* ]]; then + sudo lipo -remove x86_64 "$fp" -o "$fp" || true + fi + else + if [[ $(file "$fp") == *"arm64e)"* ]]; then + sudo lipo -remove arm64e "$fp" -o "$fp" || true + fi + if [[ $(file "$fp") == *"arm64)"* ]]; then + sudo lipo -remove arm64 "$fp" -o "$fp" || true + fi + fi + fi + done + + cd $opwd + fi + } + + tmpify /Library/Developer/CoreSimulator + tmpify ~/Library/Developer/CoreSimulator + tmpify $(xcode-select -p)/Platforms/AppleTVOS.platform + tmpify $(xcode-select -p)/Platforms/iPhoneOS.platform + tmpify $(xcode-select -p)/Platforms/WatchOS.platform + tmpify $(xcode-select -p)/Platforms/WatchSimulator.platform + tmpify $(xcode-select -p)/Platforms/AppleTVSimulator.platform + tmpify $(xcode-select -p)/Platforms/iPhoneSimulator.platform + tmpify $(xcode-select -p)/Toolchains/XcodeDefault.xctoolchain/usr/metal/ios + tmpify $(xcode-select -p)/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift + tmpify $(xcode-select -p)/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift-5.0 + tmpify ~/.rubies + tmpify ~/Library/Caches/Homebrew + tmpify /usr/local/Homebrew + + sudo rm -rf $TMPDIR/del-target + + sudo rm -rf /Applications/Safari.app + sudo rm -rf /Applications/Xcode_16.1.app + sudo rm -rf /Applications/Xcode_16.2.app + sudo rm -rf /Applications/Xcode_16.3.app + sudo rm -rf /Applications/Xcode_26* + sudo rm -rf /Applications/Google Chrome.app + sudo rm -rf /Applications/Google Chrome for Testing.app + sudo rm -rf /Applications/Firefox.app + sudo rm -rf /Applications/Microsoft Edge.app + sudo rm -rf ~/project/src/third_party/catapult/tracing/test_data + sudo rm -rf ~/project/src/third_party/angle/third_party/VK-GL-CTS + sudo rm -rf /Users/runner/Library/Android + sudo rm -rf $JAVA_HOME_11_arm64 + sudo rm -rf $JAVA_HOME_17_arm64 + sudo rm -rf $JAVA_HOME_21_arm64 + sudo rm -rf $JAVA_HOME_25_arm64 + sudo rm -rf /Users/runner/.dotnet/ + sudo rm -rf /Users/runner/.rustup + + # remove homebrew packages we don't need + if command -v brew &> /dev/null; then + brew uninstall -f --zap aws-sam-cli session-manager-plugin gcc gcc@13 gcc@14 llvm@18 gradle maven ant azure-cli + brew autoremove + fi + + # lipo off some huge binaries arm64 versions to save space + strip_universal_deep $(xcode-select -p)/../SharedFrameworks + # strip_arm_deep /System/Volumes/Data/Library/Developer/CommandLineTools/usr + sudo mdutil -a -i off diff --git a/.github/actions/generate-types/action.yml b/.github/actions/generate-types/action.yml new file mode 100644 index 0000000000000..822cc25df6f8a --- /dev/null +++ b/.github/actions/generate-types/action.yml @@ -0,0 +1,28 @@ +name: 'Generate Types for Archaeologist Dig' +description: 'Generate Types for Archaeologist Dig' +inputs: + sha-file: + description: 'File containing sha' + required: true + filename: + description: 'Filename to write types to' + required: true +runs: + using: "composite" + steps: + - name: Generating Types for SHA in ${{ inputs.sha-file }} + shell: bash + run: | + export ELECTRON_DIR=$(pwd) + if [ "${{ inputs.sha-file }}" == ".dig-old" ]; then + cd /tmp + git clone https://github.com/electron/electron.git + cd electron + fi + git checkout $(cat $ELECTRON_DIR/${{ inputs.sha-file }}) + node script/yarn.js install --immutable + echo "#!/usr/bin/env node\nglobal.x=1" > node_modules/typescript/bin/tsc + node node_modules/.bin/electron-docs-parser --dir=./ --outDir=./ --moduleVersion=0.0.0-development + node node_modules/.bin/electron-typescript-definitions --api=electron-api.json --outDir=artifacts + mv artifacts/electron.d.ts $ELECTRON_DIR/artifacts/${{ inputs.filename }} + working-directory: ./electron diff --git a/.github/actions/install-build-tools/action.yml b/.github/actions/install-build-tools/action.yml new file mode 100644 index 0000000000000..6e701c2e3166b --- /dev/null +++ b/.github/actions/install-build-tools/action.yml @@ -0,0 +1,32 @@ +name: 'Install Build Tools' +description: 'Installs an exact SHA of build tools' +runs: + using: "composite" + steps: + - name: Install Build Tools + shell: bash + run: | + if [ "$(expr substr $(uname -s) 1 10)" == "MSYS_NT-10" ]; then + git config --global core.filemode false + git config --global core.autocrlf false + git config --global branch.autosetuprebase always + git config --global core.fscache true + git config --global core.longpaths true + git config --global core.preloadindex true + git config --global core.longpaths true + fi + export BUILD_TOOLS_SHA=1b7bd25dae4a780bb3170fff56c9327b53aaf7eb + npm i -g @electron/build-tools + # Update depot_tools to ensure python + e d update_depot_tools + e auto-update disable + # Disable further updates of depot_tools + e d auto-update disable + if [ "$(expr substr $(uname -s) 1 10)" == "MSYS_NT-10" ]; then + e d cipd.bat --version + cp "C:\Python311\python.exe" "C:\Python311\python3.exe" + echo "C:\Users\ContainerAdministrator\.electron_build_tools\third_party\depot_tools" >> $GITHUB_PATH + else + echo "$HOME/.electron_build_tools/third_party/depot_tools" >> $GITHUB_PATH + echo "$HOME/.electron_build_tools/third_party/depot_tools/python-bin" >> $GITHUB_PATH + fi diff --git a/.github/actions/install-dependencies/action.yml b/.github/actions/install-dependencies/action.yml new file mode 100644 index 0000000000000..d034b7f587edc --- /dev/null +++ b/.github/actions/install-dependencies/action.yml @@ -0,0 +1,48 @@ +name: 'Install Dependencies' +description: 'Installs yarn depdencies using cache when available' +runs: + using: "composite" + steps: + - name: Get yarn cache directory path + shell: bash + id: yarn-cache-dir-path + run: echo "dir=$(node src/electron/script/yarn.js config get cacheFolder)" >> $GITHUB_OUTPUT + - uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 + id: yarn-cache + with: + path: ${{ steps.yarn-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('src/electron/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + - name: Install Dependencies + shell: bash + run: | + cd src/electron + if [ "$TARGET_ARCH" = "x86" ]; then + export npm_config_arch="ia32" + fi + ARCH=$(uname -m) + node script/yarn.js install --immutable --mode=skip-build + # if running on linux arm skip yarn Builds + if [ "$ARCH" = "armv7l" ]; then + echo "Skipping yarn build on linux arm" + else + # Pre-seed the node-gyp header cache so the parallel native-addon + # builds below don't race on a cold cache. Linux build containers + # already ship a warm cache (electron/build-images#68), so only do + # this on macOS / Windows runners. + if [ "$(uname -s)" != "Linux" ]; then + for i in 1 2 3; do + if node node_modules/node-gyp/bin/node-gyp.js install; then + break + fi + if [ "$i" = "3" ]; then + echo "node-gyp header pre-seed failed after 3 attempts" >&2 + exit 1 + fi + echo "node-gyp header pre-seed failed (attempt $i), retrying in 5s..." >&2 + sleep 5 + done + fi + node script/yarn.js install --immutable + fi diff --git a/.github/actions/restore-cache-aks/action.yml b/.github/actions/restore-cache-aks/action.yml new file mode 100644 index 0000000000000..25221932740bd --- /dev/null +++ b/.github/actions/restore-cache-aks/action.yml @@ -0,0 +1,49 @@ +name: 'Restore Cache AKS' +description: 'Restores Electron src cache via AKS' +inputs: + target-platform: + description: 'Target platform, should be linux, win, macos' +runs: + using: "composite" + steps: + - name: Restore and Ensure Src Cache + shell: bash + run: | + if [ "${{ inputs.target-platform }}" = "win" ]; then + cache_path=/mnt/win-cache/$DEPSHASH.tar + else + cache_path=/mnt/cross-instance-cache/$DEPSHASH.tar + fi + + echo "Using cache key: $DEPSHASH" + echo "Checking for cache in: $cache_path" + if [ ! -f "$cache_path" ]; then + echo "Cache Does Not Exist for $DEPSHASH - exiting" + exit 1 + else + echo "Found Cache for $DEPSHASH at $cache_path" + fi + + echo "Persisted cache is $(du -sh $cache_path | cut -f1)" + if [ `du $cache_path | cut -f1` = "0" ]; then + echo "Cache is empty - exiting" + exit 1 + fi + + mkdir temp-cache + zstd -d --long=30 -c $cache_path | tar -xf - -C temp-cache + echo "Unzipped cache is $(du -sh temp-cache/src | cut -f1)" + + if [ -d "temp-cache/src" ]; then + echo "Relocating Cache" + rm -rf src + mv temp-cache/src src + fi + + if [ ! -d "src/third_party/blink" ]; then + echo "Cache was not correctly restored - exiting" + exit 1 + fi + + echo "Wiping Electron Directory" + rm -rf src/electron diff --git a/.github/actions/restore-cache-azcopy/action.yml b/.github/actions/restore-cache-azcopy/action.yml new file mode 100644 index 0000000000000..7099ea8fda381 --- /dev/null +++ b/.github/actions/restore-cache-azcopy/action.yml @@ -0,0 +1,120 @@ +name: 'Restore Cache AZCopy' +description: 'Restores Electron src cache via AZCopy' +inputs: + target-platform: + description: 'Target platform, should be linux, win, macos' +runs: + using: "composite" + steps: + - name: Obtain SAS Key + continue-on-error: true + uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 + with: + path: sas-token + key: sas-key-${{ inputs.target-platform }}-${{ github.run_number }}-1 + enableCrossOsArchive: true + - name: Obtain SAS Key + continue-on-error: true + uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 + with: + path: sas-token + key: sas-key-${{ inputs.target-platform }}-${{ github.run_number }}-${{ github.run_attempt }} + enableCrossOsArchive: true + - name: Download Src Cache from AKS + # The cache will always exist here as a result of the checkout job + # Either it was uploaded to Azure in the checkout job for this commit + # or it was uploaded in the checkout job for a previous commit. + uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0 + with: + timeout_minutes: 30 + max_attempts: 3 + retry_on: error + shell: bash + command: | + sas_token=$(cat sas-token) + if [ -z "$sas_token" ]; then + echo "SAS Token not found; exiting src cache download early..." + exit 1 + else + sas_token=$(jq -r '.sasToken' sas-token) + account_name=$(jq -r '.accountName' sas-token) + if [ "${{ inputs.target-platform }}" = "win" ]; then + azcopy copy --log-level=ERROR \ + "https://$account_name.file.core.windows.net/${{ env.AZURE_AKS_WIN_CACHE_SHARE_NAME }}/${{ env.CACHE_PATH }}?$sas_token" $DEPSHASH.tar + else + azcopy copy --log-level=ERROR \ + "https://$account_name.file.core.windows.net/${{ env.AZURE_AKS_CACHE_SHARE_NAME }}/${{ env.CACHE_PATH }}?$sas_token" $DEPSHASH.tar + fi + fi + env: + AZURE_AKS_CACHE_SHARE_NAME: linux-cache + AZURE_AKS_WIN_CACHE_SHARE_NAME: windows-cache + - name: Clean SAS Key + shell: bash + run: rm -f sas-token + - name: Unzip and Ensure Src Cache + if: ${{ inputs.target-platform == 'macos' }} + shell: bash + run: | + echo "Downloaded cache is $(du -sh $DEPSHASH.tar | cut -f1)" + if [ `du $DEPSHASH.tar | cut -f1` = "0" ]; then + echo "Cache is empty - exiting" + exit 1 + fi + + mkdir temp-cache + zstd -d --long=30 -c $DEPSHASH.tar | tar -xf - -C temp-cache + echo "Unzipped cache is $(du -sh temp-cache/src | cut -f1)" + + if [ -d "temp-cache/src" ]; then + echo "Relocating Cache" + rm -rf src + mv temp-cache/src src + + echo "Deleting zip file" + rm -rf $DEPSHASH.tar + fi + + if [ ! -d "src/third_party/blink" ]; then + echo "Cache was not correctly restored - exiting" + exit 1 + fi + + echo "Wiping Electron Directory" + rm -rf src/electron + + - name: Unzip and Ensure Src Cache (Windows) + if: ${{ inputs.target-platform == 'win' }} + shell: bash + run: | + echo "Downloaded cache is $(du -sh $DEPSHASH.tar | cut -f1)" + if [ `du $DEPSHASH.tar | cut -f1` = "0" ]; then + echo "Cache is empty - exiting" + exit 1 + fi + + mkdir temp-cache + zstd -d --long=30 -c $DEPSHASH.tar | tar -xf - -C temp-cache + rm -f $DEPSHASH.tar + + - name: Move Src Cache (Windows) + if: ${{ inputs.target-platform == 'win' }} + uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0 + with: + timeout_minutes: 30 + max_attempts: 3 + retry_on: error + shell: powershell + command: | + if (Test-Path "temp-cache\src") { + Write-Host "Relocating Cache" + Remove-Item -Recurse -Force src + Move-Item temp-cache\src src + } + if (-Not (Test-Path "src\third_party\blink")) { + Write-Host "Cache was not correctly restored - exiting" + exit 1 + } + + Write-Host "Wiping Electron Directory" + Remove-Item -Recurse -Force src\electron diff --git a/.github/actions/set-chromium-cookie/action.yml b/.github/actions/set-chromium-cookie/action.yml new file mode 100644 index 0000000000000..cb4c145b7d494 --- /dev/null +++ b/.github/actions/set-chromium-cookie/action.yml @@ -0,0 +1,56 @@ +name: 'Set Chromium Git Cookie' +description: 'Sets an authenticated cookie from Chromium to allow for a higher request limit' +runs: + using: "composite" + steps: + - name: Set the git cookie from chromium.googlesource.com (Unix) + if: ${{ runner.os != 'Windows' }} + shell: bash + run: | + if [[ -z "$CHROMIUM_GIT_COOKIE" ]]; then + echo "CHROMIUM_GIT_COOKIE is not set - cannot authenticate." + exit 0 + fi + + eval 'set +o history' 2>/dev/null || setopt HIST_IGNORE_SPACE 2>/dev/null + touch ~/.gitcookies + chmod 0600 ~/.gitcookies + + git config --global http.cookiefile ~/.gitcookies + + echo "$CHROMIUM_GIT_COOKIE" | tr , \\t >>~/.gitcookies + eval 'set -o history' 2>/dev/null || unsetopt HIST_IGNORE_SPACE 2>/dev/null + + RESPONSE=$(curl -s -b ~/.gitcookies https://chromium-review.googlesource.com/a/accounts/self) + if [[ $RESPONSE == ")]}'"* ]]; then + # Extract account email for verification + EMAIL=$(echo "$RESPONSE" | tail -c +5 | jq -r '.email // "No email found"') + echo "Cookie authentication successful - authenticated as: $EMAIL" + else + echo "Cookie authentication failed - ensure CHROMIUM_GIT_COOKIE is set correctly" + echo $RESPONSE + fi + - name: Set the git cookie from chromium.googlesource.com (Windows) + if: ${{ runner.os == 'Windows' }} + shell: cmd + run: | + if "%CHROMIUM_GIT_COOKIE_WINDOWS_STRING%"=="" ( + echo CHROMIUM_GIT_COOKIE_WINDOWS_STRING is not set - cannot authenticate. + exit /b 0 + ) + + git config --global http.cookiefile "%USERPROFILE%\.gitcookies" + powershell -noprofile -nologo -command Write-Output $env:CHROMIUM_GIT_COOKIE_WINDOWS_STRING >>"%USERPROFILE%\.gitcookies" + + curl -s -b "%USERPROFILE%\.gitcookies" https://chromium-review.googlesource.com/a/accounts/self > response.txt + + findstr /B /C:")]}'" response.txt > nul + if %ERRORLEVEL% EQU 0 ( + echo Cookie authentication successful + powershell -NoProfile -Command "& {$content = Get-Content -Raw response.txt; $content = $content.Substring(4); try { $json = ConvertFrom-Json $content; if($json.email) { Write-Host 'Authenticated as:' $json.email } else { Write-Host 'No email found in response' } } catch { Write-Host 'Error parsing JSON:' $_ }}" + ) else ( + echo Cookie authentication failed - ensure CHROMIUM_GIT_COOKIE_WINDOWS_STRING is set correctly + type response.txt + ) + + del response.txt diff --git a/.github/actions/ssh-debug/action.yml b/.github/actions/ssh-debug/action.yml new file mode 100644 index 0000000000000..a8ed77e6c2649 --- /dev/null +++ b/.github/actions/ssh-debug/action.yml @@ -0,0 +1,20 @@ +name: Debug via SSH +description: Setup a SSH server with a tunnel to access it to debug via SSH. +inputs: + tunnel: + description: 'Enable SSH tunneling via cloudflared' + required: true + default: 'false' + timeout: + description: 'SSH session timeout in seconds' + required: false + type: number + default: 3600 +runs: + using: composite + steps: + - run: $GITHUB_ACTION_PATH/setup-ssh.sh + shell: bash + env: + TUNNEL: ${{ inputs.tunnel }} + TIMEOUT: ${{ inputs.timeout }} diff --git a/.github/actions/ssh-debug/bashrc b/.github/actions/ssh-debug/bashrc new file mode 100644 index 0000000000000..52ecb9592040f --- /dev/null +++ b/.github/actions/ssh-debug/bashrc @@ -0,0 +1,4 @@ +# If we're in an interactive SSH session and we're not already in tmux and there's no explicit SSH command, auto attach tmux +if [ -n "$SSH_TTY" ] && [ -z "$TMUX" ] && [ -z "$SSH_ORIGINAL_COMMAND" ]; then + exec tmux attach || exec tmux +fi diff --git a/.github/actions/ssh-debug/setup-ssh.sh b/.github/actions/ssh-debug/setup-ssh.sh new file mode 100755 index 0000000000000..13e11f4541144 --- /dev/null +++ b/.github/actions/ssh-debug/setup-ssh.sh @@ -0,0 +1,146 @@ +#!/bin/bash -e + +if [ "${TUNNEL}" != "true" ]; then + echo "SSH tunneling is disabled. Set enable-tunnel: true to enable remote access." + echo "Local SSH server would be available on localhost:2222 if this were a local environment." + exit 0 +fi + +echo ::group::Configuring Tunnel + +echo "SSH tunneling enabled. Setting up remote access..." + +EXTERNAL_DEPS="curl jq ssh-keygen" + +for dep in $EXTERNAL_DEPS; do + if ! command -v "${dep}" > /dev/null 2>&1; then + echo "Command ${dep} not installed on the system!" >&2 + exit 1 + fi +done + +cd "$GITHUB_ACTION_PATH" + +bashrc_path=$(pwd)/bashrc + +# Source `bashrc` to auto start tmux on SSH login. +if ! grep -q "${bashrc_path}" ~/.bash_profile; then + echo >> ~/.bash_profile # On macOS runner there's no newline at the end of the file + echo "source \"${bashrc_path}\"" >> ~/.bash_profile +fi + +OS=$(uname -s | tr '[:upper:]' '[:lower:]') +ARCH=$(uname -m) + +if [ "${ARCH}" = "x86_64" ]; then + ARCH="amd64" +elif [ "${ARCH}" = "aarch64" ]; then + ARCH="arm64" +fi + +if [ "${OS}" = "darwin" ] && ! command -v tmux > /dev/null 2>&1; then + echo "Installing tmux..." + brew install tmux +fi + +if [ "$OS" = "darwin" ]; then + cloudflared_url="https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-${OS}-${ARCH}.tgz" + echo "Downloading \`cloudflared\` from <$cloudflared_url>..." + curl --location --silent --output cloudflared.tgz "${cloudflared_url}" + tar xf cloudflared.tgz + rm cloudflared.tgz +fi + +chmod +x cloudflared + +echo 'Creating SSH server key...' +ssh-keygen -q -f ssh_host_rsa_key -N '' + +echo 'Creating SSH server config...' +sed "s,\$PWD,${PWD},;s,\$USER,${USER}," sshd_config.template > sshd_config + +echo 'Starting SSH server...' +sudo /usr/sbin/sshd -f sshd_config -D & +sshd_pid=$! + +echo "SSH server started successfully (PID: ${sshd_pid})" + +echo 'Starting tmux session...' +(cd "${GITHUB_WORKSPACE}" && tmux new-session -d -s debug) + +mkdir ~/.cloudflared +CLEAN_TUNNEL_CERT=$(printf '%s\n' "${CLOUDFLARE_TUNNEL_CERT}" | tr -d '\r' | sed '/^[[:space:]]*$/d') + +echo "${CLEAN_TUNNEL_CERT}" > ~/.cloudflared/cert.pem + +CLEAN_USER_CA_CERT=$(printf '%s\n' "${CLOUDFLARE_USER_CA_CERT}" | tr -d '\r' | sed '/^[[:space:]]*$/d') + +echo "${CLEAN_USER_CA_CERT}" | sudo tee /etc/ssh/ca.pub > /dev/null +sudo chmod 644 /etc/ssh/ca.pub + +random_suffix=$(openssl rand -hex 5 | cut -c1-10) +tunnel_name="${GITHUB_SHA}-${GITHUB_RUN_ID}-${random_suffix}" +tunnel_url="${tunnel_name}.${CLOUDFLARE_TUNNEL_HOSTNAME}" + +if ./cloudflared tunnel list | grep -q "${tunnel_name}"; then + echo "Deleting existing tunnel: ${tunnel_name}" + ./cloudflared tunnel delete ${tunnel_name} +fi + +echo "Creating new cloudflare tunnel: ${tunnel_name}" +./cloudflared tunnel create ${tunnel_name} + +credentials_file=$(find ~/.cloudflared -name "*.json" | head -n 1) +if [ -z "${credentials_file}" ]; then + echo "Error: Could not find tunnel credentials file" + exit 1 +fi + +echo "Found credentials file: ${credentials_file}" + +echo 'Creating tunnel configuration...' +cat > tunnel_config.yml << EOF +tunnel: ${tunnel_name} +credentials-file: ${credentials_file} + +ingress: + - hostname: ${tunnel_url} + service: ssh://localhost:2222 + - service: http_status:404 +EOF + +echo 'Setting up DNS routing for tunnel...' +./cloudflared tunnel route dns ${tunnel_name} ${tunnel_url} + +echo 'Running cloudflare tunnel...' +./cloudflared tunnel --no-autoupdate --config tunnel_config.yml run 2>&1 | tee cloudflared.log | sed -u 's/^/cloudflared: /' & +cloudflared_pid=$! + +echo ::endgroup:: + +echo ::notice title=SSH Debug Session Ready::ssh ${tunnel_url} + + +( + echo ' ' + echo ' ' + echo '🔗 SSH Debug Session Ready!' + echo '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━' + echo ' ' + echo '📋 Infra WG can copy and run this command to connect:' + echo ' ' + echo "ssh ${tunnel_url}" + echo ' ' + echo "⏰ Session expires automatically in ${TIMEOUT} seconds" + echo '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━' + echo ' ' + echo ' ' +) | cat + +echo ::group::Starting Background Session +echo 'Starting SSH session in background...' +./ssh-session.sh "${sshd_pid}" "${cloudflared_pid}" "${TIMEOUT}" "${tunnel_name}" & + +echo 'SSH session is running in background. GitHub Action will continue.' +echo 'Session will auto-cleanup after timeout or when processes end.' +echo ::endgroup:: diff --git a/.github/actions/ssh-debug/ssh-session.sh b/.github/actions/ssh-debug/ssh-session.sh new file mode 100755 index 0000000000000..27dfd16b62c4c --- /dev/null +++ b/.github/actions/ssh-debug/ssh-session.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +SSHD_PID=$1 +CLOUDFLARED_PID=$2 +SESSION_TIMEOUT=${3:-10000} +TUNNEL_NAME=$4 + +cleanup() { + # Kill processes. + for pid in "$SLEEP_PID" "$SSHD_PID" "$CLOUDFLARED_PID"; do + if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then + kill "$pid" 2>/dev/null || true + fi + done + + # Clean up tunnel. + if [ -n "$TUNNEL_NAME" ]; then + cd "$GITHUB_ACTION_PATH" + ./cloudflared tunnel delete "$TUNNEL_NAME" 2>/dev/null || { + echo "Failed to delete tunnel" + } + fi + + echo "Session ended at $(date)" + exit 0 +} + +# Trap signals to ensure cleanup. +trap cleanup SIGTERM SIGINT SIGQUIT SIGHUP EXIT + +# Wait for timeout or until processes die. +sleep "$SESSION_TIMEOUT" & +SLEEP_PID=$! + +# Monitor processes +while kill -0 "$SLEEP_PID" 2>/dev/null; do + # Check SSH daemon. + if ! kill -0 "$SSHD_PID" 2>/dev/null; then + echo "SSH daemon died at $(date)" + break + fi + + # Check cloudflared, + if ! kill -0 "$CLOUDFLARED_PID" 2>/dev/null; then + echo "Cloudflared died at $(date)" + break + fi + + sleep 10 +done + +cleanup diff --git a/.github/actions/ssh-debug/sshd_config.template b/.github/actions/ssh-debug/sshd_config.template new file mode 100644 index 0000000000000..7bc8934b94f3e --- /dev/null +++ b/.github/actions/ssh-debug/sshd_config.template @@ -0,0 +1,25 @@ +Port 2222 +HostKey $PWD/ssh_host_rsa_key +PidFile $PWD/sshd.pid + +# Connection settings +ClientAliveInterval 30 +ClientAliveCountMax 10 +MaxStartups 10 +LoginGraceTime 120 + +# Allow TCP forwarding for tunneling +AllowTcpForwarding yes + +# Try to prevent timeouts +TCPKeepAlive yes + +# Security +TrustedUserCAKeys /etc/ssh/ca.pub +PubkeyAuthentication yes +PasswordAuthentication no + +AuthorizedPrincipalsCommand /bin/bash -c "echo '%t %k' | ssh-keygen -L -f - | grep -A1 Principals" +AuthorizedPrincipalsCommandUser nobody + +PubkeyAcceptedKeyTypes ssh-rsa,ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-ed25519-cert-v01@openssh.com,ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com \ No newline at end of file diff --git a/.github/config.yml b/.github/config.yml index 4cfde089d51c1..e1b6e49e1777b 100644 --- a/.github/config.yml +++ b/.github/config.yml @@ -2,7 +2,9 @@ newPRWelcomeComment: | 💖 Thanks for opening this pull request! 💖 - We use [semantic commit messages](https://github.com/electron/electron/blob/master/docs/development/pull-requests.md#commit-message-guidelines) to streamline the release process. Before your pull request can be merged, you should **update your pull request title** to start with a semantic prefix. + ### Semantic PR titles + + We use [semantic commit messages](https://github.com/electron/electron/blob/main/docs/development/pull-requests.md#commit-message-guidelines) to streamline the release process. Before your pull request can be merged, you should **update your pull request title** to start with a semantic prefix. Examples of commit messages with semantic prefixes: @@ -10,11 +12,18 @@ newPRWelcomeComment: | - `feat: add app.isPackaged() method` - `docs: app.isDefaultProtocolClient is now available on Linux` + ### Commit signing + + This repo enforces [commit signatures](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits) for all incoming PRs. + To sign your commits, see GitHub's documentation on [Telling Git about your signing key](https://docs.github.com/en/authentication/managing-commit-signature-verification/telling-git-about-your-signing-key). + + ### PR tips + Things that will help get your PR across the finish line: - - Follow the JavaScript, C++, and Python [coding style](https://github.com/electron/electron/blob/master/docs/development/coding-style.md). + - Follow the JavaScript, C++, and Python [coding style](https://github.com/electron/electron/blob/main/docs/development/coding-style.md). - Run `npm run lint` locally to catch formatting errors earlier. - - Document any user-facing changes you've made following the [documentation styleguide](https://github.com/electron/electron/blob/master/docs/styleguide.md). + - Document any user-facing changes you've made following the [documentation styleguide](https://github.com/electron/electron/blob/main/docs/styleguide.md). - Include tests when adding/changing behavior. - Include screenshots and animated GIFs whenever possible. @@ -25,16 +34,3 @@ newPRWelcomeComment: | # Comment to be posted to on pull requests merged by a first time user firstPRMergeComment: > Congrats on merging your first pull request! 🎉🎉🎉 - -# Users authorized to run manual trop backports -authorizedUsers: - - alexeykuzmin - - ckerr - - codebytere - - deepak1556 - - jkleinsc - - loc - - MarshallOfSound - - miniak - - nornagon - - zcbenz diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000000000..e9dfaad4b5f0c --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,122 @@ +# Copilot Instructions for Electron + +## Build System + +Electron uses `@electron/build-tools` (`e` CLI). Install with `npm i -g @electron/build-tools`. + +```bash +e sync # Fetch sources and apply patches +e build # Build Electron (GN + Ninja) +e build -k 999 # Build, continuing through errors +e start # Run built Electron +e start --version # Verify Electron launches +e test # Run full test suite +e debug # Run in debugger (lldb on macOS, gdb on Linux) +``` + +### Linting + +```bash +npm run lint # Run all linters (JS, C++, Python, GN, docs) +npm run lint:js # JavaScript/TypeScript only +npm run lint:clang-format # C++ formatting only +npm run lint:cpp # C++ linting only +npm run lint:docs # Documentation only +``` + +### Running a Single Test + +```bash +npm run test -- -g "pattern" # Run tests matching a regex pattern +# Example: npm run test -- -g "ipc" +``` + +### Running a Single Node.js Test + +```bash +node script/node-spec-runner.js parallel/test-crypto-keygen +``` + +## Architecture + +Electron embeds Chromium (rendering) and Node.js (backend) to enable desktop apps with web technologies. The parent directory (`../`) is the Chromium source tree. + +### Process Model + +Electron has two primary process types, mirroring Chromium: + +- **Main process** (`shell/browser/` + `lib/browser/`): Controls app lifecycle, creates windows, system APIs +- **Renderer process** (`shell/renderer/` + `lib/renderer/`): Runs web content in BrowserWindows + +### Native ↔ JavaScript Bridge + +Each API is implemented as a C++/JS pair: + +- C++ side: `shell/browser/api/electron_api_{name}.cc/.h` — uses `gin::Wrappable` and `ObjectTemplateBuilder` +- JS side: `lib/browser/api/{name}.ts` — exports the module, registered in `lib/browser/api/module-list.ts` +- Binding: `NODE_LINKED_BINDING_CONTEXT_AWARE(electron_browser_{name}, Initialize)` in C++ and registered in `shell/common/node_bindings.cc` +- Type declaration: `typings/internal-ambient.d.ts` maps `process._linkedBinding('electron_browser_{name}')` + +### Patches System + +Electron patches upstream dependencies (Chromium, Node.js, V8, etc.) rather than forking them. Patches live in `patches/` organized by target, with `patches/config.json` mapping directories to repos. + +```text +patches/{target}/*.patch → [e sync] → target repo commits + ← [e patches] ← +``` + +Key rules: + +- Fix existing patches rather than creating new ones +- Preserve original authorship in TODO comments — never change `TODO(name)` assignees +- Each patch commit message must explain why the patch exists +- After modifying patches, run `e patches {target}` to export + +When working on the `roller/chromium/main` branch for Chromium upgrades, use `e sync --3` for 3-way merge conflict resolution. + +## Conventions + +### File Naming + +- JS/TS files: kebab-case (`file-name.ts`) +- C++ files: snake_case with `electron_api_` prefix (`electron_api_safe_storage.cc`) +- Test files: `api-{module-name}-spec.ts` in `spec/` +- Source file lists are maintained in `filenames.gni` (with platform-specific sections) + +### JavaScript/TypeScript + +- Semicolons required (`"semi": ["error", "always"]`) +- `const` and `let` only (no `var`) +- Arrow functions preferred +- Import order enforced: `@electron/internal` → `@electron` → `electron` → external → builtin → relative +- API naming: `PascalCase` for classes (`BrowserWindow`), `camelCase` for module APIs (`globalShortcut`) +- Prefer getters/setters over jQuery-style `.text([text])` patterns + +### C++ + +- Follows Chromium coding style, enforced by `clang-format` and `clang-tidy` +- Uses Chromium abstractions (`base::`, `content::`, etc.) +- Header guards: `#ifndef ELECTRON_SHELL_BROWSER_API_ELECTRON_API_{NAME}_H_` +- Platform-specific files: `_mac.mm`, `_win.cc`, `_linux.cc` + +### Testing + +- Framework: Mocha + Chai + Sinon +- Test helpers in `spec/lib/` (e.g., `spec-helpers.ts`, `window-helpers.ts`) +- Use `defer()` from spec-helpers for cleanup, `closeAllWindows()` for window teardown +- Tests import from `electron/main` or `electron/renderer` + +### Documentation + +- API docs in `docs/api/` as Markdown, parsed by `@electron/docs-parser` to generate `electron.d.ts` +- API history tracked via YAML blocks in HTML comments within doc files +- Docs must pass `npm run lint:docs` + +### Build Configuration + +- `BUILD.gn`: Main GN build config +- `buildflags/buildflags.gni`: Feature flags (PDF viewer, extensions, spellchecker) +- `build/args/`: Build argument profiles (`testing.gn`, `release.gn`, `all.gn`) +- `DEPS`: Dependency versions and checkout paths +- `chromium_src/`: Chromium source file overrides (compiled instead of originals) diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000000..04a32c3587dd0 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,68 @@ +# Keep GitHub Actions up to date with GitHub's Dependabot... +# https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot +# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#package-ecosystem +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + labels: + - "no-backport" + - "semver/none" + target-branch: main + - package-ecosystem: npm + directories: + - / + - /spec + - /npm + schedule: + interval: daily + labels: + - "no-backport" + open-pull-requests-limit: 2 + target-branch: main + - package-ecosystem: npm + directories: + - / + - /spec + - /npm + schedule: + interval: daily + labels: + - "backport-check-skip" + open-pull-requests-limit: 0 + target-branch: 33-x-y + - package-ecosystem: npm + directories: + - / + - /spec + - /npm + schedule: + interval: daily + labels: + - "backport-check-skip" + open-pull-requests-limit: 0 + target-branch: 32-x-y + - package-ecosystem: npm + directories: + - / + - /spec + - /npm + schedule: + interval: daily + labels: + - "backport-check-skip" + open-pull-requests-limit: 0 + target-branch: 31-x-y + - package-ecosystem: npm + directories: + - / + - /spec + - /npm + schedule: + interval: daily + labels: + - "backport-check-skip" + open-pull-requests-limit: 0 + target-branch: 30-x-y \ No newline at end of file diff --git a/.github/problem-matchers/clang.json b/.github/problem-matchers/clang.json new file mode 100644 index 0000000000000..17abb30cee85d --- /dev/null +++ b/.github/problem-matchers/clang.json @@ -0,0 +1,18 @@ +{ + "problemMatcher": [ + { + "owner": "clang", + "fromPath": "src/out/Default/args.gn", + "pattern": [ + { + "regexp": "^(.+)[(:](\\d+)[:,](\\d+)\\)?:\\s+(warning|fatal error|error):\\s+(.*)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + ] + } + ] +} diff --git a/.github/problem-matchers/markdownlint.json b/.github/problem-matchers/markdownlint.json new file mode 100644 index 0000000000000..b5bb47809732f --- /dev/null +++ b/.github/problem-matchers/markdownlint.json @@ -0,0 +1,16 @@ +{ + "problemMatcher": [ + { + "owner": "markdownlint", + "pattern": [ + { + "regexp": "^(.+):(\\d+):(\\d+)\\s+(.*)$", + "file": 1, + "line": 2, + "column": 3, + "message": 4 + } + ] + } + ] +} diff --git a/.github/problem-matchers/patch-conflict.json b/.github/problem-matchers/patch-conflict.json new file mode 100644 index 0000000000000..e145746321588 --- /dev/null +++ b/.github/problem-matchers/patch-conflict.json @@ -0,0 +1,34 @@ +{ + "problemMatcher": [ + { + "owner": "merge-conflict", + "pattern": [ + { + "regexp": "^CONFLICT\\s\\(\\S+\\): (Merge conflict in \\S+)$", + "message": 1 + } + ] + }, + { + "owner": "patch-conflict", + "pattern": [ + { + "regexp": "^error: (patch failed: (\\S+):(\\d+))$", + "message": 1, + "file": 2, + "line": 3 + } + ] + }, + { + "owner": "patch-needs-update", + "pattern": [ + { + "regexp": "^((patches\/.*): needs update)$", + "message": 1, + "file": 2 + } + ] + } + ] +} diff --git a/.github/siso-patches/0001-siso-reuse-the-outer-os.File-for-chunked-ReadAt-in-f.patch b/.github/siso-patches/0001-siso-reuse-the-outer-os.File-for-chunked-ReadAt-in-f.patch new file mode 100644 index 0000000000000..05b6f78939aac --- /dev/null +++ b/.github/siso-patches/0001-siso-reuse-the-outer-os.File-for-chunked-ReadAt-in-f.patch @@ -0,0 +1,47 @@ +From aab86e682d6f40e110700f36c9c37f6655fb14f1 Mon Sep 17 00:00:00 2001 +From: Samuel Attard +Date: Wed, 8 Apr 2026 23:24:15 -0700 +Subject: [PATCH] siso: reuse the outer *os.File for chunked ReadAt in + fileParser.readFile +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The per-chunk goroutine currently re-opens fname to get its own handle +for ReadAt. (*os.File).ReadAt is documented as safe for concurrent +calls on the same File (on Windows it is ReadFile with an OVERLAPPED +offset, so there is no shared seek state), so the extra open is +redundant — the goroutines can share the outer f. + +Besides halving the CreateFileW calls per subninja, this avoids an +intermittent 'The parameter is incorrect.' (ERROR_INVALID_PARAMETER) +from bindflt.sys when out/ is a mapped directory inside a Windows +container: bindflt's handle-relative NtCreateFile path races when a +second relative open arrives while the first handle to the same target +is still being set up. Absolute paths and single opens do not trigger +it; see microsoft/Windows-Containers#. +--- + siso/toolsupport/ninjautil/file_parser.go | 7 ------- + 1 file changed, 7 deletions(-) + +diff --git a/siso/toolsupport/ninjautil/file_parser.go b/siso/toolsupport/ninjautil/file_parser.go +index f8c7eff..75b1d6e 100644 +--- a/siso/toolsupport/ninjautil/file_parser.go ++++ b/siso/toolsupport/ninjautil/file_parser.go +@@ -128,13 +128,6 @@ func (p *fileParser) readFile(ctx context.Context, fname string) ([]byte, error) + eg.Go(func() error { + p.sema <- struct{}{} + defer func() { <-p.sema }() +- f, err := os.Open(fname) +- if err != nil { +- return err +- } +- defer func() { +- _ = f.Close() +- }() + for len(chunkBuf) > 0 { + n, err := f.ReadAt(chunkBuf, pos) + if err != nil { +-- +2.52.0 + diff --git a/.github/siso-patches/0002-siso-retry-transient-ERROR_INVALID_PARAMETER-when-op.patch b/.github/siso-patches/0002-siso-retry-transient-ERROR_INVALID_PARAMETER-when-op.patch new file mode 100644 index 0000000000000..fe18b157db9ff --- /dev/null +++ b/.github/siso-patches/0002-siso-retry-transient-ERROR_INVALID_PARAMETER-when-op.patch @@ -0,0 +1,132 @@ +From 1786f2266cba6a66343e5af2b724214930c8292f Mon Sep 17 00:00:00 2001 +From: Samuel Attard +Date: Wed, 22 Apr 2026 16:27:51 -0700 +Subject: [PATCH] siso: retry transient ERROR_INVALID_PARAMETER when opening + ninja files on Windows + +ManifestParser.Load fans out across all subninja files (~90k in a +Chromium build) at NumCPU parallelism. On Windows builders where out/ +is served through a filesystem filter driver (e.g. bindflt/wcifs for +container bind mounts), CreateFileW can intermittently return +ERROR_INVALID_PARAMETER under this concurrent open burst. The previous +patch removes the redundant per-chunk re-open, but the single remaining +open per file can still hit the race; without a retry a single transient +failure aborts the entire manifest load. + +Wrap the remaining os.Open call in readFile in a small Windows-only +retry for ERROR_INVALID_PARAMETER (5 attempts, 5-80ms backoff). Each +retry is logged via clog.Warningf and also written to stderr so it is +visible in CI step output where glog warnings are file-only by default. +Other platforms keep the direct os.Open path. +--- + siso/toolsupport/ninjautil/file_parser.go | 3 +- + siso/toolsupport/ninjautil/openfile_other.go | 18 +++++++ + .../toolsupport/ninjautil/openfile_windows.go | 50 +++++++++++++++++++ + 3 files changed, 69 insertions(+), 2 deletions(-) + create mode 100644 siso/toolsupport/ninjautil/openfile_other.go + create mode 100644 siso/toolsupport/ninjautil/openfile_windows.go + +diff --git a/siso/toolsupport/ninjautil/file_parser.go b/siso/toolsupport/ninjautil/file_parser.go +index 75b1d6e..4a3e639 100644 +--- a/siso/toolsupport/ninjautil/file_parser.go ++++ b/siso/toolsupport/ninjautil/file_parser.go +@@ -7,7 +7,6 @@ package ninjautil + import ( + "context" + "fmt" +- "os" + "path/filepath" + "runtime/trace" + "sync" +@@ -108,7 +107,7 @@ func (p *fileParser) parseFile(ctx context.Context, fname string) error { + // readFile reads a file of fname in parallel. + func (p *fileParser) readFile(ctx context.Context, fname string) ([]byte, error) { + defer trace.StartRegion(ctx, "ninja.read").End() +- f, err := os.Open(fname) ++ f, err := openFile(ctx, fname) + if err != nil { + return nil, err + } +diff --git a/siso/toolsupport/ninjautil/openfile_other.go b/siso/toolsupport/ninjautil/openfile_other.go +new file mode 100644 +index 0000000..9fca690 +--- /dev/null ++++ b/siso/toolsupport/ninjautil/openfile_other.go +@@ -0,0 +1,18 @@ ++// Copyright 2026 The Chromium Authors ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++//go:build !windows ++ ++package ninjautil ++ ++import ( ++ "context" ++ "os" ++) ++ ++// openFile opens fname for reading. ++// See openfile_windows.go for the Windows variant with transient-error retry. ++func openFile(ctx context.Context, fname string) (*os.File, error) { ++ return os.Open(fname) ++} +diff --git a/siso/toolsupport/ninjautil/openfile_windows.go b/siso/toolsupport/ninjautil/openfile_windows.go +new file mode 100644 +index 0000000..f9d8e9d +--- /dev/null ++++ b/siso/toolsupport/ninjautil/openfile_windows.go +@@ -0,0 +1,50 @@ ++// Copyright 2026 The Chromium Authors ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++//go:build windows ++ ++package ninjautil ++ ++import ( ++ "context" ++ "errors" ++ "fmt" ++ "os" ++ "time" ++ ++ "golang.org/x/sys/windows" ++ ++ "go.chromium.org/build/siso/o11y/clog" ++) ++ ++// openFile opens fname for reading, retrying transient ++// ERROR_INVALID_PARAMETER failures. ++// ++// On Windows, CreateFileW can intermittently return ++// ERROR_INVALID_PARAMETER when the target lives behind a filesystem ++// filter driver (e.g. bindflt/wcifs for container bind mounts) under ++// highly concurrent opens. loadFile fans out across ~90k subninja ++// files at NumCPU parallelism, so a single transient failure would ++// otherwise abort the whole manifest load. ++func openFile(ctx context.Context, fname string) (*os.File, error) { ++ const maxAttempts = 5 ++ delay := 5 * time.Millisecond ++ for i := 0; ; i++ { ++ f, err := os.Open(fname) ++ if err == nil { ++ return f, nil ++ } ++ if i+1 >= maxAttempts || !errors.Is(err, windows.ERROR_INVALID_PARAMETER) { ++ return nil, err ++ } ++ clog.Warningf(ctx, "open %s: %v; retrying (%d/%d) after %s", fname, err, i+1, maxAttempts, delay) ++ fmt.Fprintf(os.Stderr, "siso: open %s: %v; retrying (%d/%d) after %s\n", fname, err, i+1, maxAttempts, delay) ++ select { ++ case <-time.After(delay): ++ case <-ctx.Done(): ++ return nil, context.Cause(ctx) ++ } ++ delay *= 2 ++ } ++} +-- +2.52.0 + diff --git a/.github/workflows/apply-patches.yml b/.github/workflows/apply-patches.yml new file mode 100644 index 0000000000000..345edff3e3cc9 --- /dev/null +++ b/.github/workflows/apply-patches.yml @@ -0,0 +1,96 @@ +name: Apply Patches + +on: + pull_request: + +permissions: {} + +concurrency: + group: apply-patches-${{ github.ref }} + cancel-in-progress: true + +jobs: + setup: + if: github.repository == 'electron/electron' + runs-on: ubuntu-slim + permissions: + contents: read + pull-requests: read + outputs: + has-patches: ${{ steps.filter.outputs.patches }} + has-siso-patches: ${{ steps.filter.outputs.siso-patches }} + build-image-sha: ${{ steps.build-image-sha.outputs.build-image-sha }} + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + persist-credentials: false + ref: ${{ github.event.pull_request.head.sha }} + # Use dorny/paths-filter instead of the path filter under the on: pull_request: block + # so that the output can be used to conditionally run the apply-patches job, which lets + # the job be marked as a required status check (conditional skip counts as a success). + - uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1 + id: filter + with: + filters: | + patches: + - DEPS + - 'patches/**' + siso-patches: + - DEPS + - '.github/siso-patches/**' + - name: Set Build Image SHA + id: build-image-sha + uses: ./.github/actions/build-image-sha + + apply-patches: + needs: setup + if: ${{ needs.setup.outputs.has-patches == 'true' }} + runs-on: electron-arc-centralus-linux-amd64-32core + permissions: + contents: read + container: + image: ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }} + options: --user root + volumes: + - /mnt/cross-instance-cache:/mnt/cross-instance-cache + - /var/run/sas:/var/run/sas + env: + CHROMIUM_GIT_COOKIE: ${{ secrets.CHROMIUM_GIT_COOKIE }} + GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' + steps: + - name: Checkout Electron + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + path: src/electron + fetch-depth: 0 + persist-credentials: false + ref: ${{ github.event.pull_request.base.ref }} + - name: Merge PR HEAD + working-directory: src/electron + env: + PR_NUMBER: ${{ github.event.pull_request.number }} + run: | + git config user.email "electron@github.com" + git config user.name "Electron Bot" + git fetch origin refs/pull/${PR_NUMBER}/head + git merge --squash FETCH_HEAD + git commit -n -m "Squashed commits" + - name: Checkout & Sync & Save + uses: ./src/electron/.github/actions/checkout + with: + target-platform: linux + - name: Upload Patch Conflict Fix + if: ${{ failure() }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: update-patches + path: patches/update-patches.patch + if-no-files-found: ignore + archive: false + + build-siso: + needs: setup + if: ${{ needs.setup.outputs.has-siso-patches == 'true' }} + uses: ./.github/workflows/pipeline-segment-build-siso-windows.yml + permissions: + contents: read diff --git a/.github/workflows/archaeologist-dig.yml b/.github/workflows/archaeologist-dig.yml new file mode 100644 index 0000000000000..1b0dcf8a22739 --- /dev/null +++ b/.github/workflows/archaeologist-dig.yml @@ -0,0 +1,73 @@ +name: Archaeologist + +on: + pull_request: + +permissions: {} + +jobs: + archaeologist-dig: + name: Archaeologist Dig + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Checkout Electron + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + fetch-depth: 0 + - name: Setup Node.js/npm + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e + with: + node-version: 24.12.x + - name: Setting Up Dig Site + env: + CLONE_URL: ${{ github.event.pull_request.head.repo.clone_url }} + HEAD_SHA: ${{ github.event.pull_request.head.sha }} + BASE_REF: ${{ github.event.pull_request.base.ref }} + run: | + echo "remote: $CLONE_URL" + echo "sha $HEAD_SHA" + echo "base ref $BASE_REF" + git clone https://github.com/electron/electron.git electron + cd electron + mkdir -p artifacts + git remote add fork "$CLONE_URL" && git fetch fork + git checkout "$HEAD_SHA" + git merge-base "origin/$BASE_REF" HEAD > .dig-old + echo "$HEAD_SHA" > .dig-new + cp .dig-old artifacts + + - name: Generating Types for SHA in .dig-new + uses: ./.github/actions/generate-types + with: + sha-file: .dig-new + filename: electron.new.d.ts + - name: Generating Types for SHA in .dig-old + uses: ./.github/actions/generate-types + with: + sha-file: .dig-old + filename: electron.old.d.ts + - name: Upload artifacts + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a #v7.0.1 + with: + name: artifacts + path: electron/artifacts + include-hidden-files: true + - name: Set job output + run: | + git diff --no-index electron.old.d.ts electron.new.d.ts > patchfile || true + if [ -s patchfile ]; then + echo "Changes Detected" + echo "## Changes Detected" > $GITHUB_STEP_SUMMARY + echo "Looks like the \`electron.d.ts\` file changed." >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "\`\`\`\`\`\`diff" >> $GITHUB_STEP_SUMMARY + cat patchfile >> $GITHUB_STEP_SUMMARY + echo "\`\`\`\`\`\`" >> $GITHUB_STEP_SUMMARY + else + echo "No Changes Detected" + echo "## No Changes" > $GITHUB_STEP_SUMMARY + echo "We couldn't see any changes in the \`electron.d.ts\` artifact" >> $GITHUB_STEP_SUMMARY + fi + working-directory: ./electron/artifacts diff --git a/.github/workflows/audit-branch-ci.yml b/.github/workflows/audit-branch-ci.yml new file mode 100644 index 0000000000000..abf7322edd819 --- /dev/null +++ b/.github/workflows/audit-branch-ci.yml @@ -0,0 +1,165 @@ +name: Audit CI on Branches + +on: + workflow_dispatch: + schedule: + # Run every 2 hours + - cron: '0 */2 * * *' + +permissions: {} + +jobs: + audit_branch_ci: + name: Audit CI on Branches + if: github.repository == 'electron/electron' + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Setup Node.js + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: 22.17.x + - name: Sparse checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + sparse-checkout: | + . + .github + .yarn + - run: yarn workspaces focus @electron/gha-workflows + - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + id: audit-errors + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const { chdir } = require('node:process'); + chdir('${{ github.workspace }}/.github/workflows'); + + const cache = require('@actions/cache'); + const { ElectronVersions } = require('@electron/fiddle-core'); + + const runsWithErrors = []; + + // Only want the most recent workflow run that wasn't skipped or cancelled + const isValidWorkflowRun = (run) => !['skipped', 'cancelled'].includes(run.conclusion); + + const versions = await ElectronVersions.create({ ignoreCache: true }); + const branches = versions.supportedMajors.map((branch) => `${branch}-x-y`); + + for (const branch of ["main", ...branches]) { + const latestCheckRuns = new Map(); + const allCheckRuns = await github.paginate(github.rest.checks.listForRef, { + owner: "electron", + repo: "electron", + ref: branch, + status: 'completed', + }); + + // Sort the check runs by completed_at so that multiple check runs on the + // same ref (like a scheduled workflow) only looks at the most recent one + for (const checkRun of allCheckRuns.filter( + (run) => !['skipped', 'cancelled'].includes(run.conclusion), + ).sort((a, b) => new Date(b.completed_at) - new Date(a.completed_at))) { + if (!latestCheckRuns.has(checkRun.name)) { + latestCheckRuns.set(checkRun.name, checkRun); + } + } + + // Check for runs which had error annotations + for (const checkRun of Array.from(latestCheckRuns.values())) { + if (checkRun.name === "Audit CI on Branches") { + continue; // Skip the audit workflow itself + } + + const annotations = (await github.rest.checks.listAnnotations({ + owner: "electron", + repo: "electron", + check_run_id: checkRun.id, + })).data ?? []; + + if ( + annotations.find( + ({ annotation_level, message }) => + annotation_level === "failure" && + !message.startsWith("Process completed with exit code") && + !message.startsWith("Response status code does not indicate success") && + !message.startsWith("The hosted runner lost communication with the server") && + !message.startsWith("Dependabot encountered an error performing the update") && + !message.startsWith("The action 'Run Electron Tests' has timed out") && + !message.startsWith("The operation was canceled") && + !message.startsWith("Canceling since") && + !/Unable to make request/.test(message) && + !/The requested URL returned error/.test(message), + ) + ) { + checkRun.hasErrorAnnotations = true; + } else { + continue; + } + + // Check if this is a known failure from a previous audit run + const cacheKey = `check-run-error-annotations-${checkRun.id}`; + const cacheHit = + (await cache.restoreCache(['/dev/null'], cacheKey, undefined, { + lookupOnly: true, + })) !== undefined; + + if (cacheHit) { + checkRun.isStale = true; + } + + checkRun.branch = branch; + runsWithErrors.push(checkRun); + + // Create a cache entry (only the name matters) to keep track of + // failures we've seen from previous runs to mark them as stale + if (!cacheHit) { + await cache.saveCache(['/dev/null'], cacheKey); + } + } + } + + if (runsWithErrors.length > 0) { + core.summary.addHeading('⚠️ Runs with Errors'); + core.summary.addTable([ + [ + { data: 'Branch', header: true }, + { data: 'Workflow Run', header: true }, + { data: 'Status', header: true }, + ], + ...runsWithErrors + .sort( + (a, b) => + a.branch.localeCompare(b.branch) || + a.name.localeCompare(b.name), + ) + .map((run) => [ + run.branch, + `${run.name}`, + run.isStale + ? '📅 Stale' + : run.hasErrorAnnotations + ? '⚠️ Errors' + : '✅ Succeeded', + ]), + ]); + + // Set this as failed so it's easy to scan runs to find failures + if (runsWithErrors.find((run) => !run.isStale)) { + core.setOutput('errorsFound', true); + process.exitCode = 1; + } + } else { + core.summary.addRaw('🎉 No runs with errors'); + } + + await core.summary.write(); + - name: Send Slack message if errors + if: ${{ always() && steps.audit-errors.outputs.errorsFound && github.ref == 'refs/heads/main' }} + uses: slackapi/slack-github-action@af78098f536edbc4de71162a307590698245be95 # v3.0.1 + with: + payload: | + link: "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" + webhook: ${{ secrets.CI_ERRORS_SLACK_WEBHOOK_URL }} + webhook-type: webhook-trigger diff --git a/.github/workflows/branch-created.yml b/.github/workflows/branch-created.yml new file mode 100644 index 0000000000000..74c93f4b446d9 --- /dev/null +++ b/.github/workflows/branch-created.yml @@ -0,0 +1,245 @@ +name: Branch Created + +on: + workflow_dispatch: + inputs: + branch-name: + description: Branch name (e.g. `29-x-y`) + required: true + type: string + create: + +permissions: {} + +jobs: + release-branch-created: + name: Release Branch Created + if: ${{ github.repository == 'electron/electron' && (github.event_name == 'workflow_dispatch' || (github.event.ref_type == 'branch' && endsWith(github.event.ref, '-x-y') && !startsWith(github.event.ref, 'roller'))) }} + permissions: + contents: read + pull-requests: write + repository-projects: write # Required for labels + runs-on: ubuntu-latest + steps: + - name: Determine Major Version + id: check-major-version + env: + BRANCH_NAME: ${{ github.event.inputs.branch-name || github.event.ref }} + run: | + if [[ "$BRANCH_NAME" =~ ^([0-9]+)-x-y$ ]]; then + echo "MAJOR=${BASH_REMATCH[1]}" >> "$GITHUB_OUTPUT" + else + echo "Not a release branch: $BRANCH_NAME" + fi + - name: Determine Next Unsupported Major Version + id: determine-next-unsupported-major + if: ${{ steps.check-major-version.outputs.MAJOR }} + env: + MAJOR: ${{ steps.check-major-version.outputs.MAJOR }} + run: | + # Fetch the release schedule + SCHEDULE=$(curl -s https://releases.electronjs.org/schedule.json) + + # Get the stableDate for the current major version + STABLE_DATE=$(echo "$SCHEDULE" | jq -r --arg major "${MAJOR}.0.0" '.[] | select(.version == $major) | .stableDate') + + if [[ -z "$STABLE_DATE" || "$STABLE_DATE" == "null" ]]; then + echo "Could not find stableDate for version $MAJOR" + exit 1 + fi + + # Find the oldest version where eolDate >= stableDate of the new major + # This gives us the oldest supported version when the new major goes stable + NEXT_UNSUPPORTED_MAJOR=$(echo "$SCHEDULE" | jq -r --arg stableDate "$STABLE_DATE" ' + [.[] | select(.eolDate != null and .eolDate >= $stableDate)] | sort_by(.version | split(".")[0] | tonumber) | first | .version | split(".")[0] + ') + + if [[ -z "$NEXT_UNSUPPORTED_MAJOR" || "$NEXT_UNSUPPORTED_MAJOR" == "null" ]]; then + echo "Could not determine oldest supported version" + exit 1 + fi + + echo "SCHEDULE=$SCHEDULE" >> "$GITHUB_OUTPUT" + echo "NEXT_UNSUPPORTED_MAJOR=$NEXT_UNSUPPORTED_MAJOR" >> "$GITHUB_OUTPUT" + - name: New Release Branch Tasks + if: ${{ steps.check-major-version.outputs.MAJOR }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: electron/electron + MAJOR: ${{ steps.check-major-version.outputs.MAJOR }} + NEXT_UNSUPPORTED_MAJOR: ${{ steps.determine-next-unsupported-major.outputs.NEXT_UNSUPPORTED_MAJOR }} + run: | + PREVIOUS_MAJOR=$((MAJOR - 1)) + UNSUPPORTED_MAJOR=$((NEXT_UNSUPPORTED_MAJOR - 1)) + + # Create new labels + gh label create $MAJOR-x-y --color 8d9ee8 || true + gh label create target/$MAJOR-x-y --color ad244f --description "PR should also be added to the \"${MAJOR}-x-y\" branch." || true + gh label create merged/$MAJOR-x-y --color 61a3c6 --description "PR was merged to the \"${MAJOR}-x-y\" branch." || true + gh label create in-flight/$MAJOR-x-y --color db69a6 || true + gh label create needs-manual-bp/$MAJOR-x-y --color 8b5dba || true + + # Change color of old labels + gh label edit $UNSUPPORTED_MAJOR-x-y --color ededed || true + gh label edit target/$UNSUPPORTED_MAJOR-x-y --color ededed || true + gh label edit merged/$UNSUPPORTED_MAJOR-x-y --color ededed || true + gh label edit in-flight/$UNSUPPORTED_MAJOR-x-y --color ededed || true + gh label edit needs-manual-bp/$UNSUPPORTED_MAJOR-x-y --color ededed || true + + # Add the new target label to any PRs which: + # * target the previous major + # * are in-flight for the previous major + # * need manual backport for the previous major + for PREVIOUS_MAJOR_LABEL in target/$PREVIOUS_MAJOR-x-y in-flight/$PREVIOUS_MAJOR-x-y needs-manual-bp/$PREVIOUS_MAJOR-x-y; do + PULL_REQUESTS=$(gh pr list --label $PREVIOUS_MAJOR_LABEL --jq .[].number --json number --limit 500) + if [[ $PULL_REQUESTS ]]; then + echo $PULL_REQUESTS | xargs -n 1 gh pr edit --add-label target/$MAJOR-x-y || true + fi + done + - name: Generate GitHub App token + if: ${{ steps.check-major-version.outputs.MAJOR }} + uses: electron/github-app-auth-action@e14e47722ed120360649d0789e25b9baece12725 # v2.0.0 + id: generate-token + with: + creds: ${{ secrets.RELEASE_BOARD_GH_APP_CREDS }} + org: electron + - name: Generate Release Project Board Metadata + if: ${{ steps.check-major-version.outputs.MAJOR }} + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + id: generate-project-metadata + env: + MAJOR: ${{ steps.check-major-version.outputs.MAJOR }} + NEXT_UNSUPPORTED_MAJOR: ${{ steps.determine-next-unsupported-major.outputs.NEXT_UNSUPPORTED_MAJOR }} + SCHEDULE: ${{ steps.determine-next-unsupported-major.outputs.SCHEDULE }} + with: + script: | + const schedule = JSON.parse(process.env.SCHEDULE) + + const major = parseInt(process.env.MAJOR) + const nextMajor = major + 1 + const prevMajor = major - 1 + + const { betaDate, stableDate } = schedule.find(v => v.version === `${major}.0.0`) + + const betaPrepWeek = new Date(betaDate) + betaPrepWeek.setDate(betaPrepWeek.getDate() - 8) + const betaPrepWeekEnd = new Date(betaPrepWeek) + betaPrepWeekEnd.setDate(betaPrepWeekEnd.getDate() + 4) + + const stablePrepWeek = new Date(stableDate) + stablePrepWeek.setDate(stablePrepWeek.getDate() - 8) + const stablePrepWeekEnd = new Date(stablePrepWeek) + stablePrepWeekEnd.setDate(stablePrepWeekEnd.getDate() + 4) + + const stableWeek = new Date(stableDate) + stableWeek.setDate(stableWeek.getDate() - 1) + + const nextAlphaDate = new Date(stableDate) + nextAlphaDate.setDate(nextAlphaDate.getDate() + 2) + + core.setOutput("major", major) + core.setOutput("next-major", nextMajor) + core.setOutput("prev-major", prevMajor) + core.setOutput("prev-prev-major", prevMajor - 1) + core.setOutput("template-view", JSON.stringify({ + major, + "next-major": nextMajor, + "prev-major": prevMajor, + "ending-support-major": parseInt(process.env.NEXT_UNSUPPORTED_MAJOR), + "beta-date": betaDate, + "beta-prep-week": betaPrepWeek.toISOString().split('T')[0], + "beta-prep-week-end": betaPrepWeekEnd.toISOString().split('T')[0], + "stable-week": stableWeek.toISOString().split('T')[0], + "stable-prep-week": stablePrepWeek.toISOString().split('T')[0], + "stable-prep-week-end": stablePrepWeekEnd.toISOString().split('T')[0], + "stable-date": stableDate, + "next-alpha-date": nextAlphaDate.toISOString().split('T')[0], + })) + - name: Create Release Project Board + if: ${{ steps.check-major-version.outputs.MAJOR }} + uses: dsanders11/project-actions/copy-project@4b06452b0128cf601dac14399aa668a8eed2d684 # v2.0.1 + id: create-release-board + with: + drafts: true + project-number: 64 + # TODO - Set to public once GitHub fixes their GraphQL bug + # public: true + # TODO - Enable once GitHub doesn't require overly broad, read + # and write permission for repo "Contents" to link + # link-to-repository: electron/electron + template-view: ${{ steps.generate-project-metadata.outputs.template-view }} + title: ${{ steps.generate-project-metadata.outputs.major }}-x-y + token: ${{ steps.generate-token.outputs.token }} + - name: Randomly Assign Draft Issues to Release WG Members + if: ${{ steps.check-major-version.outputs.MAJOR }} + uses: dsanders11/project-actions/github-script@4b06452b0128cf601dac14399aa668a8eed2d684 # v2.0.1 + env: + PROJECT_ID: ${{ steps.create-release-board.outputs.id }} + with: + token: ${{ steps.generate-token.outputs.token }} + script: | + const { data: members } = await github.rest.teams.listMembersInOrg({ + org: 'electron', + team_slug: 'wg-releases', + }); + + const excludedLogins = ['nikwen']; + const memberLogins = new Set(members.map(m => m.login)); + for (const login of excludedLogins) { + if (!memberLogins.has(login)) { + core.warning(`Excluded member "${login}" is not in @electron/wg-releases`); + } + } + + const eligible = members.filter(m => !excludedLogins.includes(m.login)); + + if (eligible.length === 0) { + core.warning('No eligible members found in @electron/wg-releases team'); + return; + } + + const projectId = process.env.PROJECT_ID; + const draftIssues = await actions.getDraftIssues(projectId); + + if (draftIssues.length === 0) { + core.info('No draft issues found in the project'); + return; + } + + // Fisher-Yates shuffle for uniform random assignment + const shuffled = [...eligible]; + for (let i = shuffled.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]]; + } + + // Assign draft issues round-robin across team members + for (let i = 0; i < draftIssues.length; i++) { + const member = shuffled[i % shuffled.length]; + const draftIssue = draftIssues[i]; + core.info(`Assigning "${draftIssue.content.title}" to ${member.login}`); + await actions.editItem(projectId, draftIssue.content.id, { + assignees: [member.login], + }); + } + + core.info(`Assigned ${draftIssues.length} draft issues to ${eligible.length} team members`); + - name: Dump Release Project Board Contents + if: ${{ steps.check-major-version.outputs.MAJOR }} + run: gh project item-list ${{ steps.create-release-board.outputs.number }} --owner electron --format json | jq + env: + GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }} + - name: Find Previous Release Project Board + if: ${{ steps.check-major-version.outputs.MAJOR }} + uses: dsanders11/project-actions/find-project@4b06452b0128cf601dac14399aa668a8eed2d684 # v2.0.1 + id: find-prev-release-board + with: + fail-if-project-not-found: false + title: ${{ steps.generate-project-metadata.outputs.prev-prev-major }}-x-y + token: ${{ steps.generate-token.outputs.token }} + - name: Close Previous Release Project Board + if: ${{ steps.find-prev-release-board.outputs.number }} + uses: dsanders11/project-actions/close-project@4b06452b0128cf601dac14399aa668a8eed2d684 # v2.0.1 + with: + project-number: ${{ steps.find-prev-release-board.outputs.number }} + token: ${{ steps.generate-token.outputs.token }} diff --git a/.github/workflows/build-git-cache.yml b/.github/workflows/build-git-cache.yml new file mode 100644 index 0000000000000..2bfd9e15cb083 --- /dev/null +++ b/.github/workflows/build-git-cache.yml @@ -0,0 +1,97 @@ +name: Build Git Cache +# This workflow updates git cache on the cross-instance cache volumes +# It runs daily at midnight. + +on: + schedule: + - cron: "0 0 * * *" + +permissions: {} + +jobs: + setup: + if: github.repository == 'electron/electron' + runs-on: ubuntu-slim + permissions: + contents: read + outputs: + build-image-sha: ${{ steps.build-image-sha.outputs.build-image-sha }} + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + - name: Set Build Image SHA + id: build-image-sha + uses: ./.github/actions/build-image-sha + + build-git-cache-linux: + needs: setup + runs-on: electron-arc-centralus-linux-amd64-32core + permissions: + contents: read + container: + image: ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }} + options: --user root + volumes: + - /mnt/cross-instance-cache:/mnt/cross-instance-cache + env: + CHROMIUM_GIT_COOKIE: ${{ secrets.CHROMIUM_GIT_COOKIE }} + GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' + steps: + - name: Checkout Electron + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + path: src/electron + fetch-depth: 0 + - name: Build Git Cache + uses: ./src/electron/.github/actions/build-git-cache + with: + target-platform: linux + + build-git-cache-windows: + needs: setup + runs-on: electron-arc-centralus-linux-amd64-32core + permissions: + contents: read + container: + image: ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }} + options: --user root --device /dev/fuse --cap-add SYS_ADMIN + volumes: + - /mnt/win-cache:/mnt/win-cache + env: + CHROMIUM_GIT_COOKIE: ${{ secrets.CHROMIUM_GIT_COOKIE }} + GCLIENT_EXTRA_ARGS: '--custom-var=checkout_win=True' + TARGET_OS: 'win' + steps: + - name: Checkout Electron + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + path: src/electron + fetch-depth: 0 + - name: Build Git Cache + uses: ./src/electron/.github/actions/build-git-cache + with: + target-platform: win + + build-git-cache-macos: + # This job updates the same git cache as linux, so it needs to run after the linux one. + needs: [setup, build-git-cache-linux] + runs-on: electron-arc-centralus-linux-amd64-32core + permissions: + contents: read + container: + image: ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }} + options: --user root + volumes: + - /mnt/cross-instance-cache:/mnt/cross-instance-cache + env: + CHROMIUM_GIT_COOKIE: ${{ secrets.CHROMIUM_GIT_COOKIE }} + GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac' + steps: + - name: Checkout Electron + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + path: src/electron + fetch-depth: 0 + - name: Build Git Cache + uses: ./src/electron/.github/actions/build-git-cache + with: + target-platform: macos diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000000000..261f81125e5de --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,464 @@ +name: Build + +on: + workflow_dispatch: + inputs: + build-image-sha: + type: string + description: 'SHA for electron/build image' + default: '' + required: false + skip-macos: + type: boolean + description: 'Skip macOS builds' + default: false + required: false + skip-linux: + type: boolean + description: 'Skip Linux builds' + default: false + required: false + skip-windows: + type: boolean + description: 'Skip Windows builds' + default: false + required: false + skip-lint: + type: boolean + description: 'Skip lint check' + default: false + required: false + enable-ssh: + description: 'Enable SSH debugging' + required: false + type: boolean + default: false + push: + branches: + - main + - '[1-9][0-9]-x-y' + pull_request: + +defaults: + run: + shell: bash + +permissions: {} + +jobs: + setup: + if: github.repository == 'electron/electron' + runs-on: ubuntu-slim + permissions: + contents: read + pull-requests: read + outputs: + docs: ${{ steps.filter.outputs.docs }} + src: ${{ steps.filter.outputs.src }} + build-image-sha: ${{ steps.build-image-sha.outputs.build-image-sha }} + docs-only: ${{ steps.set-output.outputs.docs-only }} + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + ref: ${{ github.event.pull_request.head.sha }} + - uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1 + id: filter + with: + filters: | + docs: + - 'docs/**' + - '.claude/**' + - README.md + - SECURITY.md + - CONTRIBUTING.md + - CODE_OF_CONDUCT.md + src: + - '!{docs,.claude}/**' + - name: Set Build Image SHA + id: build-image-sha + uses: ./.github/actions/build-image-sha + with: + override: ${{ inputs.build-image-sha }} + - name: Set Docs Only + id: set-output + run: | + echo "docs-only=${{ steps.filter.outputs.docs == 'true' && steps.filter.outputs.src == 'false' }}" >> "$GITHUB_OUTPUT" + + # Lint Jobs + lint: + needs: setup + if: ${{ !inputs.skip-lint }} + uses: ./.github/workflows/pipeline-electron-lint.yml + permissions: + contents: read + with: + container: '{"image":"ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }}","options":"--user root"}' + secrets: inherit + + # Docs Only Jobs + docs-only: + needs: [setup, checkout-linux] + if: ${{ needs.setup.outputs.docs-only == 'true' }} + uses: ./.github/workflows/pipeline-electron-docs-only.yml + permissions: + contents: read + with: + container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}' + secrets: inherit + + # Checkout Jobs + checkout-macos: + needs: setup + if: ${{ needs.setup.outputs.src == 'true' && !inputs.skip-macos}} + runs-on: electron-arc-centralus-linux-amd64-32core + permissions: + contents: read + container: + image: ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }} + options: --user root + volumes: + - /mnt/cross-instance-cache:/mnt/cross-instance-cache + - /var/run/sas:/var/run/sas + env: + CHROMIUM_GIT_COOKIE: ${{ secrets.CHROMIUM_GIT_COOKIE }} + GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac' + outputs: + build-image-sha: ${{ needs.setup.outputs.build-image-sha }} + steps: + - name: Checkout Electron + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + path: src/electron + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + - name: Checkout & Sync & Save + uses: ./src/electron/.github/actions/checkout + with: + generate-sas-token: 'true' + target-platform: macos + + checkout-linux: + needs: setup + if: ${{ !inputs.skip-linux}} + runs-on: electron-arc-centralus-linux-amd64-32core + permissions: + contents: read + container: + image: ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }} + options: --user root + volumes: + - /mnt/cross-instance-cache:/mnt/cross-instance-cache + - /var/run/sas:/var/run/sas + env: + CHROMIUM_GIT_COOKIE: ${{ secrets.CHROMIUM_GIT_COOKIE }} + DD_API_KEY: ${{ secrets.DD_API_KEY }} + GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' + PATCH_UP_APP_CREDS: ${{ secrets.PATCH_UP_APP_CREDS }} + outputs: + build-image-sha: ${{ needs.setup.outputs.build-image-sha}} + steps: + - name: Checkout Electron + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + path: src/electron + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + - name: Checkout & Sync & Save + uses: ./src/electron/.github/actions/checkout + with: + target-platform: linux + + checkout-windows: + needs: setup + if: ${{ needs.setup.outputs.src == 'true' && !inputs.skip-windows }} + runs-on: electron-arc-centralus-linux-amd64-32core + permissions: + contents: read + container: + image: ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }} + options: --user root --device /dev/fuse --cap-add SYS_ADMIN + volumes: + - /mnt/win-cache:/mnt/win-cache + - /var/run/sas:/var/run/sas + env: + CHROMIUM_GIT_COOKIE: ${{ secrets.CHROMIUM_GIT_COOKIE }} + CHROMIUM_GIT_COOKIE_WINDOWS_STRING: ${{ secrets.CHROMIUM_GIT_COOKIE_WINDOWS_STRING }} + GCLIENT_EXTRA_ARGS: '--custom-var=checkout_win=True' + TARGET_OS: 'win' + ELECTRON_DEPOT_TOOLS_WIN_TOOLCHAIN: '1' + outputs: + build-image-sha: ${{ needs.setup.outputs.build-image-sha}} + steps: + - name: Checkout Electron + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + path: src/electron + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + - name: Checkout & Sync & Save + uses: ./src/electron/.github/actions/checkout + with: + generate-sas-token: 'true' + target-platform: win + + # Build a patched siso binary for Windows CI in parallel with checkout-windows. + # The Windows build jobs download the resulting artifact and use it via SISO_PATH. + build-siso-windows: + needs: setup + if: ${{ needs.setup.outputs.src == 'true' && !inputs.skip-windows }} + uses: ./.github/workflows/pipeline-segment-build-siso-windows.yml + permissions: + contents: read + + # GN Check Jobs + macos-gn-check: + uses: ./.github/workflows/pipeline-segment-electron-gn-check.yml + permissions: + contents: read + needs: checkout-macos + with: + target-platform: macos + target-archs: x64 arm64 + check-runs-on: macos-15 + gn-build-type: testing + secrets: inherit + + linux-gn-check: + uses: ./.github/workflows/pipeline-segment-electron-gn-check.yml + permissions: + contents: read + needs: checkout-linux + if: ${{ needs.setup.outputs.src == 'true' }} + with: + target-platform: linux + target-archs: x64 arm arm64 + check-runs-on: electron-arc-centralus-linux-amd64-8core + check-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}' + gn-build-type: testing + secrets: inherit + + windows-gn-check: + uses: ./.github/workflows/pipeline-segment-electron-gn-check.yml + permissions: + contents: read + needs: checkout-windows + with: + target-platform: win + target-archs: x64 x86 arm64 + check-runs-on: electron-arc-centralus-linux-amd64-8core + check-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-windows.outputs.build-image-sha }}","options":"--user root --device /dev/fuse --cap-add SYS_ADMIN","volumes":["/mnt/win-cache:/mnt/win-cache"]}' + gn-build-type: testing + secrets: inherit + + # Build Jobs - These cascade into testing jobs + macos-x64: + permissions: + contents: read + issues: read + pull-requests: read + uses: ./.github/workflows/pipeline-electron-build-and-test.yml + needs: checkout-macos + with: + build-runs-on: macos-15-xlarge + test-runs-on: macos-15-large + target-platform: macos + target-arch: x64 + is-release: false + gn-build-type: testing + generate-symbols: false + upload-to-storage: '0' + enable-ssh: ${{ inputs.enable-ssh || false }} + secrets: inherit + + macos-arm64: + permissions: + contents: read + issues: read + pull-requests: read + uses: ./.github/workflows/pipeline-electron-build-and-tidy-and-test.yml + needs: checkout-macos + with: + build-runs-on: macos-15-xlarge + clang-tidy-runs-on: macos-15-large + test-runs-on: macos-15 + target-platform: macos + target-arch: arm64 + is-release: false + gn-build-type: testing + generate-symbols: false + upload-to-storage: '0' + enable-ssh: ${{ inputs.enable-ssh || false }} + secrets: inherit + + linux-x64: + permissions: + contents: read + issues: read + pull-requests: read + uses: ./.github/workflows/pipeline-electron-build-and-tidy-and-test-and-nan.yml + needs: checkout-linux + if: ${{ needs.setup.outputs.src == 'true' }} + with: + build-runs-on: electron-arc-centralus-linux-amd64-32core + clang-tidy-runs-on: electron-arc-centralus-linux-amd64-8core + test-runs-on: electron-arc-centralus-linux-amd64-4core + build-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}' + clang-tidy-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}' + test-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root --privileged --init"}' + target-platform: linux + target-arch: x64 + is-release: false + gn-build-type: testing + generate-symbols: false + upload-to-storage: '0' + secrets: inherit + + linux-x64-asan: + permissions: + contents: read + issues: read + pull-requests: read + uses: ./.github/workflows/pipeline-electron-build-and-test.yml + needs: checkout-linux + if: ${{ needs.setup.outputs.src == 'true' }} + with: + build-runs-on: electron-arc-centralus-linux-amd64-32core + test-runs-on: electron-arc-centralus-linux-amd64-4core + build-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}' + test-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root --privileged --init"}' + target-platform: linux + target-arch: x64 + is-release: false + gn-build-type: testing + generate-symbols: false + upload-to-storage: '0' + is-asan: true + secrets: inherit + + linux-arm: + permissions: + contents: read + issues: read + pull-requests: read + uses: ./.github/workflows/pipeline-electron-build-and-test.yml + needs: checkout-linux + if: ${{ needs.setup.outputs.src == 'true' }} + with: + build-runs-on: electron-arc-centralus-linux-amd64-32core + test-runs-on: electron-arc-centralus-linux-arm64-4core + build-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}' + test-container: '{"image":"ghcr.io/electron/test:arm32v7-${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root --privileged --init --memory=12g","volumes":["/home/runner/externals:/mnt/runner-externals"]}' + target-platform: linux + target-arch: arm + is-release: false + gn-build-type: testing + generate-symbols: false + upload-to-storage: '0' + secrets: inherit + + linux-arm64: + permissions: + contents: read + issues: read + pull-requests: read + uses: ./.github/workflows/pipeline-electron-build-and-test.yml + needs: checkout-linux + if: ${{ needs.setup.outputs.src == 'true' }} + with: + build-runs-on: electron-arc-centralus-linux-amd64-32core + test-runs-on: ubuntu-22.04-arm + build-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}' + test-container: '{"image":"ghcr.io/electron/test:arm64v8-${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root --privileged --init"}' + target-platform: linux + target-arch: arm64 + is-release: false + gn-build-type: testing + generate-symbols: false + upload-to-storage: '0' + secrets: inherit + + test-linux-arm64-64k: + uses: ./.github/workflows/pipeline-segment-electron-test-64k.yml + permissions: + contents: read + issues: read + pull-requests: read + needs: [checkout-linux, linux-arm64] + with: + test-runs-on: ubuntu-22.04-arm + test-container: '{"image":"ghcr.io/electron/test:arm64v8-${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root --privileged --init"}' + secrets: inherit + + windows-x64: + permissions: + contents: read + issues: read + pull-requests: read + uses: ./.github/workflows/pipeline-electron-build-and-tidy-and-test.yml + needs: [checkout-windows, build-siso-windows] + if: ${{ needs.setup.outputs.src == 'true' && !inputs.skip-windows }} + with: + build-runs-on: electron-arc-centralus-windows-amd64-32core + clang-tidy-runs-on: electron-arc-centralus-linux-amd64-8core + test-runs-on: windows-latest + clang-tidy-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-windows.outputs.build-image-sha }}","options":"--user root --device /dev/fuse --cap-add SYS_ADMIN","volumes":["/mnt/win-cache:/mnt/win-cache"]}' + target-platform: win + target-arch: x64 + is-release: false + gn-build-type: testing + generate-symbols: false + upload-to-storage: '0' + secrets: inherit + + windows-x86: + permissions: + contents: read + issues: read + pull-requests: read + uses: ./.github/workflows/pipeline-electron-build-and-test.yml + needs: [checkout-windows, build-siso-windows] + if: ${{ needs.setup.outputs.src == 'true' && !inputs.skip-windows }} + with: + build-runs-on: electron-arc-centralus-windows-amd64-32core + test-runs-on: windows-latest + target-platform: win + target-arch: x86 + is-release: false + gn-build-type: testing + generate-symbols: false + upload-to-storage: '0' + secrets: inherit + + windows-arm64: + permissions: + contents: read + issues: read + pull-requests: read + uses: ./.github/workflows/pipeline-electron-build-and-test.yml + needs: [checkout-windows, build-siso-windows] + if: ${{ needs.setup.outputs.src == 'true' && !inputs.skip-windows }} + with: + build-runs-on: electron-arc-centralus-windows-amd64-32core + test-runs-on: windows-11-arm + target-platform: win + target-arch: arm64 + is-release: false + gn-build-type: testing + generate-symbols: false + upload-to-storage: '0' + secrets: inherit + + gha-done: + name: GitHub Actions Completed + runs-on: ubuntu-latest + permissions: + contents: read + needs: [docs-only, macos-x64, macos-arm64, linux-x64, linux-x64-asan, linux-arm, linux-arm64, build-siso-windows, windows-x64, windows-x86, windows-arm64] + if: always() && github.repository == 'electron/electron' + steps: + - name: Fail if any needed job failed or was cancelled + if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') + run: exit 1 + - name: GitHub Actions Jobs Done + run: | + echo "All GitHub Actions Jobs are done" diff --git a/.github/workflows/clean-orphaned-cache-uploads.yml b/.github/workflows/clean-orphaned-cache-uploads.yml new file mode 100644 index 0000000000000..28b445fc50b78 --- /dev/null +++ b/.github/workflows/clean-orphaned-cache-uploads.yml @@ -0,0 +1,45 @@ +name: Clean Orphaned Cache Uploads + +# Description: +# Sweeps orphaned in-flight upload temp files left on the src-cache volumes +# by checkout/action.yml when its cp-to-share step dies before the rename. +# A successful upload finishes in minutes, so anything older than 4h is dead. + +on: + schedule: + - cron: "0 */4 * * *" + workflow_dispatch: + +permissions: {} + +jobs: + setup: + if: github.repository == 'electron/electron' + runs-on: ubuntu-slim + permissions: + contents: read + outputs: + build-image-sha: ${{ steps.build-image-sha.outputs.build-image-sha }} + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + - name: Set Build Image SHA + id: build-image-sha + uses: ./.github/actions/build-image-sha + + clean-orphaned-uploads: + needs: setup + runs-on: electron-arc-centralus-linux-amd64-32core + permissions: + contents: read + container: + image: ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }} + options: --user root + volumes: + - /mnt/cross-instance-cache:/mnt/cross-instance-cache + - /mnt/win-cache:/mnt/win-cache + steps: + - name: Remove Orphaned Upload Temp Files + shell: bash + run: | + find /mnt/cross-instance-cache -maxdepth 1 -type f -name '*.tar.upload-*' -mmin +240 -print -delete + find /mnt/win-cache -maxdepth 1 -type f -name '*.tar.upload-*' -mmin +240 -print -delete diff --git a/.github/workflows/clean-src-cache.yml b/.github/workflows/clean-src-cache.yml new file mode 100644 index 0000000000000..35a3641d7b332 --- /dev/null +++ b/.github/workflows/clean-src-cache.yml @@ -0,0 +1,168 @@ +name: Clean Source Cache + +# Description: +# This workflow cleans up the source cache on the cross-instance cache volume +# to free up space. It runs daily at midnight and clears files older than 15 days. + +on: + schedule: + - cron: "0 0 * * *" + workflow_dispatch: + +permissions: {} + +jobs: + setup: + if: github.repository == 'electron/electron' + runs-on: ubuntu-slim + permissions: + contents: read + outputs: + build-image-sha: ${{ steps.build-image-sha.outputs.build-image-sha }} + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + - name: Set Build Image SHA + id: build-image-sha + uses: ./.github/actions/build-image-sha + + clean-src-cache: + needs: setup + runs-on: electron-arc-centralus-linux-amd64-32core + permissions: + contents: read + env: + DD_API_KEY: ${{ secrets.DD_API_KEY }} + container: + image: ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }} + options: --user root + volumes: + - /mnt/cross-instance-cache:/mnt/cross-instance-cache + - /mnt/win-cache:/mnt/win-cache + steps: + - name: Get Disk Space Before Cleanup + id: disk-before + shell: bash + run: | + echo "Disk space before cleanup:" + df -h /mnt/cross-instance-cache + df -h /mnt/win-cache + CROSS_FREE_BEFORE=$(df -k /mnt/cross-instance-cache | tail -1 | awk '{print $4}') + CROSS_TOTAL=$(df -k /mnt/cross-instance-cache | tail -1 | awk '{print $2}') + WIN_FREE_BEFORE=$(df -k /mnt/win-cache | tail -1 | awk '{print $4}') + WIN_TOTAL=$(df -k /mnt/win-cache | tail -1 | awk '{print $2}') + echo "cross_free_kb=$CROSS_FREE_BEFORE" >> $GITHUB_OUTPUT + echo "cross_total_kb=$CROSS_TOTAL" >> $GITHUB_OUTPUT + echo "win_free_kb=$WIN_FREE_BEFORE" >> $GITHUB_OUTPUT + echo "win_total_kb=$WIN_TOTAL" >> $GITHUB_OUTPUT + + - name: Cleanup Source Cache + shell: bash + run: | + find /mnt/cross-instance-cache -type f -mtime +15 -delete + find /mnt/win-cache -type f -mtime +15 -delete + + - name: Get Disk Space After Cleanup + id: disk-after + shell: bash + run: | + echo "Disk space after cleanup:" + df -h /mnt/cross-instance-cache + df -h /mnt/win-cache + CROSS_FREE_AFTER=$(df -k /mnt/cross-instance-cache | tail -1 | awk '{print $4}') + WIN_FREE_AFTER=$(df -k /mnt/win-cache | tail -1 | awk '{print $4}') + echo "cross_free_kb=$CROSS_FREE_AFTER" >> $GITHUB_OUTPUT + echo "win_free_kb=$WIN_FREE_AFTER" >> $GITHUB_OUTPUT + + - name: Log Disk Space to Datadog + if: ${{ env.DD_API_KEY != '' }} + shell: bash + env: + CROSS_FREE_BEFORE: ${{ steps.disk-before.outputs.cross_free_kb }} + CROSS_FREE_AFTER: ${{ steps.disk-after.outputs.cross_free_kb }} + CROSS_TOTAL: ${{ steps.disk-before.outputs.cross_total_kb }} + WIN_FREE_BEFORE: ${{ steps.disk-before.outputs.win_free_kb }} + WIN_FREE_AFTER: ${{ steps.disk-after.outputs.win_free_kb }} + WIN_TOTAL: ${{ steps.disk-before.outputs.win_total_kb }} + run: | + TIMESTAMP=$(date +%s) + + CROSS_FREE_BEFORE_GB=$(awk "BEGIN {printf \"%.2f\", $CROSS_FREE_BEFORE / 1024 / 1024}") + CROSS_FREE_AFTER_GB=$(awk "BEGIN {printf \"%.2f\", $CROSS_FREE_AFTER / 1024 / 1024}") + CROSS_FREED_GB=$(awk "BEGIN {printf \"%.2f\", ($CROSS_FREE_AFTER - $CROSS_FREE_BEFORE) / 1024 / 1024}") + CROSS_TOTAL_GB=$(awk "BEGIN {printf \"%.2f\", $CROSS_TOTAL / 1024 / 1024}") + + WIN_FREE_BEFORE_GB=$(awk "BEGIN {printf \"%.2f\", $WIN_FREE_BEFORE / 1024 / 1024}") + WIN_FREE_AFTER_GB=$(awk "BEGIN {printf \"%.2f\", $WIN_FREE_AFTER / 1024 / 1024}") + WIN_FREED_GB=$(awk "BEGIN {printf \"%.2f\", ($WIN_FREE_AFTER - $WIN_FREE_BEFORE) / 1024 / 1024}") + WIN_TOTAL_GB=$(awk "BEGIN {printf \"%.2f\", $WIN_TOTAL / 1024 / 1024}") + + echo "cross-instance-cache: free before=${CROSS_FREE_BEFORE_GB}GB, after=${CROSS_FREE_AFTER_GB}GB, freed=${CROSS_FREED_GB}GB, total=${CROSS_TOTAL_GB}GB" + echo "win-cache: free before=${WIN_FREE_BEFORE_GB}GB, after=${WIN_FREE_AFTER_GB}GB, freed=${WIN_FREED_GB}GB, total=${WIN_TOTAL_GB}GB" + + curl -s -X POST "https://api.datadoghq.com/api/v2/series" \ + -H "Content-Type: application/json" \ + -H "DD-API-KEY: ${DD_API_KEY}" \ + -d @- << EOF + { + "series": [ + { + "metric": "electron.src_cache.disk.free_space_before_cleanup_gb", + "points": [{"timestamp": ${TIMESTAMP}, "value": ${CROSS_FREE_BEFORE_GB}}], + "type": 3, + "unit": "gigabyte", + "tags": ["volume:cross-instance-cache", "platform:linux"] + }, + { + "metric": "electron.src_cache.disk.free_space_after_cleanup_gb", + "points": [{"timestamp": ${TIMESTAMP}, "value": ${CROSS_FREE_AFTER_GB}}], + "type": 3, + "unit": "gigabyte", + "tags": ["volume:cross-instance-cache", "platform:linux"] + }, + { + "metric": "electron.src_cache.disk.space_freed_gb", + "points": [{"timestamp": ${TIMESTAMP}, "value": ${CROSS_FREED_GB}}], + "type": 3, + "unit": "gigabyte", + "tags": ["volume:cross-instance-cache", "platform:linux"] + }, + { + "metric": "electron.src_cache.disk.total_space_gb", + "points": [{"timestamp": ${TIMESTAMP}, "value": ${CROSS_TOTAL_GB}}], + "type": 3, + "unit": "gigabyte", + "tags": ["volume:cross-instance-cache", "platform:linux"] + }, + { + "metric": "electron.src_cache.disk.free_space_before_cleanup_gb", + "points": [{"timestamp": ${TIMESTAMP}, "value": ${WIN_FREE_BEFORE_GB}}], + "type": 3, + "unit": "gigabyte", + "tags": ["volume:win-cache", "platform:linux"] + }, + { + "metric": "electron.src_cache.disk.free_space_after_cleanup_gb", + "points": [{"timestamp": ${TIMESTAMP}, "value": ${WIN_FREE_AFTER_GB}}], + "type": 3, + "unit": "gigabyte", + "tags": ["volume:win-cache", "platform:linux"] + }, + { + "metric": "electron.src_cache.disk.space_freed_gb", + "points": [{"timestamp": ${TIMESTAMP}, "value": ${WIN_FREED_GB}}], + "type": 3, + "unit": "gigabyte", + "tags": ["volume:win-cache", "platform:linux"] + }, + { + "metric": "electron.src_cache.disk.total_space_gb", + "points": [{"timestamp": ${TIMESTAMP}, "value": ${WIN_TOTAL_GB}}], + "type": 3, + "unit": "gigabyte", + "tags": ["volume:win-cache", "platform:linux"] + } + ] + } + EOF + + echo "Disk space metrics logged to Datadog" diff --git a/.github/workflows/issue-commented.yml b/.github/workflows/issue-commented.yml new file mode 100644 index 0000000000000..08f289deb134c --- /dev/null +++ b/.github/workflows/issue-commented.yml @@ -0,0 +1,88 @@ +name: Issue / Pull Request Commented + +on: + issue_comment: + types: + - created + +permissions: {} + +jobs: + blocked-issue-commented: + name: Remove blocked/{need-info,need-repro} on comment + if: ${{ !github.event.issue.pull_request && (contains(github.event.issue.labels.*.name, 'blocked/need-repro') || contains(github.event.issue.labels.*.name, 'blocked/need-info ❌')) && github.event.comment.user.type != 'Bot' }} + runs-on: ubuntu-slim + steps: + - name: Get author association + id: get-author-association + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: &get-author-association | + AUTHOR_ASSOCIATION=$(gh api /repos/electron/electron/issues/comments/${{ github.event.comment.id }} --jq '.author_association') + echo "author_association=$AUTHOR_ASSOCIATION" >> "$GITHUB_OUTPUT" + - name: Generate GitHub App token + uses: electron/github-app-auth-action@e14e47722ed120360649d0789e25b9baece12725 # v2.0.0 + if: ${{ !contains(fromJSON('["MEMBER", "OWNER", "COLLABORATOR"]'), steps.get-author-association.outputs.author_association) }} + id: generate-token + with: + creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }} + - name: Remove label + if: ${{ !contains(fromJSON('["MEMBER", "OWNER", "COLLABORATOR"]'), steps.get-author-association.outputs.author_association) }} + env: + GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }} + ISSUE_URL: ${{ github.event.issue.html_url }} + run: | + gh issue edit $ISSUE_URL --remove-label 'blocked/need-repro','blocked/need-info ❌' + + pr-reviewer-requested: + name: Maintainer requested reviewer on PR + if: ${{ github.event.issue.pull_request && startsWith(github.event.comment.body, '/request-review') && github.event.comment.user.type != 'Bot' }} + runs-on: ubuntu-slim + steps: + - name: Get author association + id: get-author-association + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: *get-author-association + - name: Generate GitHub App token + uses: electron/github-app-auth-action@e14e47722ed120360649d0789e25b9baece12725 # v2.0.0 + if: ${{ contains(fromJSON('["MEMBER", "OWNER"]'), steps.get-author-association.outputs.author_association) }} + id: generate-token + with: + creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }} + - name: Request reviewer + if: ${{ contains(fromJSON('["MEMBER", "OWNER"]'), steps.get-author-association.outputs.author_association) }} + env: + GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }} + PR_URL: ${{ github.event.issue.html_url }} + COMMENT_BODY: ${{ github.event.comment.body }} + run: | + RAW=$(echo "$COMMENT_BODY" | head -n 1 | sed 's|/request-review\s*||' | xargs) + + if [ -z "$RAW" ]; then + echo "::warning::No username provided. Usage: /request-review [,,...]" + exit 0 + fi + + IFS=',' read -ra USERS <<< "$RAW" + for USER in "${USERS[@]}"; do + NAME=$(echo "$USER" | sed 's/@//g' | xargs) + if [ -z "$NAME" ]; then + continue + fi + + # Strip "electron/" prefix if present to get the bare name + BARE_NAME=$(echo "$NAME" | sed 's|^electron/||') + + # If the original name contained "electron/" or looks like a team slug, treat as team + if [ "$NAME" != "$BARE_NAME" ]; then + gh pr edit $PR_URL --add-reviewer "electron/$BARE_NAME" + else + if ! gh api /orgs/electron/public_members/$BARE_NAME --silent > /dev/null 2>&1; then + echo "::warning::$BARE_NAME is not a public member of the electron organization." + continue + fi + + gh pr edit $PR_URL --add-reviewer "$BARE_NAME" + fi + done diff --git a/.github/workflows/issue-labeled.yml b/.github/workflows/issue-labeled.yml new file mode 100644 index 0000000000000..53e38954c7c37 --- /dev/null +++ b/.github/workflows/issue-labeled.yml @@ -0,0 +1,92 @@ +name: Issue Labeled + +on: + issues: + types: [labeled] + +permissions: {} + +jobs: + issue-labeled-with-status: + name: status/{confirmed,reviewed} label added + if: github.event.label.name == 'status/confirmed' || github.event.label.name == 'status/reviewed' + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Generate GitHub App token + uses: electron/github-app-auth-action@e14e47722ed120360649d0789e25b9baece12725 # v2.0.0 + id: generate-token + with: + creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }} + org: electron + - name: Set status + uses: dsanders11/project-actions/edit-item@4b06452b0128cf601dac14399aa668a8eed2d684 # v2.0.1 + with: + token: ${{ steps.generate-token.outputs.token }} + project-number: 90 + field: Status + field-value: ✅ Triaged + fail-if-item-not-found: false + issue-labeled-blocked: + name: blocked/* label added + if: startsWith(github.event.label.name, 'blocked/') + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Generate GitHub App token + uses: electron/github-app-auth-action@e14e47722ed120360649d0789e25b9baece12725 # v2.0.0 + id: generate-token + with: + creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }} + org: electron + - name: Set status + uses: dsanders11/project-actions/edit-item@4b06452b0128cf601dac14399aa668a8eed2d684 # v2.0.1 + with: + token: ${{ steps.generate-token.outputs.token }} + project-number: 90 + field: Status + field-value: 🛑 Blocked + fail-if-item-not-found: false + issue-labeled-blocked-need-repro: + name: blocked/need-repro label added + if: github.event.label.name == 'blocked/need-repro' + permissions: + issues: write # for actions-cool/issues-helper to update issues + runs-on: ubuntu-latest + steps: + - name: Check if comment needed + id: check-for-comment + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: electron/electron + ISSUE_NUMBER: ${{ github.event.issue.number }} + run: | + set -eo pipefail + COMMENT_COUNT=$(gh issue view "$ISSUE_NUMBER" --comments --json comments | jq '[ .comments[] | select(.author.login == "electron-issue-triage" or .authorAssociation == "OWNER" or .authorAssociation == "MEMBER") | select(.body | startswith("")) ] | length') + if [[ $COMMENT_COUNT -eq 0 ]]; then + echo "SHOULD_COMMENT=1" >> "$GITHUB_OUTPUT" + fi + - name: Generate GitHub App token + if: ${{ steps.check-for-comment.outputs.SHOULD_COMMENT }} + uses: electron/github-app-auth-action@e14e47722ed120360649d0789e25b9baece12725 # v2.0.0 + id: generate-token + with: + creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }} + - name: Create comment + if: ${{ steps.check-for-comment.outputs.SHOULD_COMMENT }} + uses: actions-cool/issues-helper@200c78641dbf33838311e5a1e0c31bbdb92d7cf0 # v3.8.0 + with: + actions: 'create-comment' + token: ${{ steps.generate-token.outputs.token }} + body: | + + + Hello @${{ github.event.issue.user.login }}. Thanks for reporting this and helping to make Electron better! + + Would it be possible for you to make a standalone testcase with only the code necessary to reproduce the issue? For example, [Electron Fiddle](https://www.electronjs.org/fiddle) is a great tool for making small test cases and makes it easy to publish your test case to a [gist](https://gist.github.com) that Electron maintainers can use. + + Stand-alone test cases make fixing issues go more smoothly: it ensure everyone's looking at the same issue, it removes all unnecessary variables from the equation, and it can also provide the basis for automated regression tests. + + Now adding the https://github.com/electron/electron/labels/blocked%2Fneed-repro label for this reason. After you make a test case, please link to it in a followup comment. This issue will be closed in 10 days if the above is not addressed. diff --git a/.github/workflows/issue-opened.yml b/.github/workflows/issue-opened.yml new file mode 100644 index 0000000000000..9b6a1a9dd03b0 --- /dev/null +++ b/.github/workflows/issue-opened.yml @@ -0,0 +1,160 @@ +name: Issue Opened + +on: + issues: + types: + - opened + +permissions: {} + +jobs: + add-to-issue-triage: + if: ${{ contains(github.event.issue.labels.*.name, 'bug :beetle:') }} + runs-on: ubuntu-latest + permissions: {} + steps: + - name: Generate GitHub App token + uses: electron/github-app-auth-action@e14e47722ed120360649d0789e25b9baece12725 # v2.0.0 + id: generate-token + with: + creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }} + org: electron + - name: Add to Issue Triage + uses: dsanders11/project-actions/add-item@4b06452b0128cf601dac14399aa668a8eed2d684 # v2.0.1 + with: + field: Reporter + field-value: ${{ github.event.issue.user.login }} + project-number: 90 + token: ${{ steps.generate-token.outputs.token }} + set-labels: + if: ${{ contains(github.event.issue.labels.*.name, 'bug :beetle:') }} + runs-on: ubuntu-latest + permissions: {} + steps: + - name: Generate GitHub App token + uses: electron/github-app-auth-action@e14e47722ed120360649d0789e25b9baece12725 # v2.0.0 + id: generate-token + with: + creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }} + org: electron + - name: Sparse checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + sparse-checkout: | + . + .github + .yarn + - run: yarn workspaces focus @electron/gha-workflows + - name: Add labels + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + id: add-labels + env: + ISSUE_BODY: ${{ github.event.issue.body }} + with: + github-token: ${{ steps.generate-token.outputs.token }} + script: | + const { chdir } = require('node:process'); + chdir('${{ github.workspace }}/.github/workflows'); + + const { ElectronVersions } = require('@electron/fiddle-core'); + const { fromMarkdown } = require('mdast-util-from-markdown'); + const { select } = require('unist-util-select'); + const semver = require('semver'); + + const [ owner, repo ] = '${{ github.repository }}'.split('/'); + const issue_number = ${{ github.event.issue.number }}; + + const tree = fromMarkdown(process.env.ISSUE_BODY); + + const labels = []; + + const electronVersion = select('heading:has(> text[value="Electron Version"]) + paragraph > text', tree)?.value.trim(); + if (electronVersion !== undefined) { + // It's possible for multiple versions to be listed - + // for now check for comma or space separated version. + const versions = electronVersion.split(/, | /); + let hasSupportedVersion = false; + + for (const version of versions) { + const major = semver.coerce(version, { loose: true })?.major; + if (major) { + const versionLabel = `${major}-x-y`; + let labelExists = false; + + try { + await github.rest.issues.getLabel({ + owner, + repo, + name: versionLabel, + }); + labelExists = true; + } catch {} + + const electronVersions = await ElectronVersions.create(undefined, { ignoreCache: true }); + const validVersions = [...electronVersions.supportedMajors, ...electronVersions.prereleaseMajors]; + + if (validVersions.includes(major)) { + hasSupportedVersion = true; + if (labelExists) { + labels.push(versionLabel); + } + } + } + } + + if (!hasSupportedVersion) { + core.setOutput('unsupportedMajor', true); + labels.push('blocked/need-info ❌'); + } + } + + const operatingSystems = select('heading:has(> text[value="What operating system(s) are you using?"]) + paragraph > text', tree)?.value.trim().split(', '); + const platformLabels = new Set(); + for (const operatingSystem of (operatingSystems ?? [])) { + switch (operatingSystem) { + case 'Windows': + platformLabels.add('platform/windows'); + break; + case 'macOS': + platformLabels.add('platform/macOS'); + break; + case 'Ubuntu': + case 'Other Linux': + platformLabels.add('platform/linux'); + break; + } + } + + if (platformLabels.size === 3) { + labels.push('platform/all'); + } else { + labels.push(...platformLabels); + } + + const gistUrl = select('heading:has(> text[value="Testcase Gist URL"]) + paragraph > text', tree)?.value.trim(); + if (gistUrl !== undefined && gistUrl.startsWith('https://gist.github.com/')) { + labels.push('has-repro-gist'); + } + + if (labels.length) { + await github.rest.issues.addLabels({ + owner, + repo, + issue_number, + labels, + }); + } + - name: Create unsupported major comment + if: ${{ steps.add-labels.outputs.unsupportedMajor }} + uses: actions-cool/issues-helper@200c78641dbf33838311e5a1e0c31bbdb92d7cf0 # v3.8.0 + with: + actions: 'create-comment' + token: ${{ steps.generate-token.outputs.token }} + body: | + + + Hello @${{ github.event.issue.user.login }}. Thanks for reporting this and helping to make Electron better! + + The version of Electron reported in this issue has reached end-of-life and is [no longer supported](https://www.electronjs.org/docs/latest/tutorial/electron-timelines#timeline). If you're still experiencing this issue on a [supported version](https://www.electronjs.org/releases/stable) of Electron, please update this issue to reflect that version of Electron. + + Now adding the https://github.com/electron/electron/labels/blocked%2Fneed-info%20%E2%9D%8C label for this reason. This issue will be closed in 10 days if the above is not addressed. diff --git a/.github/workflows/issue-transferred.yml b/.github/workflows/issue-transferred.yml new file mode 100644 index 0000000000000..45345dffa57fa --- /dev/null +++ b/.github/workflows/issue-transferred.yml @@ -0,0 +1,28 @@ +name: Issue Transferred + +on: + issues: + types: [transferred] + +permissions: {} + +jobs: + issue-transferred: + name: Issue Transferred + runs-on: ubuntu-latest + permissions: {} + if: ${{ !github.event.changes.new_repository.private }} + steps: + - name: Generate GitHub App token + uses: electron/github-app-auth-action@e14e47722ed120360649d0789e25b9baece12725 # v2.0.0 + id: generate-token + with: + creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }} + org: electron + - name: Remove from issue triage + uses: dsanders11/project-actions/delete-item@4b06452b0128cf601dac14399aa668a8eed2d684 # v2.0.1 + with: + token: ${{ steps.generate-token.outputs.token }} + project-number: 90 + item: ${{ github.event.changes.new_issue.html_url }} + fail-if-item-not-found: false diff --git a/.github/workflows/issue-unlabeled.yml b/.github/workflows/issue-unlabeled.yml new file mode 100644 index 0000000000000..740a23e80fecb --- /dev/null +++ b/.github/workflows/issue-unlabeled.yml @@ -0,0 +1,42 @@ +name: Issue Unlabeled + +on: + issues: + types: [unlabeled] + +permissions: {} + +jobs: + issue-unlabeled-blocked: + name: All blocked/* labels removed + if: startsWith(github.event.label.name, 'blocked/') && github.event.issue.state == 'open' + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Check for any blocked labels + id: check-for-blocked-labels + env: + LABELS_JSON: ${{ toJSON(github.event.issue.labels.*.name) }} + run: | + set -eo pipefail + BLOCKED_LABEL_COUNT=$(echo "$LABELS_JSON" | jq '[ .[] | select(startswith("blocked/")) ] | length') + if [[ $BLOCKED_LABEL_COUNT -eq 0 ]]; then + echo "NOT_BLOCKED=1" >> "$GITHUB_OUTPUT" + fi + - name: Generate GitHub App token + if: ${{ steps.check-for-blocked-labels.outputs.NOT_BLOCKED }} + uses: electron/github-app-auth-action@e14e47722ed120360649d0789e25b9baece12725 # v2.0.0 + id: generate-token + with: + creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }} + org: electron + - name: Set status + if: ${{ steps.check-for-blocked-labels.outputs.NOT_BLOCKED }} + uses: dsanders11/project-actions/edit-item@4b06452b0128cf601dac14399aa668a8eed2d684 # v2.0.1 + with: + token: ${{ steps.generate-token.outputs.token }} + project-number: 90 + field: Status + field-value: 📥 Was Blocked + fail-if-item-not-found: false diff --git a/.github/workflows/linux-publish.yml b/.github/workflows/linux-publish.yml new file mode 100644 index 0000000000000..692ff550ed5ad --- /dev/null +++ b/.github/workflows/linux-publish.yml @@ -0,0 +1,120 @@ +name: Publish Linux + +on: + workflow_dispatch: + inputs: + build-image-sha: + type: string + description: 'SHA for electron/build image' + default: '' + required: false + upload-to-storage: + description: 'Uploads to Azure storage' + required: false + default: '1' + type: string + run-linux-publish: + description: 'Run the publish jobs vs just the build jobs' + type: boolean + default: false + +permissions: {} + +jobs: + setup: + if: github.repository == 'electron/electron' + runs-on: ubuntu-slim + permissions: + contents: read + outputs: + build-image-sha: ${{ steps.build-image-sha.outputs.build-image-sha }} + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + - name: Set Build Image SHA + id: build-image-sha + uses: ./.github/actions/build-image-sha + with: + override: ${{ inputs.build-image-sha }} + + checkout-linux: + needs: setup + runs-on: electron-arc-centralus-linux-amd64-32core + permissions: + contents: read + container: + image: ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }} + options: --user root + volumes: + - /mnt/cross-instance-cache:/mnt/cross-instance-cache + - /var/run/sas:/var/run/sas + env: + CHROMIUM_GIT_COOKIE: ${{ secrets.CHROMIUM_GIT_COOKIE }} + GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' + steps: + - name: Checkout Electron + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + path: src/electron + fetch-depth: 0 + - name: Checkout & Sync & Save + uses: ./src/electron/.github/actions/checkout + + publish-x64: + uses: ./.github/workflows/pipeline-segment-electron-publish.yml + permissions: + artifact-metadata: write + attestations: write + contents: read + id-token: write + needs: [setup, checkout-linux] + with: + environment: production-release + build-runs-on: electron-arc-centralus-linux-amd64-32core + build-container: '{"image":"ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}' + target-platform: linux + target-arch: x64 + is-release: true + gn-build-type: release + generate-symbols: true + upload-to-storage: ${{ inputs.upload-to-storage }} + secrets: inherit + + publish-arm: + uses: ./.github/workflows/pipeline-segment-electron-publish.yml + permissions: + artifact-metadata: write + attestations: write + contents: read + id-token: write + needs: [setup, checkout-linux] + with: + environment: production-release + build-runs-on: electron-arc-centralus-linux-amd64-32core + build-container: '{"image":"ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}' + target-platform: linux + target-arch: arm + is-release: true + gn-build-type: release + generate-symbols: true + upload-to-storage: ${{ inputs.upload-to-storage }} + secrets: inherit + + publish-arm64: + uses: ./.github/workflows/pipeline-segment-electron-publish.yml + permissions: + artifact-metadata: write + attestations: write + contents: read + id-token: write + needs: [setup, checkout-linux] + with: + environment: production-release + build-runs-on: electron-arc-centralus-linux-amd64-32core + build-container: '{"image":"ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}' + target-platform: linux + target-arch: arm64 + is-release: true + gn-build-type: release + generate-symbols: true + upload-to-storage: ${{ inputs.upload-to-storage }} + secrets: inherit diff --git a/.github/workflows/macos-disk-cleanup.yml b/.github/workflows/macos-disk-cleanup.yml new file mode 100644 index 0000000000000..b110170922f44 --- /dev/null +++ b/.github/workflows/macos-disk-cleanup.yml @@ -0,0 +1,105 @@ +name: macOS Disk Space Cleanup + +# Description: +# This workflow runs the disk space reclaimer on macOS runners every night +# and logs disk space metrics to Datadog for monitoring. + +on: + schedule: + - cron: "0 0 * * *" + workflow_dispatch: + +permissions: {} + +jobs: + macos-disk-cleanup: + if: github.repository == 'electron/electron' + strategy: + fail-fast: false + matrix: + runner: + - macos-15 + - macos-15-large + - macos-15-xlarge + runs-on: ${{ matrix.runner }} + permissions: + contents: read + steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + sparse-checkout: | + .github/actions/free-space-macos + sparse-checkout-cone-mode: false + + - name: Get Disk Space Before Cleanup + id: disk-before + shell: bash + run: | + echo "Disk space before cleanup:" + df -h / + FREE_SPACE_BEFORE=$(df -k / | tail -1 | awk '{print $4}') + echo "free_kb=$FREE_SPACE_BEFORE" >> $GITHUB_OUTPUT + + - name: Free Space on macOS + uses: ./.github/actions/free-space-macos + + - name: Get Disk Space After Cleanup + id: disk-after + shell: bash + run: | + echo "Disk space after cleanup:" + df -h / + FREE_SPACE_AFTER=$(df -k / | tail -1 | awk '{print $4}') + echo "free_kb=$FREE_SPACE_AFTER" >> $GITHUB_OUTPUT + + - name: Log Disk Space to Datadog + if: ${{ env.DD_API_KEY != '' }} + shell: bash + env: + DD_API_KEY: ${{ secrets.DD_API_KEY }} + FREE_BEFORE: ${{ steps.disk-before.outputs.free_kb }} + FREE_AFTER: ${{ steps.disk-after.outputs.free_kb }} + MATRIX_RUNNER: ${{ matrix.runner }} + run: | + TIMESTAMP=$(date +%s) + FREE_BEFORE_GB=$(echo "scale=2; $FREE_BEFORE / 1024 / 1024" | bc) + FREE_AFTER_GB=$(echo "scale=2; $FREE_AFTER / 1024 / 1024" | bc) + SPACE_FREED_GB=$(echo "scale=2; ($FREE_AFTER - $FREE_BEFORE) / 1024 / 1024" | bc) + + echo "Free space before: ${FREE_BEFORE_GB}GB" + echo "Free space after: ${FREE_AFTER_GB}GB" + echo "Space freed: ${SPACE_FREED_GB}GB" + + curl -s -X POST "https://api.datadoghq.com/api/v2/series" \ + -H "Content-Type: application/json" \ + -H "DD-API-KEY: ${DD_API_KEY}" \ + -d @- << EOF + { + "series": [ + { + "metric": "electron.macos.disk.free_space_before_cleanup_gb", + "points": [{"timestamp": ${TIMESTAMP}, "value": ${FREE_BEFORE_GB}}], + "type": 3, + "unit": "gigabyte", + "tags": ["runner:${MATRIX_RUNNER}", "platform:macos"] + }, + { + "metric": "electron.macos.disk.free_space_after_cleanup_gb", + "points": [{"timestamp": ${TIMESTAMP}, "value": ${FREE_AFTER_GB}}], + "type": 3, + "unit": "gigabyte", + "tags": ["runner:${MATRIX_RUNNER}", "platform:macos"] + }, + { + "metric": "electron.macos.disk.space_freed_gb", + "points": [{"timestamp": ${TIMESTAMP}, "value": ${SPACE_FREED_GB}}], + "type": 3, + "unit": "gigabyte", + "tags": ["runner:${MATRIX_RUNNER}", "platform:macos"] + } + ] + } + EOF + + echo "Disk space metrics logged to Datadog" diff --git a/.github/workflows/macos-publish.yml b/.github/workflows/macos-publish.yml new file mode 100644 index 0000000000000..f9e6804ea930b --- /dev/null +++ b/.github/workflows/macos-publish.yml @@ -0,0 +1,143 @@ +name: Publish MacOS + +on: + workflow_dispatch: + inputs: + build-image-sha: + type: string + description: 'SHA for electron/build image' + default: '' + required: false + upload-to-storage: + description: 'Uploads to Azure storage' + required: false + default: '1' + type: string + run-macos-publish: + description: 'Run the publish jobs vs just the build jobs' + type: boolean + default: false + +permissions: {} + +jobs: + setup: + if: github.repository == 'electron/electron' + runs-on: ubuntu-slim + permissions: + contents: read + outputs: + build-image-sha: ${{ steps.build-image-sha.outputs.build-image-sha }} + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + - name: Set Build Image SHA + id: build-image-sha + uses: ./.github/actions/build-image-sha + with: + override: ${{ inputs.build-image-sha }} + + checkout-macos: + needs: setup + runs-on: electron-arc-centralus-linux-amd64-32core + permissions: + contents: read + container: + image: ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }} + options: --user root + volumes: + - /mnt/cross-instance-cache:/mnt/cross-instance-cache + - /var/run/sas:/var/run/sas + env: + CHROMIUM_GIT_COOKIE: ${{ secrets.CHROMIUM_GIT_COOKIE }} + GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac' + steps: + - name: Checkout Electron + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + path: src/electron + fetch-depth: 0 + - name: Checkout & Sync & Save + uses: ./src/electron/.github/actions/checkout + with: + generate-sas-token: 'true' + target-platform: macos + + publish-x64-darwin: + uses: ./.github/workflows/pipeline-segment-electron-publish.yml + permissions: + artifact-metadata: write + attestations: write + contents: read + id-token: write + needs: checkout-macos + with: + environment: production-release + build-runs-on: macos-15-xlarge + target-platform: macos + target-arch: x64 + target-variant: darwin + is-release: true + gn-build-type: release + generate-symbols: true + upload-to-storage: ${{ inputs.upload-to-storage }} + secrets: inherit + + publish-x64-mas: + uses: ./.github/workflows/pipeline-segment-electron-publish.yml + permissions: + artifact-metadata: write + attestations: write + contents: read + id-token: write + needs: checkout-macos + with: + environment: production-release + build-runs-on: macos-15-xlarge + target-platform: macos + target-arch: x64 + target-variant: mas + is-release: true + gn-build-type: release + generate-symbols: true + upload-to-storage: ${{ inputs.upload-to-storage }} + secrets: inherit + + publish-arm64-darwin: + uses: ./.github/workflows/pipeline-segment-electron-publish.yml + permissions: + artifact-metadata: write + attestations: write + contents: read + id-token: write + needs: checkout-macos + with: + environment: production-release + build-runs-on: macos-15-xlarge + target-platform: macos + target-arch: arm64 + target-variant: darwin + is-release: true + gn-build-type: release + generate-symbols: true + upload-to-storage: ${{ inputs.upload-to-storage }} + secrets: inherit + + publish-arm64-mas: + uses: ./.github/workflows/pipeline-segment-electron-publish.yml + permissions: + artifact-metadata: write + attestations: write + contents: read + id-token: write + needs: checkout-macos + with: + environment: production-release + build-runs-on: macos-15-xlarge + target-platform: macos + target-arch: arm64 + target-variant: mas + is-release: true + gn-build-type: release + generate-symbols: true + upload-to-storage: ${{ inputs.upload-to-storage }} + secrets: inherit diff --git a/.github/workflows/non-maintainer-dependency-change.yml b/.github/workflows/non-maintainer-dependency-change.yml new file mode 100644 index 0000000000000..e9938d4176e54 --- /dev/null +++ b/.github/workflows/non-maintainer-dependency-change.yml @@ -0,0 +1,71 @@ +name: Check for Disallowed Non-Maintainer Change + +on: + pull_request_target: + paths: + - 'yarn.lock' + - 'spec/yarn.lock' + - '.github/workflows/**' + - '.github/actions/**' + - '.yarn/**' + - '.yarnrc.yml' + +# SECURITY: This workflow uses pull_request_target and has access to secrets. +# Do NOT checkout or run code from the PR head. All code execution must use +# the base branch only. Adding a ref to PR head would expose secrets to +# untrusted code. +permissions: {} + +jobs: + check-for-non-maintainer-dependency-change: + name: Check for disallowed non-maintainer change + if: ${{ github.event.pull_request.user.type != 'Bot' && !github.event.pull_request.draft }} + permissions: + contents: read + pull-requests: write + runs-on: ubuntu-latest + steps: + - name: Get author association + id: get-author-association + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + AUTHOR_ASSOCIATION=$(gh api /repos/electron/electron/pulls/${{ github.event.pull_request.number }} --jq '.author_association') + echo "author_association=$AUTHOR_ASSOCIATION" >> "$GITHUB_OUTPUT" + - name: Check for existing review + id: check-for-review + if: ${{ !contains(fromJSON('["MEMBER", "OWNER"]'), steps.get-author-association.outputs.author_association) }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_URL: ${{ github.event.pull_request.html_url }} + run: | + set -eo pipefail + REVIEW_COUNT=$(gh pr view $PR_URL --json reviews | jq '[ .reviews[] | select(.author.login == "github-actions") | select(.body | startswith("")) ] | length') + if [[ $REVIEW_COUNT -eq 0 ]]; then + echo "SHOULD_REVIEW=1" >> "$GITHUB_OUTPUT" + fi + - name: Request changes + if: ${{ steps.check-for-review.outputs.SHOULD_REVIEW }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_URL: ${{ github.event.pull_request.html_url }} + PR_AUTHOR: ${{ github.event.pull_request.user.login }} + run: | + cat <<'REVIEW_EOF' | sed "s/%AUTHOR%/$PR_AUTHOR/g" | gh pr review $PR_URL -r --body-file=- + + + Hello @%AUTHOR%! It looks like this pull request touches one of our dependency or CI files, and per [our contribution policy](https://github.com/electron/electron/blob/main/CONTRIBUTING.md#dependencies-upgrades-policy) we do not accept these types of changes in PRs. + + To move this PR forward, please: + + 1. Revert the dependency/CI file changes from your branch. (e.g. `yarn.lock`, `.yarn/`, `.yarnrc.yml`, `.github/workflows/`, `.github/actions/`) + 2. Ensure your branch [allows maintainer commits](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork) so a maintainer can push the necessary dependency changes on your behalf. + 3. Leave a comment letting reviewers know the dependency change is still needed. + +
+ For maintainers + + To land this PR, push a verified commit to the contributor's branch with the required dependency/CI changes, then dismiss this review. + +
+ REVIEW_EOF diff --git a/.github/workflows/package.json b/.github/workflows/package.json new file mode 100644 index 0000000000000..0439c28d43612 --- /dev/null +++ b/.github/workflows/package.json @@ -0,0 +1,13 @@ +{ + "name": "@electron/gha-workflows", + "version": "0.0.0-development", + "private": true, + "type": "module", + "dependencies": { + "@actions/cache": "^4.0.3", + "@electron/fiddle-core": "^2.0.1", + "mdast-util-from-markdown": "^2.0.0", + "semver": "^7.7.2", + "unist-util-select": "^5.1.0" + } +} diff --git a/.github/workflows/pipeline-electron-build-and-test-and-nan.yml b/.github/workflows/pipeline-electron-build-and-test-and-nan.yml new file mode 100644 index 0000000000000..8ba78ac23fb3b --- /dev/null +++ b/.github/workflows/pipeline-electron-build-and-test-and-nan.yml @@ -0,0 +1,103 @@ +name: Electron Build & Test (+ Node + NaN) Pipeline + +on: + workflow_call: + inputs: + target-platform: + type: string + description: 'Platform to run on, can be macos, win or linux.' + required: true + target-arch: + type: string + description: 'Arch to build for, can be x64, arm64 or arm' + required: true + build-runs-on: + type: string + description: 'What host to run the build' + required: true + test-runs-on: + type: string + description: 'What host to run the tests on' + required: true + build-container: + type: string + description: 'JSON container information for aks runs-on' + required: false + default: '{"image":null}' + test-container: + type: string + description: 'JSON container information for testing' + required: false + default: '{"image":null}' + is-release: + description: 'Whether this build job is a release job' + required: true + type: boolean + default: false + gn-build-type: + description: 'The gn build type - testing or release' + required: true + type: string + default: testing + generate-symbols: + description: 'Whether or not to generate symbols' + required: true + type: boolean + default: false + upload-to-storage: + description: 'Whether or not to upload build artifacts to external storage' + required: true + type: string + default: '0' + is-asan: + description: 'Building the Address Sanitizer (ASan) Linux build' + required: false + type: boolean + default: false + +permissions: {} + +concurrency: + group: electron-build-and-test-and-nan-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref_protected == true && github.run_id || github.ref }} + cancel-in-progress: ${{ github.ref_protected != true }} + +jobs: + build: + uses: ./.github/workflows/pipeline-segment-electron-build.yml + permissions: + contents: read + with: + build-runs-on: ${{ inputs.build-runs-on }} + build-container: ${{ inputs.build-container }} + target-platform: ${{ inputs.target-platform }} + target-arch: ${{ inputs.target-arch }} + is-release: ${{ inputs.is-release }} + gn-build-type: ${{ inputs.gn-build-type }} + generate-symbols: ${{ inputs.generate-symbols }} + upload-to-storage: ${{ inputs.upload-to-storage }} + secrets: inherit + test: + uses: ./.github/workflows/pipeline-segment-electron-test.yml + permissions: + contents: read + issues: read + pull-requests: read + needs: build + with: + target-arch: ${{ inputs.target-arch }} + target-platform: ${{ inputs.target-platform }} + test-runs-on: ${{ inputs.test-runs-on }} + test-container: ${{ inputs.test-container }} + secrets: inherit + nn-test: + uses: ./.github/workflows/pipeline-segment-node-nan-test.yml + permissions: + contents: read + needs: build + with: + target-arch: ${{ inputs.target-arch }} + target-platform: ${{ inputs.target-platform }} + test-runs-on: ${{ inputs.test-runs-on }} + test-container: ${{ inputs.test-container }} + gn-build-type: ${{ inputs.gn-build-type }} + secrets: inherit diff --git a/.github/workflows/pipeline-electron-build-and-test.yml b/.github/workflows/pipeline-electron-build-and-test.yml new file mode 100644 index 0000000000000..258bd969d767a --- /dev/null +++ b/.github/workflows/pipeline-electron-build-and-test.yml @@ -0,0 +1,100 @@ +name: Electron Build & Test Pipeline + +on: + workflow_call: + inputs: + target-platform: + type: string + description: 'Platform to run on, can be macos, win or linux' + required: true + target-arch: + type: string + description: 'Arch to build for, can be x64, arm64 or arm' + required: true + build-runs-on: + type: string + description: 'What host to run the build' + required: true + test-runs-on: + type: string + description: 'What host to run the tests on' + required: true + build-container: + type: string + description: 'JSON container information for aks runs-on' + required: false + default: '{"image":null}' + test-container: + type: string + description: 'JSON container information for testing' + required: false + default: '{"image":null}' + is-release: + description: 'Whether this build job is a release job' + required: true + type: boolean + default: false + gn-build-type: + description: 'The gn build type - testing or release' + required: true + type: string + default: testing + generate-symbols: + description: 'Whether or not to generate symbols' + required: true + type: boolean + default: false + upload-to-storage: + description: 'Whether or not to upload build artifacts to external storage' + required: true + type: string + default: '0' + is-asan: + description: 'Building the Address Sanitizer (ASan) Linux build' + required: false + type: boolean + default: false + enable-ssh: + description: 'Enable SSH debugging' + required: false + type: boolean + default: false + +concurrency: + group: electron-build-and-test-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref_protected == true && github.run_id || github.ref }} + cancel-in-progress: ${{ github.ref_protected != true }} + +permissions: {} + +jobs: + build: + uses: ./.github/workflows/pipeline-segment-electron-build.yml + permissions: + contents: read + with: + build-runs-on: ${{ inputs.build-runs-on }} + build-container: ${{ inputs.build-container }} + target-platform: ${{ inputs.target-platform }} + target-arch: ${{ inputs.target-arch }} + is-release: ${{ inputs.is-release }} + gn-build-type: ${{ inputs.gn-build-type }} + generate-symbols: ${{ inputs.generate-symbols }} + upload-to-storage: ${{ inputs.upload-to-storage }} + is-asan: ${{ inputs.is-asan }} + enable-ssh: ${{ inputs.enable-ssh }} + secrets: inherit + test: + uses: ./.github/workflows/pipeline-segment-electron-test.yml + permissions: + contents: read + issues: read + pull-requests: read + needs: build + with: + target-arch: ${{ inputs.target-arch }} + target-platform: ${{ inputs.target-platform }} + test-runs-on: ${{ inputs.test-runs-on }} + test-container: ${{ inputs.test-container }} + is-asan: ${{ inputs.is-asan }} + enable-ssh: ${{ inputs.enable-ssh }} + secrets: inherit diff --git a/.github/workflows/pipeline-electron-build-and-tidy-and-test-and-nan.yml b/.github/workflows/pipeline-electron-build-and-tidy-and-test-and-nan.yml new file mode 100644 index 0000000000000..8aecf8b6c0155 --- /dev/null +++ b/.github/workflows/pipeline-electron-build-and-tidy-and-test-and-nan.yml @@ -0,0 +1,139 @@ +name: Electron Build & Clang Tidy & Test (+ Node + NaN) Pipeline + +on: + workflow_call: + inputs: + target-platform: + type: string + description: 'Platform to run on, can be macos, win or linux.' + required: true + target-arch: + type: string + description: 'Arch to build for, can be x64, arm64 or arm' + required: true + build-runs-on: + type: string + description: 'What host to run the build' + required: true + clang-tidy-runs-on: + type: string + description: 'What host to run clang-tidy on' + required: true + test-runs-on: + type: string + description: 'What host to run the tests on' + required: true + build-container: + type: string + description: 'JSON container information for aks runs-on' + required: false + default: '{"image":null}' + clang-tidy-container: + type: string + description: 'JSON container information to run clang-tidy on' + required: false + default: '{"image":null}' + test-container: + type: string + description: 'JSON container information for testing' + required: false + default: '{"image":null}' + is-release: + description: 'Whether this build job is a release job' + required: true + type: boolean + default: false + gn-build-type: + description: 'The gn build type - testing or release' + required: true + type: string + default: testing + generate-symbols: + description: 'Whether or not to generate symbols' + required: true + type: boolean + default: false + upload-to-storage: + description: 'Whether or not to upload build artifacts to external storage' + required: true + type: string + default: '0' + is-asan: + description: 'Building the Address Sanitizer (ASan) Linux build' + required: false + type: boolean + default: false + +permissions: {} + +concurrency: + group: electron-build-and-test-and-nan-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref_protected == true && github.run_id || github.ref }} + cancel-in-progress: ${{ github.ref_protected != true }} + +jobs: + build: + uses: ./.github/workflows/pipeline-segment-electron-build.yml + permissions: + contents: read + with: + build-runs-on: ${{ inputs.build-runs-on }} + build-container: ${{ inputs.build-container }} + target-platform: ${{ inputs.target-platform }} + target-arch: ${{ inputs.target-arch }} + is-release: ${{ inputs.is-release }} + gn-build-type: ${{ inputs.gn-build-type }} + generate-symbols: ${{ inputs.generate-symbols }} + upload-to-storage: ${{ inputs.upload-to-storage }} + upload-out-gen-artifacts: true + secrets: inherit + clang-tidy: + uses: ./.github/workflows/pipeline-segment-electron-clang-tidy.yml + permissions: + contents: read + needs: build + with: + clang-tidy-runs-on: ${{ inputs.clang-tidy-runs-on }} + clang-tidy-container: ${{ inputs.clang-tidy-container }} + target-platform: ${{ inputs.target-platform }} + target-arch: ${{ inputs.target-arch }} + secrets: inherit + test: + uses: ./.github/workflows/pipeline-segment-electron-test.yml + permissions: + contents: read + issues: read + pull-requests: read + needs: build + with: + target-arch: ${{ inputs.target-arch }} + target-platform: ${{ inputs.target-platform }} + test-runs-on: ${{ inputs.test-runs-on }} + test-container: ${{ inputs.test-container }} + secrets: inherit + test-wayland: + uses: ./.github/workflows/pipeline-segment-electron-test.yml + permissions: + contents: read + issues: read + pull-requests: read + needs: build + if: ${{ inputs.target-platform == 'linux' && inputs.target-arch == 'x64' && !inputs.is-asan }} + with: + target-arch: ${{ inputs.target-arch }} + target-platform: ${{ inputs.target-platform }} + test-runs-on: ${{ inputs.test-runs-on }} + test-container: ${{ inputs.test-container }} + display-server: wayland + secrets: inherit + nn-test: + uses: ./.github/workflows/pipeline-segment-node-nan-test.yml + permissions: + contents: read + needs: build + with: + target-arch: ${{ inputs.target-arch }} + target-platform: ${{ inputs.target-platform }} + test-runs-on: ${{ inputs.test-runs-on }} + test-container: ${{ inputs.test-container }} + gn-build-type: ${{ inputs.gn-build-type }} + secrets: inherit diff --git a/.github/workflows/pipeline-electron-build-and-tidy-and-test.yml b/.github/workflows/pipeline-electron-build-and-tidy-and-test.yml new file mode 100644 index 0000000000000..103aafaa04e20 --- /dev/null +++ b/.github/workflows/pipeline-electron-build-and-tidy-and-test.yml @@ -0,0 +1,121 @@ +name: Electron Build & Clang Tidy & Test Pipeline + +on: + workflow_call: + inputs: + target-platform: + type: string + description: 'Platform to run on, can be macos, win or linux' + required: true + target-arch: + type: string + description: 'Arch to build for, can be x64, arm64 or arm' + required: true + build-runs-on: + type: string + description: 'What host to run the build' + required: true + clang-tidy-runs-on: + type: string + description: 'What host to run clang-tidy on' + required: true + test-runs-on: + type: string + description: 'What host to run the tests on' + required: true + build-container: + type: string + description: 'JSON container information for aks runs-on' + required: false + default: '{"image":null}' + clang-tidy-container: + type: string + description: 'JSON container information to run clang-tidy on' + required: false + default: '{"image":null}' + test-container: + type: string + description: 'JSON container information for testing' + required: false + default: '{"image":null}' + is-release: + description: 'Whether this build job is a release job' + required: true + type: boolean + default: false + gn-build-type: + description: 'The gn build type - testing or release' + required: true + type: string + default: testing + generate-symbols: + description: 'Whether or not to generate symbols' + required: true + type: boolean + default: false + upload-to-storage: + description: 'Whether or not to upload build artifacts to external storage' + required: true + type: string + default: '0' + is-asan: + description: 'Building the Address Sanitizer (ASan) Linux build' + required: false + type: boolean + default: false + enable-ssh: + description: 'Enable SSH debugging' + required: false + type: boolean + default: false + +concurrency: + group: electron-build-and-tidy-and-test-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref_protected == true && github.run_id || github.ref }} + cancel-in-progress: ${{ github.ref_protected != true }} + +permissions: {} + +jobs: + build: + uses: ./.github/workflows/pipeline-segment-electron-build.yml + permissions: + contents: read + with: + build-runs-on: ${{ inputs.build-runs-on }} + build-container: ${{ inputs.build-container }} + target-platform: ${{ inputs.target-platform }} + target-arch: ${{ inputs.target-arch }} + is-release: ${{ inputs.is-release }} + gn-build-type: ${{ inputs.gn-build-type }} + generate-symbols: ${{ inputs.generate-symbols }} + upload-to-storage: ${{ inputs.upload-to-storage }} + is-asan: ${{ inputs.is-asan }} + enable-ssh: ${{ inputs.enable-ssh }} + upload-out-gen-artifacts: true + secrets: inherit + clang-tidy: + uses: ./.github/workflows/pipeline-segment-electron-clang-tidy.yml + permissions: + contents: read + needs: build + with: + clang-tidy-runs-on: ${{ inputs.clang-tidy-runs-on }} + clang-tidy-container: ${{ inputs.clang-tidy-container }} + target-platform: ${{ inputs.target-platform }} + target-arch: ${{ inputs.target-arch }} + secrets: inherit + test: + uses: ./.github/workflows/pipeline-segment-electron-test.yml + permissions: + contents: read + issues: read + pull-requests: read + needs: build + with: + target-arch: ${{ inputs.target-arch }} + target-platform: ${{ inputs.target-platform }} + test-runs-on: ${{ inputs.test-runs-on }} + test-container: ${{ inputs.test-container }} + is-asan: ${{ inputs.is-asan }} + enable-ssh: ${{ inputs.enable-ssh }} + secrets: inherit diff --git a/.github/workflows/pipeline-electron-docs-only.yml b/.github/workflows/pipeline-electron-docs-only.yml new file mode 100644 index 0000000000000..038822c57dccc --- /dev/null +++ b/.github/workflows/pipeline-electron-docs-only.yml @@ -0,0 +1,65 @@ +name: Electron Docs Compile + +on: + workflow_call: + inputs: + container: + required: true + description: 'Container to run the docs-only ts compile in' + type: string + +permissions: {} + +concurrency: + group: electron-docs-only-${{ github.ref }} + cancel-in-progress: true + +env: + GCLIENT_EXTRA_ARGS: --custom-var=checkout_arm=True --custom-var=checkout_arm64=True + +jobs: + docs-only: + name: Docs Only Compile + runs-on: electron-arc-centralus-linux-amd64-4core + permissions: + contents: read + timeout-minutes: 20 + container: ${{ fromJSON(inputs.container) }} + steps: + - name: Checkout Electron + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + path: src/electron + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + - name: Generate DEPS Hash + run: | + node src/electron/script/generate-deps-hash.js + DEPSHASH=v2-src-cache-$(cat src/electron/.depshash) + echo "DEPSHASH=$DEPSHASH" >> $GITHUB_ENV + echo "CACHE_PATH=$DEPSHASH.tar" >> $GITHUB_ENV + - name: Restore src cache via AKS + uses: ./src/electron/.github/actions/restore-cache-aks + with: + target-platform: linux + - name: Checkout Electron + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + path: src/electron + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + - name: Install Dependencies + uses: ./src/electron/.github/actions/install-dependencies + - name: Run TS/JS compile + shell: bash + run: | + cd src/electron + node script/yarn.js create-typescript-definitions + node script/yarn.js tsc -p tsconfig.default_app.json --noEmit + for f in build/webpack/*.js + do + out="${f:29}" + if [ "$out" != "base.js" ]; then + node script/yarn.js webpack --config $f --output-filename=$out --output-path=./.tmp --env mode=development + fi + done diff --git a/.github/workflows/pipeline-electron-lint.yml b/.github/workflows/pipeline-electron-lint.yml new file mode 100644 index 0000000000000..bcc12e72d020c --- /dev/null +++ b/.github/workflows/pipeline-electron-lint.yml @@ -0,0 +1,101 @@ +name: Electron Lint + +on: + workflow_call: + inputs: + container: + required: true + description: 'Container to run lint in' + type: string + +permissions: {} + +concurrency: + group: electron-lint-${{ github.ref_protected == true && github.run_id || github.ref }} + cancel-in-progress: ${{ github.ref_protected != true }} + +env: + CHROMIUM_GIT_COOKIE: ${{ secrets.CHROMIUM_GIT_COOKIE }} + +jobs: + lint: + name: Lint + runs-on: electron-arc-centralus-linux-amd64-4core + permissions: + contents: read + timeout-minutes: 20 + container: ${{ fromJSON(inputs.container) }} + steps: + - name: Checkout Electron + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + path: src/electron + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + - name: Install Dependencies + uses: ./src/electron/.github/actions/install-dependencies + - name: Set Chromium Git Cookie + uses: ./src/electron/.github/actions/set-chromium-cookie + - name: Setup third_party Depot Tools + shell: bash + run: | + # "depot_tools" has to be checkout into "//third_party/depot_tools" so pylint.py can a "pylintrc" file. + git clone --filter=tree:0 https://chromium.googlesource.com/chromium/tools/depot_tools.git src/third_party/depot_tools + echo "$(pwd)/src/third_party/depot_tools" >> $GITHUB_PATH + - name: Download GN Binary + shell: bash + run: | + chromium_revision="$(grep -A1 chromium_version src/electron/DEPS | tr -d '\n' | cut -d\' -f4)" + if [[ ! "$chromium_revision" =~ ^[a-zA-Z0-9._-]+$ ]]; then + echo "::error::Invalid chromium_revision: $chromium_revision" + exit 1 + fi + gn_version="$(curl -sL "https://raw.githubusercontent.com/chromium/chromium/refs/tags/${chromium_revision}/DEPS" | grep gn_version | head -n1 | cut -d\' -f4)" + + cipd ensure -ensure-file - -root . <<-CIPD + \$ServiceURL https://chrome-infra-packages.appspot.com/ + @Subdir src/buildtools/linux64 + gn/gn/linux-amd64 $gn_version + CIPD + + buildtools_path="$(pwd)/src/buildtools" + echo "CHROMIUM_BUILDTOOLS_PATH=$buildtools_path" >> $GITHUB_ENV + - name: Download clang-format Binary + shell: bash + run: | + chromium_revision="$(grep -A1 chromium_version src/electron/DEPS | tr -d '\n' | cut -d\' -f4)" + if [[ ! "$chromium_revision" =~ ^[a-zA-Z0-9._-]+$ ]]; then + echo "::error::Invalid chromium_revision: $chromium_revision" + exit 1 + fi + + mkdir -p src/buildtools + curl -sL "https://raw.githubusercontent.com/chromium/chromium/refs/tags/${chromium_revision}/buildtools/DEPS" > src/buildtools/DEPS + + gclient sync --spec="solutions=[{'name':'src/buildtools','url':None,'deps_file':'DEPS','custom_vars':{'process_deps':True},'managed':False}]" + - name: Add problem matchers + shell: bash + run: | + echo "::add-matcher::src/electron/.github/problem-matchers/markdownlint.json" + - name: Run Lint + shell: bash + run: | + # gn.py tries to find a gclient root folder starting from the current dir. + # When it fails and returns "None" path, the whole script fails. Let's "fix" it. + touch .gclient + # Another option would be to checkout "buildtools" inside the Electron checkout, + # but then we would lint its contents (at least gn format), and it doesn't pass it. + + cd src/electron + node script/yarn.js install --immutable + node script/yarn.js lint + - name: Run Script Typechecker + shell: bash + run: | + cd src/electron + node script/yarn.js tsc -p tsconfig.script.json + - name: Check GHA Workflows + shell: bash + run: | + cd src/electron + node script/copy-pipeline-segment-publish.js --check diff --git a/.github/workflows/pipeline-segment-build-siso-windows.yml b/.github/workflows/pipeline-segment-build-siso-windows.yml new file mode 100644 index 0000000000000..93892ef490a03 --- /dev/null +++ b/.github/workflows/pipeline-segment-build-siso-windows.yml @@ -0,0 +1,98 @@ +name: Pipeline Segment - Build Siso (Windows) + +# Builds a patched siso binary for Windows CI. Reads the siso revision from +# the Chromium DEPS file at the pinned chromium_version, shallow-clones +# chromium.googlesource.com/build at that revision, applies the patches under +# .github/siso-patches/, cross-compiles siso.exe for windows/amd64, and +# publishes it as the `siso-windows-amd64` artifact. The Windows build jobs +# download it and use it via SISO_PATH. The built binary is cached keyed on +# the siso revision + sha256 of the patch contents, so subsequent runs just +# restore it. + +on: + workflow_call: {} + +permissions: {} + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Checkout Electron + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 1 + ref: ${{ github.event.pull_request.head.sha }} + sparse-checkout: | + DEPS + .github/siso-patches + - name: Resolve siso revision from Chromium DEPS + id: resolve + run: | + set -euo pipefail + CHROMIUM_VERSION=$(python3 -c "import re; print(re.search(r\"'chromium_version':\s*\n\s*'([^']+)'\", open('DEPS').read()).group(1))") + if ! [[ "$CHROMIUM_VERSION" =~ ^[0-9]+(\.[0-9]+){1,3}$ ]]; then + echo "error: unexpected chromium_version format: $CHROMIUM_VERSION" >&2 + exit 1 + fi + curl -sfL "https://raw.githubusercontent.com/chromium/chromium/${CHROMIUM_VERSION}/DEPS" -o /tmp/chromium-DEPS + SISO_SHA=$(python3 -c "import re; print(re.search(r\"'siso_version':\s*'git_revision:([0-9a-f]+)'\", open('/tmp/chromium-DEPS').read()).group(1))") + if ! [[ "$SISO_SHA" =~ ^[0-9a-f]{40}$ ]]; then + echo "error: unexpected siso_version SHA: $SISO_SHA" >&2 + exit 1 + fi + PATCHES_HASH=$(find .github/siso-patches -type f -name '*.patch' | sort | xargs sha256sum | sha256sum | awk '{print $1}') + echo "siso-sha=${SISO_SHA}" >> "$GITHUB_OUTPUT" + echo "patches-hash=${PATCHES_HASH}" >> "$GITHUB_OUTPUT" + echo "Chromium ${CHROMIUM_VERSION} pins siso at ${SISO_SHA}" + echo "Patches hash: ${PATCHES_HASH}" + - name: Restore cached siso binary + id: cache-siso + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + with: + path: siso-out/siso.exe + key: siso-windows-amd64-${{ steps.resolve.outputs.siso-sha }}-${{ steps.resolve.outputs.patches-hash }} + - name: Shallow clone chromium build repo at pinned revision + if: steps.cache-siso.outputs.cache-hit != 'true' + env: + SISO_SHA: ${{ steps.resolve.outputs.siso-sha }} + run: | + set -euo pipefail + mkdir chromium-build + cd chromium-build + git init -q + git remote add origin https://chromium.googlesource.com/build + git -c protocol.version=2 fetch --depth=1 origin "$SISO_SHA" + git checkout --detach FETCH_HEAD + - name: Apply in-tree siso patches + if: steps.cache-siso.outputs.cache-hit != 'true' + run: | + set -euo pipefail + cd chromium-build + git -c user.name=electron-ci -c user.email=ci@electronjs.org \ + am --3way "${GITHUB_WORKSPACE}/.github/siso-patches"/*.patch + - name: Set up Go + if: steps.cache-siso.outputs.cache-hit != 'true' + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 + with: + go-version-file: chromium-build/siso/go.mod + cache: false + - name: Build siso (windows/amd64) + if: steps.cache-siso.outputs.cache-hit != 'true' + working-directory: chromium-build/siso + env: + CGO_ENABLED: '0' + GOOS: windows + GOARCH: amd64 + run: | + mkdir -p "${GITHUB_WORKSPACE}/siso-out" + go build -trimpath -o "${GITHUB_WORKSPACE}/siso-out/siso.exe" . + - name: Upload siso artifact + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: siso-windows-amd64 + path: siso-out/siso.exe + if-no-files-found: error + retention-days: 1 diff --git a/.github/workflows/pipeline-segment-electron-build.yml b/.github/workflows/pipeline-segment-electron-build.yml new file mode 100644 index 0000000000000..b8aa494efa9ef --- /dev/null +++ b/.github/workflows/pipeline-segment-electron-build.yml @@ -0,0 +1,241 @@ +name: Pipeline Segment - Electron Build + +on: + workflow_call: + inputs: + environment: + description: using the production or testing environment + required: false + type: string + target-platform: + type: string + description: 'Platform to run on, can be macos, win or linux' + required: true + target-arch: + type: string + description: 'Arch to build for, can be x64, arm64, ia32 or arm' + required: true + target-variant: + type: string + description: 'Variant to build for, no effect on non-macOS target platforms. Can be darwin, mas or all.' + default: all + build-runs-on: + type: string + description: 'What host to run the build' + required: true + build-container: + type: string + description: 'JSON container information for aks runs-on' + required: false + default: '{"image":null}' + is-release: + description: 'Whether this build job is a release job' + required: true + type: boolean + default: false + gn-build-type: + description: 'The gn build type - testing or release' + required: true + type: string + default: testing + generate-symbols: + description: 'Whether or not to generate symbols' + required: true + type: boolean + default: false + upload-to-storage: + description: 'Whether or not to upload build artifacts to external storage' + required: true + type: string + default: '0' + is-asan: + description: 'Building the Address Sanitizer (ASan) Linux build' + required: false + type: boolean + default: false + upload-out-gen-artifacts: + description: 'Whether to upload the src/gen artifacts' + required: false + type: boolean + default: false + enable-ssh: + description: 'Enable SSH debugging' + required: false + type: boolean + default: false + +permissions: {} + +concurrency: + group: electron-build-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ inputs.target-variant }}-${{ inputs.is-asan }}-${{ github.ref_protected == true && github.run_id || github.ref }} + cancel-in-progress: ${{ github.ref_protected != true }} + +env: + CHROMIUM_GIT_COOKIE: ${{ secrets.CHROMIUM_GIT_COOKIE }} + CHROMIUM_GIT_COOKIE_WINDOWS_STRING: ${{ secrets.CHROMIUM_GIT_COOKIE_WINDOWS_STRING }} + DD_API_KEY: ${{ secrets.DD_API_KEY }} + ELECTRON_ARTIFACTS_BLOB_STORAGE: ${{ secrets.ELECTRON_ARTIFACTS_BLOB_STORAGE }} + ELECTRON_RBE_JWT: ${{ secrets.ELECTRON_RBE_JWT }} + SUDOWOODO_EXCHANGE_URL: ${{ secrets.SUDOWOODO_EXCHANGE_URL }} + GCLIENT_EXTRA_ARGS: ${{ inputs.target-platform == 'macos' && '--custom-var=checkout_mac=True --custom-var=host_os=mac' || inputs.target-platform == 'win' && '--custom-var=checkout_win=True' || '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' }} + ELECTRON_OUT_DIR: Default + ACTIONS_STEP_DEBUG: ${{ secrets.ACTIONS_STEP_DEBUG }} + +jobs: + build: + defaults: + run: + shell: bash + runs-on: ${{ inputs.build-runs-on }} + permissions: + contents: read + container: ${{ fromJSON(inputs.build-container) }} + environment: ${{ inputs.environment }} + env: + TARGET_ARCH: ${{ inputs.target-arch }} + TARGET_PLATFORM: ${{ inputs.target-platform }} + steps: + - name: Create src dir + run: | + mkdir src + - name: Checkout Electron + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + path: src/electron + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + - name: Setup SSH Debugging + if: ${{ inputs.target-platform == 'macos' && (inputs.enable-ssh || env.ACTIONS_STEP_DEBUG == 'true') }} + uses: ./src/electron/.github/actions/ssh-debug + with: + tunnel: 'true' + env: + CLOUDFLARE_TUNNEL_CERT: ${{ secrets.CLOUDFLARE_TUNNEL_CERT }} + CLOUDFLARE_TUNNEL_HOSTNAME: ${{ vars.CLOUDFLARE_TUNNEL_HOSTNAME }} + CLOUDFLARE_USER_CA_CERT: ${{ secrets.CLOUDFLARE_USER_CA_CERT }} + AUTHORIZED_USERS: ${{ secrets.SSH_DEBUG_AUTHORIZED_USERS }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Free up space (macOS) + if: ${{ inputs.target-platform == 'macos' }} + uses: ./src/electron/.github/actions/free-space-macos + - name: Check disk space after freeing up space + if: ${{ inputs.target-platform == 'macos' }} + run: df -h + - name: Setup Node.js/npm + if: ${{ inputs.target-platform == 'macos' }} + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e + with: + node-version: 22.21.x + cache: yarn + cache-dependency-path: src/electron/yarn.lock + - name: Install Dependencies + uses: ./src/electron/.github/actions/install-dependencies + - name: Install AZCopy + if: ${{ inputs.target-platform == 'macos' }} + run: brew install azcopy + - name: Set GN_EXTRA_ARGS for Linux + if: ${{ inputs.target-platform == 'linux' }} + run: | + if [ "${{ inputs.target-arch }}" = "arm" ]; then + if [ "${{ inputs.is-release }}" = true ]; then + GN_EXTRA_ARGS='target_cpu="arm" build_tflite_with_xnnpack=false symbol_level=1' + else + GN_EXTRA_ARGS='target_cpu="arm" build_tflite_with_xnnpack=false' + fi + elif [ "${{ inputs.target-arch }}" = "arm64" ]; then + GN_EXTRA_ARGS='target_cpu="arm64" fatal_linker_warnings=false enable_linux_installer=false' + elif [ "${{ inputs.is-asan }}" = true ]; then + GN_EXTRA_ARGS='is_asan=true' + fi + echo "GN_EXTRA_ARGS=$GN_EXTRA_ARGS" >> $GITHUB_ENV + - name: Set Chromium Git Cookie + uses: ./src/electron/.github/actions/set-chromium-cookie + - name: Install Build Tools + uses: ./src/electron/.github/actions/install-build-tools + - name: Generate DEPS Hash + run: | + node src/electron/script/generate-deps-hash.js + DEPSHASH=v2-src-cache-$(cat src/electron/.depshash) + echo "DEPSHASH=$DEPSHASH" >> $GITHUB_ENV + echo "CACHE_PATH=$DEPSHASH.tar" >> $GITHUB_ENV + - name: Restore src cache via AZCopy + if: ${{ inputs.target-platform != 'linux' }} + uses: ./src/electron/.github/actions/restore-cache-azcopy + with: + target-platform: ${{ inputs.target-platform }} + - name: Restore src cache via AKS + if: ${{ inputs.target-platform == 'linux' }} + uses: ./src/electron/.github/actions/restore-cache-aks + - name: Checkout Electron + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + path: src/electron + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + - name: Fix Sync + if: ${{ inputs.target-platform != 'linux' }} + uses: ./src/electron/.github/actions/fix-sync + with: + target-platform: ${{ inputs.target-platform }} + env: + ELECTRON_DEPOT_TOOLS_DISABLE_LOG: true + - name: Init Build Tools + run: | + e init -f --root=$(pwd) --out=Default ${{ inputs.gn-build-type }} --import ${{ inputs.gn-build-type }} --target-cpu ${{ inputs.target-arch }} --remote-build siso + - name: Run Electron Only Hooks + run: | + e d gclient runhooks --spec="solutions=[{'name':'src/electron','url':None,'deps_file':'DEPS','custom_vars':{'process_deps':False},'managed':False}]" + - name: Regenerate DEPS Hash + run: | + (cd src/electron && git checkout .) && node src/electron/script/generate-deps-hash.js + echo "DEPSHASH=$(cat src/electron/.depshash)" >> $GITHUB_ENV + - name: Add CHROMIUM_BUILDTOOLS_PATH to env + run: echo "CHROMIUM_BUILDTOOLS_PATH=$(pwd)/src/buildtools" >> $GITHUB_ENV + - name: Free up space (macOS) + if: ${{ inputs.target-platform == 'macos' }} + uses: ./src/electron/.github/actions/free-space-macos + - name: Download custom siso binary (Windows) + if: ${{ inputs.target-platform == 'win' }} + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: siso-windows-amd64 + path: ${{ runner.temp }}/siso + - name: Set SISO_PATH (Windows) + if: ${{ inputs.target-platform == 'win' }} + run: | + SISO_BIN="${RUNNER_TEMP}/siso/siso.exe" + if [ ! -f "$SISO_BIN" ]; then + echo "error: expected siso binary at $SISO_BIN" >&2 + exit 1 + fi + echo "SISO_PATH=$SISO_BIN" >> "$GITHUB_ENV" + echo "Using custom siso binary at $SISO_BIN" + - name: Build Electron + if: ${{ inputs.target-platform != 'macos' || (inputs.target-variant == 'all' || inputs.target-variant == 'darwin') }} + uses: ./src/electron/.github/actions/build-electron + with: + target-arch: ${{ inputs.target-arch }} + target-platform: ${{ inputs.target-platform }} + artifact-platform: ${{ inputs.target-platform == 'macos' && 'darwin' || inputs.target-platform }} + is-release: '${{ inputs.is-release }}' + generate-symbols: '${{ inputs.generate-symbols }}' + upload-to-storage: '${{ inputs.upload-to-storage }}' + is-asan: '${{ inputs.is-asan }}' + upload-out-gen-artifacts: '${{ inputs.upload-out-gen-artifacts }}' + - name: Set GN_EXTRA_ARGS for MAS Build + if: ${{ inputs.target-platform == 'macos' && (inputs.target-variant == 'all' || inputs.target-variant == 'mas') }} + run: | + echo "MAS_BUILD=true" >> $GITHUB_ENV + GN_EXTRA_ARGS='is_mas_build=true' + echo "GN_EXTRA_ARGS=$GN_EXTRA_ARGS" >> $GITHUB_ENV + - name: Build Electron (MAS) + if: ${{ inputs.target-platform == 'macos' && (inputs.target-variant == 'all' || inputs.target-variant == 'mas') }} + uses: ./src/electron/.github/actions/build-electron + with: + target-arch: ${{ inputs.target-arch }} + target-platform: ${{ inputs.target-platform }} + artifact-platform: 'mas' + is-release: '${{ inputs.is-release }}' + generate-symbols: '${{ inputs.generate-symbols }}' + upload-to-storage: '${{ inputs.upload-to-storage }}' + step-suffix: '(mas)' diff --git a/.github/workflows/pipeline-segment-electron-clang-tidy.yml b/.github/workflows/pipeline-segment-electron-clang-tidy.yml new file mode 100644 index 0000000000000..0f34bebc0cc0c --- /dev/null +++ b/.github/workflows/pipeline-segment-electron-clang-tidy.yml @@ -0,0 +1,178 @@ +name: Pipeline Segment - Electron Clang-Tidy + +on: + workflow_call: + inputs: + target-platform: + type: string + description: 'Platform to run on, can be macos, win or linux' + required: true + target-arch: + type: string + description: 'Arch to build for, can be x64, arm64 or arm' + required: true + clang-tidy-runs-on: + type: string + description: 'What host to run clang-tidy on' + required: true + clang-tidy-container: + type: string + description: 'JSON container information for aks runs-on' + required: false + default: '{"image":null}' + +permissions: {} + +concurrency: + group: electron-clang-tidy-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref }} + cancel-in-progress: true + +env: + GCLIENT_EXTRA_ARGS: ${{ inputs.target-platform == 'macos' && '--custom-var=checkout_mac=True --custom-var=host_os=mac' || (inputs.target-platform == 'linux' && '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' || '--custom-var=checkout_win=True') }} + ELECTRON_OUT_DIR: Default + +jobs: + clang-tidy: + defaults: + run: + shell: bash + runs-on: ${{ inputs.clang-tidy-runs-on }} + permissions: + contents: read + container: ${{ fromJSON(inputs.clang-tidy-container) }} + env: + BUILD_TYPE: ${{ inputs.target-platform == 'macos' && 'darwin' || inputs.target-platform }} + TARGET_ARCH: ${{ inputs.target-arch }} + TARGET_PLATFORM: ${{ inputs.target-platform }} + ARTIFACT_KEY: ${{ inputs.target-platform == 'macos' && 'darwin' || inputs.target-platform }}_${{ inputs.target-arch }} + steps: + - name: Checkout Electron + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + path: src/electron + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + - name: Cleanup disk space on macOS + if: ${{ inputs.target-platform == 'macos' }} + shell: bash + run: | + sudo mkdir -p $TMPDIR/del-target + + tmpify() { + if [ -d "$1" ]; then + sudo mv "$1" $TMPDIR/del-target/$(echo $1|shasum -a 256|head -n1|cut -d " " -f1) + fi + } + tmpify /Library/Developer/CoreSimulator + tmpify ~/Library/Developer/CoreSimulator + sudo rm -rf $TMPDIR/del-target + - name: Check disk space after freeing up space + if: ${{ inputs.target-platform == 'macos' }} + run: df -h + - name: Set Chromium Git Cookie + uses: ./src/electron/.github/actions/set-chromium-cookie + - name: Install Build Tools + uses: ./src/electron/.github/actions/install-build-tools + - name: Enable windows toolchain + if: ${{ inputs.target-platform == 'win' }} + run: | + echo "ELECTRON_DEPOT_TOOLS_WIN_TOOLCHAIN=1" >> $GITHUB_ENV + - name: Generate DEPS Hash + run: | + node src/electron/script/generate-deps-hash.js + DEPSHASH=v2-src-cache-$(cat src/electron/.depshash) + echo "DEPSHASH=$DEPSHASH" >> $GITHUB_ENV + echo "CACHE_PATH=$DEPSHASH.tar" >> $GITHUB_ENV + - name: Restore src cache via AZCopy + if: ${{ inputs.target-platform == 'macos' }} + uses: ./src/electron/.github/actions/restore-cache-azcopy + with: + target-platform: ${{ inputs.target-platform }} + - name: Restore src cache via AKS + if: ${{ inputs.target-platform == 'linux' || inputs.target-platform == 'win' }} + uses: ./src/electron/.github/actions/restore-cache-aks + with: + target-platform: ${{ inputs.target-platform }} + - name: Run Electron Only Hooks + run: | + echo "solutions=[{'name':'src/electron','url':None,'deps_file':'DEPS','custom_vars':{'process_deps':False},'managed':False}]" > tmpgclient + if [ "${{ inputs.target-platform }}" = "win" ]; then + echo "solutions=[{'name':'src/electron','url':None,'deps_file':'DEPS','custom_vars':{'process_deps':False,'install_sysroot':False,'checkout_win':True},'managed':False}]" > tmpgclient + echo "target_os=['win']" >> tmpgclient + fi + e d gclient runhooks --gclientfile=tmpgclient + + # Fix VS Toolchain + if [ "${{ inputs.target-platform }}" = "win" ]; then + rm -rf src/third_party/depot_tools/win_toolchain/vs_files + e d python3 src/build/vs_toolchain.py update --force + fi + - name: Regenerate DEPS Hash + run: | + (cd src/electron && git checkout .) && node src/electron/script/generate-deps-hash.js + echo "DEPSHASH=$(cat src/electron/.depshash)" >> $GITHUB_ENV + - name: Add CHROMIUM_BUILDTOOLS_PATH to env + run: echo "CHROMIUM_BUILDTOOLS_PATH=$(pwd)/src/buildtools" >> $GITHUB_ENV + - name: Checkout Electron + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + path: src/electron + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + - name: Install Dependencies + uses: ./src/electron/.github/actions/install-dependencies + - name: Default GN gen + run: | + cd src/electron + git pack-refs + - name: Download Out Gen Artifacts + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: out_gen_artifacts_${{ env.ARTIFACT_KEY }} + path: ./src/out/${{ env.ELECTRON_OUT_DIR }}/gen + - name: Add Clang problem matcher + shell: bash + run: echo "::add-matcher::src/electron/.github/problem-matchers/clang.json" + - name: Run Clang-Tidy + run: | + e init -f --root=$(pwd) --out=${ELECTRON_OUT_DIR} testing --target-cpu ${TARGET_ARCH} --remote-build none + + # For macOS use_remoteexec=false will cause GN errors, so even though we're doing no remote build, set it + export GN_EXTRA_ARGS="use_remoteexec=true target_cpu=\"${TARGET_ARCH}\"" + if [ "${{ inputs.target-platform }}" = "win" ]; then + export GN_EXTRA_ARGS="$GN_EXTRA_ARGS use_v8_context_snapshot=true target_os=\"win\"" + fi + + e build --only-gen + + # Copy macOS framework headers so clang-tidy can find them via -F. + # This must happen after e build --only-gen since e init -f may + # recreate the output directory. + if [ "${{ inputs.target-platform }}" = "macos" ]; then + OUT=src/out/${ELECTRON_OUT_DIR} + SQRL=src/third_party/squirrel.mac + + mkdir -p ${OUT}/{ReactiveObjC,Squirrel,Mantle}.framework/Headers + + cp ${SQRL}/vendor/ReactiveObjC/ReactiveObjC/*.h ${OUT}/ReactiveObjC.framework/Headers/ + cp ${SQRL}/vendor/ReactiveObjC/ReactiveObjC/extobjc/*.h ${OUT}/ReactiveObjC.framework/Headers/ + + cp ${SQRL}/Squirrel/*.h ${OUT}/Squirrel.framework/Headers/ + + cp ${SQRL}/vendor/Mantle/Mantle/include/*.h ${OUT}/Mantle.framework/Headers/ + cp ${SQRL}/vendor/Mantle/Mantle/extobjc/include/*.h ${OUT}/Mantle.framework/Headers/ + fi + + cd src/electron + node script/yarn.js lint:clang-tidy --jobs 8 --out-dir ../out/${ELECTRON_OUT_DIR} + - name: Remove Clang problem matcher + shell: bash + run: echo "::remove-matcher owner=clang::" + - name: Wait for active SSH sessions + if: always() && !cancelled() + shell: bash + run: | + while [ -f /var/.ssh-lock ] + do + sleep 60 + done diff --git a/.github/workflows/pipeline-segment-electron-gn-check.yml b/.github/workflows/pipeline-segment-electron-gn-check.yml new file mode 100644 index 0000000000000..ef5b69210c405 --- /dev/null +++ b/.github/workflows/pipeline-segment-electron-gn-check.yml @@ -0,0 +1,166 @@ +name: Pipeline Segment - Electron GN Check + +on: + workflow_call: + inputs: + target-platform: + type: string + description: 'Platform to run on, can be macos, win or linux' + required: true + target-archs: + type: string + description: 'Archs to check for, can be x64, x86, arm64 or arm space separated' + required: true + check-runs-on: + type: string + description: 'What host to run the tests on' + required: true + check-container: + type: string + description: 'JSON container information for aks runs-on' + required: false + default: '{"image":null}' + gn-build-type: + description: 'The gn build type - testing or release' + required: true + type: string + default: testing + +permissions: {} + +concurrency: + group: electron-gn-check-${{ inputs.target-platform }}-${{ github.ref }} + cancel-in-progress: true + +env: + ELECTRON_RBE_JWT: ${{ secrets.ELECTRON_RBE_JWT }} + GCLIENT_EXTRA_ARGS: ${{ inputs.target-platform == 'macos' && '--custom-var=checkout_mac=True --custom-var=host_os=mac' || (inputs.target-platform == 'linux' && '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' || '--custom-var=checkout_win=True') }} + ELECTRON_OUT_DIR: Default + +jobs: + gn-check: + defaults: + run: + shell: bash + runs-on: ${{ inputs.check-runs-on }} + permissions: + contents: read + container: ${{ fromJSON(inputs.check-container) }} + steps: + - name: Checkout Electron + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + path: src/electron + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + - name: Cleanup disk space on macOS + if: ${{ inputs.target-platform == 'macos' }} + shell: bash + run: | + sudo mkdir -p $TMPDIR/del-target + + tmpify() { + if [ -d "$1" ]; then + sudo mv "$1" $TMPDIR/del-target/$(echo $1|shasum -a 256|head -n1|cut -d " " -f1) + fi + } + tmpify /Library/Developer/CoreSimulator + tmpify ~/Library/Developer/CoreSimulator + sudo rm -rf $TMPDIR/del-target + - name: Check disk space after freeing up space + if: ${{ inputs.target-platform == 'macos' }} + run: df -h + - name: Set Chromium Git Cookie + uses: ./src/electron/.github/actions/set-chromium-cookie + - name: Install Build Tools + uses: ./src/electron/.github/actions/install-build-tools + - name: Enable windows toolchain + if: ${{ inputs.target-platform == 'win' }} + run: | + echo "ELECTRON_DEPOT_TOOLS_WIN_TOOLCHAIN=1" >> $GITHUB_ENV + - name: Generate DEPS Hash + run: | + node src/electron/script/generate-deps-hash.js + DEPSHASH=v2-src-cache-$(cat src/electron/.depshash) + echo "DEPSHASH=$DEPSHASH" >> $GITHUB_ENV + echo "CACHE_PATH=$DEPSHASH.tar" >> $GITHUB_ENV + - name: Restore src cache via AZCopy + if: ${{ inputs.target-platform == 'macos' }} + uses: ./src/electron/.github/actions/restore-cache-azcopy + with: + target-platform: ${{ inputs.target-platform }} + - name: Restore src cache via AKS + if: ${{ inputs.target-platform == 'linux' || inputs.target-platform == 'win' }} + uses: ./src/electron/.github/actions/restore-cache-aks + with: + target-platform: ${{ inputs.target-platform }} + - name: Run Electron Only Hooks + run: | + echo "solutions=[{'name':'src/electron','url':None,'deps_file':'DEPS','custom_vars':{'process_deps':False},'managed':False}]" > tmpgclient + if [ "${{ inputs.target-platform }}" = "win" ]; then + echo "solutions=[{'name':'src/electron','url':None,'deps_file':'DEPS','custom_vars':{'process_deps':False,'install_sysroot':False,'checkout_win':True},'managed':False}]" > tmpgclient + echo "target_os=['win']" >> tmpgclient + fi + e d gclient runhooks --gclientfile=tmpgclient + + # Fix VS Toolchain + if [ "${{ inputs.target-platform }}" = "win" ]; then + rm -rf src/third_party/depot_tools/win_toolchain/vs_files + e d python3 src/build/vs_toolchain.py update --force + fi + - name: Regenerate DEPS Hash + run: | + (cd src/electron && git checkout .) && node src/electron/script/generate-deps-hash.js + echo "DEPSHASH=$(cat src/electron/.depshash)" >> $GITHUB_ENV + - name: Add CHROMIUM_BUILDTOOLS_PATH to env + run: echo "CHROMIUM_BUILDTOOLS_PATH=$(pwd)/src/buildtools" >> $GITHUB_ENV + - name: Checkout Electron + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + path: src/electron + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + - name: Install Dependencies + uses: ./src/electron/.github/actions/install-dependencies + - name: Default GN gen + run: | + cd src/electron + git pack-refs + - name: Run GN Check for ${{ inputs.target-archs }} + run: | + for target_cpu in ${{ inputs.target-archs }} + do + e init -f --root=$(pwd) --out=Default ${{ inputs.gn-build-type }} --import ${{ inputs.gn-build-type }} --target-cpu $target_cpu --remote-build none + cd src + export GN_EXTRA_ARGS="target_cpu=\"$target_cpu\"" + if [ "${{ inputs.target-platform }}" = "linux" ]; then + if [ "$target_cpu" = "arm" ]; then + export GN_EXTRA_ARGS="$GN_EXTRA_ARGS build_tflite_with_xnnpack=false" + elif [ "$target_cpu" = "arm64" ]; then + export GN_EXTRA_ARGS="$GN_EXTRA_ARGS fatal_linker_warnings=false enable_linux_installer=false" + fi + fi + if [ "${{ inputs.target-platform }}" = "win" ]; then + export GN_EXTRA_ARGS="$GN_EXTRA_ARGS use_v8_context_snapshot=true target_os=\"win\"" + fi + + e build --only-gen + + e d gn check out/Default //electron:electron_lib + e d gn check out/Default //electron:electron_app + e d gn check out/Default //electron/shell/common:mojo + e d gn check out/Default //electron/shell/common:plugin + + # Check the hunspell filenames + node electron/script/gen-hunspell-filenames.js --check + node electron/script/gen-libc++-filenames.js --check + cd .. + done + - name: Wait for active SSH sessions + if: always() && !cancelled() + shell: bash + run: | + while [ -f /var/.ssh-lock ] + do + sleep 60 + done diff --git a/.github/workflows/pipeline-segment-electron-publish.yml b/.github/workflows/pipeline-segment-electron-publish.yml new file mode 100644 index 0000000000000..4e2e9e0ff4c9c --- /dev/null +++ b/.github/workflows/pipeline-segment-electron-publish.yml @@ -0,0 +1,258 @@ +# AUTOGENERATED FILE - DO NOT EDIT MANUALLY +# ONLY EDIT .github/workflows/pipeline-segment-electron-build.yml + +name: Pipeline Segment - Electron Build +on: + workflow_call: + inputs: + environment: + description: using the production or testing environment + required: false + type: string + target-platform: + type: string + description: Platform to run on, can be macos, win or linux + required: true + target-arch: + type: string + description: Arch to build for, can be x64, arm64, ia32 or arm + required: true + target-variant: + type: string + description: Variant to build for, no effect on non-macOS target platforms. Can + be darwin, mas or all. + default: all + build-runs-on: + type: string + description: What host to run the build + required: true + build-container: + type: string + description: JSON container information for aks runs-on + required: false + default: '{"image":null}' + is-release: + description: Whether this build job is a release job + required: true + type: boolean + default: false + gn-build-type: + description: The gn build type - testing or release + required: true + type: string + default: testing + generate-symbols: + description: Whether or not to generate symbols + required: true + type: boolean + default: false + upload-to-storage: + description: Whether or not to upload build artifacts to external storage + required: true + type: string + default: "0" + is-asan: + description: Building the Address Sanitizer (ASan) Linux build + required: false + type: boolean + default: false + upload-out-gen-artifacts: + description: Whether to upload the src/gen artifacts + required: false + type: boolean + default: false + enable-ssh: + description: Enable SSH debugging + required: false + type: boolean + default: false +permissions: {} +concurrency: + group: electron-build-${{ inputs.target-platform }}-${{ inputs.target-arch + }}-${{ inputs.target-variant }}-${{ inputs.is-asan }}-${{ + github.ref_protected == true && github.run_id || github.ref }} + cancel-in-progress: ${{ github.ref_protected != true }} +env: + CHROMIUM_GIT_COOKIE: ${{ secrets.CHROMIUM_GIT_COOKIE }} + CHROMIUM_GIT_COOKIE_WINDOWS_STRING: ${{ secrets.CHROMIUM_GIT_COOKIE_WINDOWS_STRING }} + DD_API_KEY: ${{ secrets.DD_API_KEY }} + ELECTRON_ARTIFACTS_BLOB_STORAGE: ${{ secrets.ELECTRON_ARTIFACTS_BLOB_STORAGE }} + ELECTRON_RBE_JWT: ${{ secrets.ELECTRON_RBE_JWT }} + SUDOWOODO_EXCHANGE_URL: ${{ secrets.SUDOWOODO_EXCHANGE_URL }} + GCLIENT_EXTRA_ARGS: ${{ inputs.target-platform == 'macos' && + '--custom-var=checkout_mac=True --custom-var=host_os=mac' || + inputs.target-platform == 'win' && '--custom-var=checkout_win=True' || + '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' }} + ELECTRON_OUT_DIR: Default + ACTIONS_STEP_DEBUG: ${{ secrets.ACTIONS_STEP_DEBUG }} +jobs: + build: + defaults: + run: + shell: bash + runs-on: ${{ inputs.build-runs-on }} + permissions: + artifact-metadata: write + attestations: write + contents: read + id-token: write + container: ${{ fromJSON(inputs.build-container) }} + environment: ${{ inputs.environment }} + env: + TARGET_ARCH: ${{ inputs.target-arch }} + TARGET_PLATFORM: ${{ inputs.target-platform }} + steps: + - name: Create src dir + run: | + mkdir src + - name: Checkout Electron + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + path: src/electron + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + - name: Setup SSH Debugging + if: ${{ inputs.target-platform == 'macos' && (inputs.enable-ssh || + env.ACTIONS_STEP_DEBUG == 'true') }} + uses: ./src/electron/.github/actions/ssh-debug + with: + tunnel: "true" + env: + CLOUDFLARE_TUNNEL_CERT: ${{ secrets.CLOUDFLARE_TUNNEL_CERT }} + CLOUDFLARE_TUNNEL_HOSTNAME: ${{ vars.CLOUDFLARE_TUNNEL_HOSTNAME }} + CLOUDFLARE_USER_CA_CERT: ${{ secrets.CLOUDFLARE_USER_CA_CERT }} + AUTHORIZED_USERS: ${{ secrets.SSH_DEBUG_AUTHORIZED_USERS }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Free up space (macOS) + if: ${{ inputs.target-platform == 'macos' }} + uses: ./src/electron/.github/actions/free-space-macos + - name: Check disk space after freeing up space + if: ${{ inputs.target-platform == 'macos' }} + run: df -h + - name: Setup Node.js/npm + if: ${{ inputs.target-platform == 'macos' }} + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e + with: + node-version: 22.21.x + cache: yarn + cache-dependency-path: src/electron/yarn.lock + - name: Install Dependencies + uses: ./src/electron/.github/actions/install-dependencies + - name: Install AZCopy + if: ${{ inputs.target-platform == 'macos' }} + run: brew install azcopy + - name: Set GN_EXTRA_ARGS for Linux + if: ${{ inputs.target-platform == 'linux' }} + run: > + if [ "${{ inputs.target-arch }}" = "arm" ]; then + if [ "${{ inputs.is-release }}" = true ]; then + GN_EXTRA_ARGS='target_cpu="arm" build_tflite_with_xnnpack=false symbol_level=1' + else + GN_EXTRA_ARGS='target_cpu="arm" build_tflite_with_xnnpack=false' + fi + elif [ "${{ inputs.target-arch }}" = "arm64" ]; then + GN_EXTRA_ARGS='target_cpu="arm64" fatal_linker_warnings=false enable_linux_installer=false' + elif [ "${{ inputs.is-asan }}" = true ]; then + GN_EXTRA_ARGS='is_asan=true' + fi + + echo "GN_EXTRA_ARGS=$GN_EXTRA_ARGS" >> $GITHUB_ENV + - name: Set Chromium Git Cookie + uses: ./src/electron/.github/actions/set-chromium-cookie + - name: Install Build Tools + uses: ./src/electron/.github/actions/install-build-tools + - name: Generate DEPS Hash + run: | + node src/electron/script/generate-deps-hash.js + DEPSHASH=v2-src-cache-$(cat src/electron/.depshash) + echo "DEPSHASH=$DEPSHASH" >> $GITHUB_ENV + echo "CACHE_PATH=$DEPSHASH.tar" >> $GITHUB_ENV + - name: Restore src cache via AZCopy + if: ${{ inputs.target-platform != 'linux' }} + uses: ./src/electron/.github/actions/restore-cache-azcopy + with: + target-platform: ${{ inputs.target-platform }} + - name: Restore src cache via AKS + if: ${{ inputs.target-platform == 'linux' }} + uses: ./src/electron/.github/actions/restore-cache-aks + - name: Checkout Electron + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + path: src/electron + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + - name: Fix Sync + if: ${{ inputs.target-platform != 'linux' }} + uses: ./src/electron/.github/actions/fix-sync + with: + target-platform: ${{ inputs.target-platform }} + env: + ELECTRON_DEPOT_TOOLS_DISABLE_LOG: true + - name: Init Build Tools + run: > + e init -f --root=$(pwd) --out=Default ${{ inputs.gn-build-type }} + --import ${{ inputs.gn-build-type }} --target-cpu ${{ + inputs.target-arch }} --remote-build siso + - name: Run Electron Only Hooks + run: | + e d gclient runhooks --spec="solutions=[{'name':'src/electron','url':None,'deps_file':'DEPS','custom_vars':{'process_deps':False},'managed':False}]" + - name: Regenerate DEPS Hash + run: > + (cd src/electron && git checkout .) && node + src/electron/script/generate-deps-hash.js + + echo "DEPSHASH=$(cat src/electron/.depshash)" >> $GITHUB_ENV + - name: Add CHROMIUM_BUILDTOOLS_PATH to env + run: echo "CHROMIUM_BUILDTOOLS_PATH=$(pwd)/src/buildtools" >> $GITHUB_ENV + - name: Free up space (macOS) + if: ${{ inputs.target-platform == 'macos' }} + uses: ./src/electron/.github/actions/free-space-macos + - name: Download custom siso binary (Windows) + if: ${{ inputs.target-platform == 'win' }} + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: siso-windows-amd64 + path: ${{ runner.temp }}/siso + - name: Set SISO_PATH (Windows) + if: ${{ inputs.target-platform == 'win' }} + run: | + SISO_BIN="${RUNNER_TEMP}/siso/siso.exe" + if [ ! -f "$SISO_BIN" ]; then + echo "error: expected siso binary at $SISO_BIN" >&2 + exit 1 + fi + echo "SISO_PATH=$SISO_BIN" >> "$GITHUB_ENV" + echo "Using custom siso binary at $SISO_BIN" + - name: Build Electron + if: ${{ inputs.target-platform != 'macos' || (inputs.target-variant == 'all' || + inputs.target-variant == 'darwin') }} + uses: ./src/electron/.github/actions/build-electron + with: + target-arch: ${{ inputs.target-arch }} + target-platform: ${{ inputs.target-platform }} + artifact-platform: ${{ inputs.target-platform == 'macos' && 'darwin' || + inputs.target-platform }} + is-release: ${{ inputs.is-release }} + generate-symbols: ${{ inputs.generate-symbols }} + upload-to-storage: ${{ inputs.upload-to-storage }} + is-asan: ${{ inputs.is-asan }} + upload-out-gen-artifacts: ${{ inputs.upload-out-gen-artifacts }} + - name: Set GN_EXTRA_ARGS for MAS Build + if: ${{ inputs.target-platform == 'macos' && (inputs.target-variant == 'all' || + inputs.target-variant == 'mas') }} + run: | + echo "MAS_BUILD=true" >> $GITHUB_ENV + GN_EXTRA_ARGS='is_mas_build=true' + echo "GN_EXTRA_ARGS=$GN_EXTRA_ARGS" >> $GITHUB_ENV + - name: Build Electron (MAS) + if: ${{ inputs.target-platform == 'macos' && (inputs.target-variant == 'all' || + inputs.target-variant == 'mas') }} + uses: ./src/electron/.github/actions/build-electron + with: + target-arch: ${{ inputs.target-arch }} + target-platform: ${{ inputs.target-platform }} + artifact-platform: mas + is-release: ${{ inputs.is-release }} + generate-symbols: ${{ inputs.generate-symbols }} + upload-to-storage: ${{ inputs.upload-to-storage }} + step-suffix: (mas) diff --git a/.github/workflows/pipeline-segment-electron-test-64k.yml b/.github/workflows/pipeline-segment-electron-test-64k.yml new file mode 100644 index 0000000000000..e7934cac15be4 --- /dev/null +++ b/.github/workflows/pipeline-segment-electron-test-64k.yml @@ -0,0 +1,67 @@ +name: Pipeline Segment - Electron Test on Linux ARM64 64k + +on: + workflow_call: + inputs: + test-runs-on: + type: string + description: 'What host to run the tests on' + required: true + test-container: + type: string + description: 'JSON container information for aks runs-on' + required: false + default: '{"image":null}' + +concurrency: + group: electron-test-linux-64k-${{ github.ref_protected == true && github.run_id || github.ref }} + cancel-in-progress: ${{ github.ref_protected != true }} + +permissions: {} + +env: + ELECTRON_OUT_DIR: Default + +jobs: + test-linux-arm64-64k: + env: + BUILD_TYPE: linux + TARGET_ARCH: arm64 + defaults: + run: + shell: bash + runs-on: ${{ inputs.test-runs-on }} + permissions: + contents: read + issues: read + pull-requests: read + steps: + - name: Checkout Electron + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + path: src/electron + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + - name: Download Generated Artifacts + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: generated_artifacts_linux_arm64 + path: ./generated_artifacts_linux_arm64 + - name: Restore Generated Artifacts + run: ./src/electron/script/actions/restore-artifacts.sh + - name: Unzip Dist + run: | + cd src/out/Default + unzip -:o dist.zip + + - name: Run Electron Tests in QEMU 64k Container + shell: bash + env: + MOCHA_REPORTER: mocha-multi-reporters + MOCHA_MULTI_REPORTERS: mocha-junit-reporter, tap + ELECTRON_DISABLE_SECURITY_WARNINGS: 1 + DISPLAY: ':99.0' + run: | + container=$(echo '${{ inputs.test-container }}' | jq -r '.image') + src/electron/script/run-qemu-64k.sh --container $container --testfiles "`pwd`/src" + \ No newline at end of file diff --git a/.github/workflows/pipeline-segment-electron-test.yml b/.github/workflows/pipeline-segment-electron-test.yml new file mode 100644 index 0000000000000..ba9ec2576d429 --- /dev/null +++ b/.github/workflows/pipeline-segment-electron-test.yml @@ -0,0 +1,330 @@ +name: Pipeline Segment - Electron Test + +on: + workflow_call: + inputs: + target-platform: + type: string + description: 'Platform to run on, can be macos, win or linux' + required: true + target-arch: + type: string + description: 'Arch to build for, can be x64, arm64 or arm' + required: true + test-runs-on: + type: string + description: 'What host to run the tests on' + required: true + test-container: + type: string + description: 'JSON container information for aks runs-on' + required: false + default: '{"image":null}' + is-asan: + description: 'Building the Address Sanitizer (ASan) Linux build' + required: false + type: boolean + default: false + enable-ssh: + description: 'Enable SSH debugging' + required: false + type: boolean + default: false + display-server: + description: 'Display backend for Linux tests: x11 or wayland' + required: false + type: string + default: x11 + +concurrency: + group: electron-test-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ inputs.is-asan }}-${{ inputs.display-server }}-${{ github.ref_protected == true && github.run_id || github.ref }} + cancel-in-progress: ${{ github.ref_protected != true }} + +permissions: {} + +env: + CHROMIUM_GIT_COOKIE: ${{ secrets.CHROMIUM_GIT_COOKIE }} + CHROMIUM_GIT_COOKIE_WINDOWS_STRING: ${{ secrets.CHROMIUM_GIT_COOKIE_WINDOWS_STRING }} + ELECTRON_OUT_DIR: Default + ELECTRON_RBE_JWT: ${{ secrets.ELECTRON_RBE_JWT }} + ACTIONS_STEP_DEBUG: ${{ secrets.ACTIONS_STEP_DEBUG }} + # @sentry/cli is only needed by release upload-symbols.py; skip the ~17MB CDN download on test jobs + SENTRYCLI_SKIP_DOWNLOAD: 1 + +jobs: + test: + defaults: + run: + shell: bash + runs-on: ${{ inputs.test-runs-on }} + permissions: + contents: read + issues: read + pull-requests: read + container: ${{ fromJSON(inputs.test-container) }} + strategy: + fail-fast: false + matrix: + build-type: ${{ inputs.target-platform == 'macos' && fromJSON('["darwin","mas"]') || (inputs.target-platform == 'win' && fromJSON('["win"]') || fromJSON('["linux"]')) }} + shard: ${{ case(inputs.display-server == 'wayland', fromJSON('[1]'), inputs.target-platform == 'linux', fromJSON('[1, 2, 3]'), inputs.target-platform == 'macos' && inputs.target-arch == 'x64', fromJSON('[1, 2, 3]'), fromJSON('[1, 2]')) }} + env: + BUILD_TYPE: ${{ matrix.build-type }} + TARGET_ARCH: ${{ inputs.target-arch }} + ARTIFACT_KEY: ${{ matrix.build-type }}_${{ inputs.target-arch }} + steps: + - name: Fix node20 on arm32 runners + if: ${{ inputs.target-arch == 'arm' && inputs.target-platform == 'linux' }} + run: | + cp $(which node) /mnt/runner-externals/node20/bin/ + cp $(which node) /mnt/runner-externals/node24/bin/ + - name: Setup Node.js/npm + if: ${{ inputs.target-platform == 'win' }} + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e + with: + node-version: 22.21.x + - name: Add TCC permissions on macOS + if: ${{ inputs.target-platform == 'macos' }} + run: | + epochdate=$(($(date +'%s * 1000 + %-N / 1000000'))) + configure_user_tccdb () { + local values=$1 + local dbPath="$HOME/Library/Application Support/com.apple.TCC/TCC.db" + local sqlQuery="INSERT OR REPLACE INTO access VALUES($values);" + sqlite3 "$dbPath" "$sqlQuery" + } + + configure_sys_tccdb () { + local values=$1 + local dbPath="/Library/Application Support/com.apple.TCC/TCC.db" + local sqlQuery="INSERT OR REPLACE INTO access VALUES($values);" + sudo sqlite3 "$dbPath" "$sqlQuery" + } + + userValuesArray=( + "'kTCCServiceCamera','/usr/local/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159" + "'kTCCServiceBluetoothAlways','/usr/local/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159" + "'kTCCServiceAppleEvents','/usr/local/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159" + "'kTCCServiceCamera','/opt/hca/hosted-compute-agent',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159" + "'kTCCServiceBluetoothAlways','/opt/hca/hosted-compute-agent',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159" + "'kTCCServiceScreenCapture','/bin/bash',1,2,3,1,NULL,NULL,NULL,'UNUSED',NULL,0,$epochdate" + ) + for values in "${userValuesArray[@]}"; do + # Sonoma and higher have a few extra values + # Ref: https://github.com/actions/runner-images/blob/main/images/macos/scripts/build/configure-tccdb-macos.sh + if [ "$OSTYPE" = "darwin23" ] || [ "$OSTYPE" = "darwin24" ]; then + configure_user_tccdb "$values,NULL,NULL,'UNUSED',${values##*,}" + configure_sys_tccdb "$values,NULL,NULL,'UNUSED',${values##*,}" + else + configure_user_tccdb "$values" + configure_sys_tccdb "$values" + fi + done + - name: Turn off the unexpectedly quit dialog on macOS + if: ${{ inputs.target-platform == 'macos' }} + run: defaults write com.apple.CrashReporter DialogType server + - name: Set xcode to 16.4 + if: ${{ inputs.target-platform == 'macos' }} + run: sudo xcode-select --switch /Applications/Xcode_16.4.app + - name: Checkout Electron + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + path: src/electron + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + - name: Turn off screenshot nag on macOS + if: ${{ inputs.target-platform == 'macos' }} + run: | + defaults write ~/Library/Group\ Containers/group.com.apple.replayd/ScreenCaptureApprovals.plist "/bin/bash" -date "3024-09-23 12:00:00 +0000" + src/electron/script/actions/screencapture-nag-remover.sh -a $(which bash) + src/electron/script/actions/screencapture-nag-remover.sh -a /opt/hca/hosted-compute-agent + - name: Setup SSH Debugging + if: ${{ inputs.target-platform == 'macos' && (inputs.enable-ssh || env.ACTIONS_STEP_DEBUG == 'true') }} + uses: ./src/electron/.github/actions/ssh-debug + with: + tunnel: 'true' + env: + CLOUDFLARE_TUNNEL_CERT: ${{ secrets.CLOUDFLARE_TUNNEL_CERT }} + CLOUDFLARE_TUNNEL_HOSTNAME: ${{ vars.CLOUDFLARE_TUNNEL_HOSTNAME }} + CLOUDFLARE_USER_CA_CERT: ${{ secrets.CLOUDFLARE_USER_CA_CERT }} + AUTHORIZED_USERS: ${{ secrets.SSH_DEBUG_AUTHORIZED_USERS }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Install Dependencies + uses: ./src/electron/.github/actions/install-dependencies + - name: Set Chromium Git Cookie + uses: ./src/electron/.github/actions/set-chromium-cookie + - name: Get Depot Tools + timeout-minutes: 5 + run: | + git config --global core.filemode false + git config --global core.autocrlf false + git config --global branch.autosetuprebase always + git config --global core.fscache true + git config --global core.longpaths true + git config --global core.preloadindex true + git config --global core.longpaths true + git clone --filter=tree:0 https://chromium.googlesource.com/chromium/tools/depot_tools.git + # Ensure depot_tools does not update. + test -d depot_tools && cd depot_tools + touch .disable_auto_update + - name: Add Depot Tools to PATH + run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH + - name: Load ASan specific environment variables + if: ${{ inputs.is-asan == true }} + run: | + echo "ARTIFACT_KEY=${{ matrix.build-type }}_${{ inputs.target-arch }}_asan" >> $GITHUB_ENV + echo "DISABLE_CRASH_REPORTER_TESTS=true" >> $GITHUB_ENV + echo "IS_ASAN=true" >> $GITHUB_ENV + - name: Download Generated Artifacts + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: generated_artifacts_${{ env.ARTIFACT_KEY }} + path: ./generated_artifacts_${{ matrix.build-type }}_${{ inputs.target-arch }} + - name: Download Src Artifacts + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: src_artifacts_${{ env.ARTIFACT_KEY }} + path: ./src_artifacts_${{ matrix.build-type }}_${{ inputs.target-arch }} + - name: Restore Generated Artifacts + run: ./src/electron/script/actions/restore-artifacts.sh + - name: Unzip Dist (win) + if: ${{ inputs.target-platform == 'win' }} + shell: powershell + run: | + Set-ExecutionPolicy Bypass -Scope Process -Force + cd src/out/Default + Expand-Archive -Force dist.zip -DestinationPath ./ + - name: Unzip Dist (unix) + if: ${{ inputs.target-platform != 'win' }} + run: | + cd src/out/Default + unzip -:o dist.zip + - name: Import & Trust Self-Signed Codesigning Cert on MacOS + if: ${{ inputs.target-platform == 'macos' }} + run: | + cd src/electron + ./script/codesign/generate-identity.sh + # Sign with our self-signed cert so that macOS system integrations + # (UNNotifications, dock bounce, etc.) work in tests on both architectures. + # Autoupdater tests sign their own fixture copies via signApp(). + - name: Sign Electron.app for macOS tests + if: ${{ inputs.target-platform == 'macos' }} + run: | + identity=$(src/electron/script/codesign/get-trusted-identity.sh) + if [ -n "$identity" ]; then + codesign -s "$identity" --deep --force src/out/Default/Electron.app + fi + + - name: Run Electron Tests + shell: bash + timeout-minutes: 60 + env: + MOCHA_REPORTER: mocha-multi-reporters + MOCHA_MULTI_REPORTERS: mocha-junit-reporter, tap + ELECTRON_DISABLE_SECURITY_WARNINGS: 1 + DISPLAY: ':99.0' + NPM_CONFIG_MSVS_VERSION: '2022' + run: | + cd src/electron + export ELECTRON_TEST_RESULTS_DIR=`pwd`/junit + # Get which tests are on this shard + tests_files=$(node script/split-tests ${{ matrix.shard }} ${{ case(inputs.display-server == 'wayland', 1, inputs.target-platform == 'linux', 3, inputs.target-platform == 'macos' && inputs.target-arch == 'x64', 3, 2) }}) + if [ "${{ inputs.display-server }}" = "wayland" ]; then + allowlist_file=script/wayland-test-allowlist.txt + filtered_tests="" + for test_file in $tests_files; do + if grep -Fxq "$test_file" "$allowlist_file"; then + filtered_tests="$filtered_tests $test_file" + fi + done + tests_files="${filtered_tests# }" + + if [ -z "$tests_files" ]; then + echo "No tests matched Wayland filter, skipping." + exit 0 + fi + fi + + # Run tests + if [ "${{ inputs.target-platform }}" != "linux" ]; then + echo "About to start tests" + if [ "${{ inputs.target-platform }}" = "win" ]; then + if [ "${{ inputs.target-arch }}" = "x86" ]; then + export npm_config_arch="ia32" + fi + if [ "${{ inputs.target-arch }}" = "arm64" ]; then + export ELECTRON_FORCE_TEST_SUITE_EXIT="true" + fi + fi + node script/yarn.js test --runners=main --enableRerun=3 --trace-uncaught --enable-logging --files $tests_files + else + chown :builduser .. && chmod g+w .. + chown -R :builduser . && chmod -R g+w . + chmod 4755 ../out/Default/chrome-sandbox + runuser -u builduser -- git config --global --add safe.directory $(pwd) + if [ "${{ inputs.is-asan }}" == "true" ]; then + cd .. + ASAN_SYMBOLIZE="$PWD/tools/valgrind/asan/asan_symbolize.py --executable-path=$PWD/out/Default/electron" + export ASAN_OPTIONS="symbolize=0 handle_abort=1" + export G_SLICE=always-malloc + export NSS_DISABLE_ARENA_FREE_LIST=1 + export NSS_DISABLE_UNLOAD=1 + export LLVM_SYMBOLIZER_PATH=$PWD/third_party/llvm-build/Release+Asserts/bin/llvm-symbolizer + export MOCHA_TIMEOUT=180000 + echo "Piping output to ASAN_SYMBOLIZE ($ASAN_SYMBOLIZE)" + cd electron + runuser -u builduser -- xvfb-run script/actions/run-tests.sh script/yarn.js test --runners=main --trace-uncaught --enable-logging --files $tests_files | $ASAN_SYMBOLIZE + else + if [ "${{ inputs.target-arch }}" = "arm" ]; then + runuser -u builduser -- xvfb-run script/actions/run-tests.sh script/yarn.js test --skipYarnInstall --runners=main --enableRerun=3 --trace-uncaught --enable-logging --files $tests_files + else + if [ "${{ inputs.display-server }}" = "wayland" ]; then + runuser -u builduser -- script/actions/run-tests-wayland.sh script/yarn.js test --runners=main --enableRerun=3 --trace-uncaught --enable-logging --files $tests_files + else + runuser -u builduser -- xvfb-run script/actions/run-tests.sh script/yarn.js test --runners=main --enableRerun=3 --trace-uncaught --enable-logging --files $tests_files + fi + fi + + fi + fi + - name: Take screenshot on timeout or cancellation + if: ${{ inputs.target-platform != 'linux' && (cancelled() || failure()) }} + shell: bash + run: | + screenshot_dir="src/electron/spec/artifacts" + mkdir -p "$screenshot_dir" + screenshot_file="$screenshot_dir/screenshot-timeout-$(date +%Y%m%d%H%M%S).png" + if [ "${{ inputs.target-platform }}" = "macos" ]; then + screencapture -x "$screenshot_file" || true + elif [ "${{ inputs.target-platform }}" = "win" ]; then + powershell -command "Add-Type -AssemblyName System.Windows.Forms; \$screen = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds; \$bitmap = New-Object System.Drawing.Bitmap(\$screen.Width, \$screen.Height); \$graphics = [System.Drawing.Graphics]::FromImage(\$bitmap); \$graphics.CopyFromScreen(\$screen.Location, [System.Drawing.Point]::Empty, \$screen.Size); \$bitmap.Save('$screenshot_file')" || true + fi + + - name: Upload Test results to Datadog + env: + DD_ENV: ci + DD_SERVICE: electron + DD_API_KEY: ${{ secrets.DD_API_KEY }} + DD_CIVISIBILITY_LOGS_ENABLED: true + DD_TAGS: "os.architecture:${{ inputs.target-arch }},os.family:${{ inputs.target-platform }},os.platform:${{ inputs.target-platform }},asan:${{ inputs.is-asan }}" + run: | + if ! [ -z $DD_API_KEY ] && [ -f src/electron/junit/test-results-main.xml ]; then + cd src/electron + export DATADOG_PATH=`node script/yarn.js bin datadog-ci` + $DATADOG_PATH junit upload junit/test-results-main.xml + fi + if: always() && !cancelled() + - name: Upload Test Artifacts + if: always() + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a #v7.0.1 + with: + name: ${{ inputs.target-platform == 'linux' && format('test_artifacts_{0}_{1}_{2}', env.ARTIFACT_KEY, inputs.display-server, matrix.shard) || format('test_artifacts_{0}_{1}', env.ARTIFACT_KEY, matrix.shard) }} + path: src/electron/spec/artifacts + if-no-files-found: ignore + - name: Wait for active SSH sessions + if: always() && !cancelled() + shell: bash + run: | + while [ -f /var/.ssh-lock ] + do + sleep 60 + done diff --git a/.github/workflows/pipeline-segment-node-nan-test.yml b/.github/workflows/pipeline-segment-node-nan-test.yml new file mode 100644 index 0000000000000..9fbead086a9b9 --- /dev/null +++ b/.github/workflows/pipeline-segment-node-nan-test.yml @@ -0,0 +1,160 @@ +name: Pipeline Segment - Node/Nan Test + +on: + workflow_call: + inputs: + target-platform: + type: string + description: 'Platform to run on, can be macos, win or linux' + required: true + target-arch: + type: string + description: 'Arch to build for, can be x64, arm64 or arm' + required: true + test-runs-on: + type: string + description: 'What host to run the tests on' + required: true + test-container: + type: string + description: 'JSON container information for aks runs-on' + required: false + default: '{"image":null}' + gn-build-type: + description: 'The gn build type - testing or release' + required: true + type: string + default: testing + +permissions: {} + +concurrency: + group: electron-node-nan-test-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref_protected == true && github.run_id || github.ref }} + cancel-in-progress: ${{ github.ref_protected != true }} + +env: + CHROMIUM_GIT_COOKIE: ${{ secrets.CHROMIUM_GIT_COOKIE }} + ELECTRON_OUT_DIR: Default + ELECTRON_RBE_JWT: ${{ secrets.ELECTRON_RBE_JWT }} + # @sentry/cli is only needed by release upload-symbols.py; skip the ~17MB CDN download on test jobs + SENTRYCLI_SKIP_DOWNLOAD: 1 + +jobs: + node-tests: + name: Run Node.js Tests + runs-on: electron-arc-centralus-linux-amd64-8core + permissions: + contents: read + timeout-minutes: 30 + env: + TARGET_ARCH: ${{ inputs.target-arch }} + BUILD_TYPE: linux + container: ${{ fromJSON(inputs.test-container) }} + steps: + - name: Checkout Electron + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + path: src/electron + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + - name: Set Chromium Git Cookie + uses: ./src/electron/.github/actions/set-chromium-cookie + - name: Install Build Tools + uses: ./src/electron/.github/actions/install-build-tools + - name: Init Build Tools + run: | + e init -f --root=$(pwd) --out=Default ${{ inputs.gn-build-type }} --import ${{ inputs.gn-build-type }} --target-cpu ${{ inputs.target-arch }} + - name: Install Dependencies + uses: ./src/electron/.github/actions/install-dependencies + - name: Download Generated Artifacts + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: generated_artifacts_${{ env.BUILD_TYPE }}_${{ env.TARGET_ARCH }} + path: ./generated_artifacts_${{ env.BUILD_TYPE }}_${{ env.TARGET_ARCH }} + - name: Download Src Artifacts + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: src_artifacts_linux_${{ env.TARGET_ARCH }} + path: ./src_artifacts_linux_${{ env.TARGET_ARCH }} + - name: Restore Generated Artifacts + run: ./src/electron/script/actions/restore-artifacts.sh + - name: Unzip Dist + run: | + cd src/out/Default + unzip -:o dist.zip + - name: Setup Linux for Headless Testing + run: sh -e /etc/init.d/xvfb start + - name: Run Node.js Tests + run: | + cd src + node electron/script/node-spec-runner.js --default --jUnitDir=junit + - name: Wait for active SSH sessions + if: always() && !cancelled() + shell: bash + run: | + while [ -f /var/.ssh-lock ] + do + sleep 60 + done + nan-tests: + name: Run Nan Tests + runs-on: electron-arc-centralus-linux-amd64-4core + permissions: + contents: read + timeout-minutes: 30 + env: + TARGET_ARCH: ${{ inputs.target-arch }} + BUILD_TYPE: linux + container: ${{ fromJSON(inputs.test-container) }} + steps: + - name: Checkout Electron + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + path: src/electron + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + - name: Set Chromium Git Cookie + uses: ./src/electron/.github/actions/set-chromium-cookie + - name: Install Build Tools + uses: ./src/electron/.github/actions/install-build-tools + - name: Init Build Tools + run: | + e init -f --root=$(pwd) --out=Default ${{ inputs.gn-build-type }} + - name: Install Dependencies + uses: ./src/electron/.github/actions/install-dependencies + - name: Download Generated Artifacts + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: generated_artifacts_${{ env.BUILD_TYPE }}_${{ env.TARGET_ARCH }} + path: ./generated_artifacts_${{ env.BUILD_TYPE }}_${{ env.TARGET_ARCH }} + - name: Download Src Artifacts + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: src_artifacts_linux_${{ env.TARGET_ARCH }} + path: ./src_artifacts_linux_${{ env.TARGET_ARCH }} + - name: Restore Generated Artifacts + run: ./src/electron/script/actions/restore-artifacts.sh + - name: Unzip Dist + run: | + cd src/out/Default + unzip -:o dist.zip + - name: Setup Linux for Headless Testing + run: sh -e /etc/init.d/xvfb start + - name: Add Clang problem matcher + shell: bash + run: echo "::add-matcher::src/electron/.github/problem-matchers/clang.json" + - name: Run Nan Tests + run: | + cd src + node electron/script/nan-spec-runner.js + - name: Remove Clang problem matcher + shell: bash + run: echo "::remove-matcher owner=clang::" + - name: Wait for active SSH sessions + shell: bash + if: always() && !cancelled() + run: | + while [ -f /var/.ssh-lock ] + do + sleep 60 + done diff --git a/.github/workflows/pr-template-check.yml b/.github/workflows/pr-template-check.yml new file mode 100644 index 0000000000000..fd91f681e910d --- /dev/null +++ b/.github/workflows/pr-template-check.yml @@ -0,0 +1,64 @@ +name: PR Template Check + +on: + pull_request_target: + types: [opened, ready_for_review] + +# SECURITY: This workflow uses pull_request_target and has access to secrets. +# Do NOT checkout or run code from the PR head. All code execution must use +# the base branch only. Adding a ref to PR head would expose secrets to +# untrusted code. +permissions: {} + +jobs: + check-pr-template: + if: ${{ github.event.pull_request.head.repo.fork && !github.event.pull_request.draft && !startsWith(github.head_ref, 'roller/') }} + name: Check PR Template + runs-on: ubuntu-slim + permissions: + contents: read + pull-requests: write + steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + sparse-checkout: .github/PULL_REQUEST_TEMPLATE.md + sparse-checkout-cone-mode: false + - name: Check for required sections + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + with: + script: | + const fs = require('fs'); + const template = fs.readFileSync('.github/PULL_REQUEST_TEMPLATE.md', 'utf8'); + const requiredSections = [...template.matchAll(/^(#{1,4} .+)$/gm)].map( + (m) => m[1], + ); + if (requiredSections.length === 0) { + console.log('No heading sections found in PR template'); + return; + } + const body = context.payload.pull_request.body || ''; + // Allow through if body contains a valid backport line + const backportRegex = /Backport of (?:#|https:\/\/github.com\/electron\/electron\/pull\/)\d+/i; + if (backportRegex.test(body)) { + console.log('Backport PR detected, skipping required section check.'); + return; + } + const missingSections = requiredSections.filter( + (section) => !body.includes(section), + ); + if (missingSections.length > 0) { + const list = missingSections.map((s) => `- \`${s}\``).join('\n'); + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.pull_request.number, + body: `This PR was automatically closed because the PR template was not properly filled out. The following required sections are missing:\n\n${list}\n\nPlease update your PR description to include all required sections and reopen the PR.`, + }); + await github.rest.pulls.update({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.payload.pull_request.number, + state: 'closed', + }); + } diff --git a/.github/workflows/pr-triage-automation.yml b/.github/workflows/pr-triage-automation.yml new file mode 100644 index 0000000000000..b8424940ac6c2 --- /dev/null +++ b/.github/workflows/pr-triage-automation.yml @@ -0,0 +1,56 @@ +name: PR Triage Automation + +on: + pull_request_target: + types: [synchronize, review_requested] + issue_comment: + types: [created] + +# SECURITY: This workflow uses pull_request_target and has access to secrets. +# Do NOT checkout or run code from the PR head. All code execution must use +# the base branch only. Adding a ref to PR head would expose secrets to +# untrusted code. +permissions: {} + +jobs: + set-needs-review: + name: Set status to Needs Review + if: >- + (github.event_name == 'pull_request_target' + && github.event.pull_request.state == 'open' + && github.event.pull_request.draft != true + && !contains(github.event.pull_request.labels.*.name, 'wip ⚒') + && (github.event.action == 'synchronize' || github.event.action == 'review_requested')) + || (github.event_name == 'issue_comment' + && github.event.issue.pull_request + && github.event.issue.state == 'open' + && !contains(github.event.issue.labels.*.name, 'wip ⚒') + && github.event.comment.user.login == github.event.issue.user.login) + runs-on: ubuntu-slim + permissions: + contents: read + steps: + - name: Generate GitHub App token + uses: electron/github-app-auth-action@e14e47722ed120360649d0789e25b9baece12725 # v2.0.0 + id: generate-token + with: + creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }} + org: electron + - name: Get project item status + uses: dsanders11/project-actions/get-item@4b06452b0128cf601dac14399aa668a8eed2d684 # v2.0.1 + id: get-item + with: + token: ${{ steps.generate-token.outputs.token }} + project-number: 118 + fail-if-item-not-found: false + - name: Set status to Needs Review + if: >- + (steps.get-item.outputs.field-status == '🛑 Needs Submitter Response' + || steps.get-item.outputs.field-status == '🟡 WIP') + uses: dsanders11/project-actions/edit-item@4b06452b0128cf601dac14399aa668a8eed2d684 # v2.0.1 + with: + token: ${{ steps.generate-token.outputs.token }} + project-number: 118 + field: Status + field-value: 🌀 Needs Review + fail-if-item-not-found: false diff --git a/.github/workflows/pull-request-labeled.yml b/.github/workflows/pull-request-labeled.yml new file mode 100644 index 0000000000000..f0cf02cee6c16 --- /dev/null +++ b/.github/workflows/pull-request-labeled.yml @@ -0,0 +1,82 @@ +name: Pull Request Labeled + +on: + pull_request_target: + types: [labeled] + +# SECURITY: This workflow uses pull_request_target and has access to secrets. +# Do NOT checkout or run code from the PR head. All code execution must use +# the base branch only. Adding a ref to PR head would expose secrets to +# untrusted code. +permissions: {} + +jobs: + pull-request-labeled-backport-requested: + name: backport/requested label added + if: github.event.label.name == 'backport/requested 🗳' + runs-on: ubuntu-latest + permissions: {} + steps: + - name: Trigger Slack workflow + uses: slackapi/slack-github-action@af78098f536edbc4de71162a307590698245be95 # v3.0.1 + with: + webhook: ${{ secrets.BACKPORT_REQUESTED_SLACK_WEBHOOK_URL }} + webhook-type: webhook-trigger + payload: | + { + "base_ref": ${{ toJSON(github.event.pull_request.base.ref) }}, + "title": ${{ toJSON(github.event.pull_request.title) }}, + "url": ${{ toJSON(github.event.pull_request.html_url) }}, + "user": ${{ toJSON(github.event.pull_request.user.login) }} + } + pull-request-labeled-deprecation-review-complete: + name: deprecation-review/complete label added + if: github.event.label.name == 'deprecation-review/complete ✅' + runs-on: ubuntu-latest + permissions: {} + steps: + - name: Generate GitHub App token + uses: electron/github-app-auth-action@e14e47722ed120360649d0789e25b9baece12725 # v2.0.0 + id: generate-token + with: + creds: ${{ secrets.RELEASE_BOARD_GH_APP_CREDS }} + org: electron + - name: Set status + uses: dsanders11/project-actions/edit-item@4b06452b0128cf601dac14399aa668a8eed2d684 # v2.0.1 + with: + token: ${{ steps.generate-token.outputs.token }} + project-number: 94 + field: Status + field-value: ✅ Reviewed + pull-request-labeled-ai-pr: + name: ai-pr label added + if: github.event.label.name == 'ai-pr' && github.event.pull_request.state != 'closed' + runs-on: ubuntu-latest + permissions: {} + steps: + - name: Generate GitHub App token + uses: electron/github-app-auth-action@e14e47722ed120360649d0789e25b9baece12725 # v2.0.0 + id: generate-token + with: + creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }} + - name: Create comment + uses: actions-cool/issues-helper@200c78641dbf33838311e5a1e0c31bbdb92d7cf0 # v3.8.0 + with: + actions: 'create-comment' + token: ${{ steps.generate-token.outputs.token }} + issue-number: ${{ github.event.pull_request.number }} + body: | + + + *AI PR Detected* + + Hello @${{ github.event.pull_request.user.login }}. Due to the high amount of AI spam PRs we receive, if a PR is detected to be majority AI-generated without disclosure and untested, we will automatically close the PR. + + We welcome the use of AI tools, as long as the PR meets our quality standards and has clearly been built and tested. If you believe your PR was closed in error, we welcome you to resubmit. However, please read our [CONTRIBUTING.md](https://github.com/electron/electron/blob/main/CONTRIBUTING.md) and [AI Tool Policy](https://github.com/electron/governance/blob/main/policy/ai.md) carefully before reopening. Thanks for your contribution. + - name: Close the pull request + env: + GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }} + GH_REPO: electron/electron + PR_NUMBER: ${{ github.event.pull_request.number }} + run: | + gh pr close "$PR_NUMBER" diff --git a/.github/workflows/pull-request-opened-synchronized.yml b/.github/workflows/pull-request-opened-synchronized.yml new file mode 100644 index 0000000000000..3f81c120682ed --- /dev/null +++ b/.github/workflows/pull-request-opened-synchronized.yml @@ -0,0 +1,46 @@ +name: Pull Request Opened/Synchronized + +on: + pull_request_target: + types: [opened, synchronize] + +# SECURITY: This workflow uses pull_request_target and has access to secrets. +# Do NOT checkout or run code from the PR head. All code execution must use +# the base branch only. Adding a ref to PR head would expose secrets to +# untrusted code. +permissions: {} + +jobs: + check-signed-commits: + name: Check signed commits in PR + runs-on: ubuntu-slim + permissions: + contents: read + pull-requests: write + steps: + - name: Check signed commits in PR + uses: 1Password/check-signed-commits-action@ed2885f3ed2577a4f5d3c3fe895432a557d23d52 # v1 + with: + comment: | + ⚠️ This PR contains unsigned commits. This repository enforces [commit signatures](https://docs.github.com/en/authentication/managing-commit-signature-verification) + for all incoming PRs. To get your PR merged, please sign those commits + (`git rebase --exec 'git commit -S --amend --no-edit -n' @{upstream}`) and force push them to this branch + (`git push --force-with-lease`) + + For more information on signing commits, see GitHub's documentation on [Telling Git about your signing key](https://docs.github.com/en/authentication/managing-commit-signature-verification/telling-git-about-your-signing-key). + + - name: Add needs-signed-commits label + if: ${{ failure() }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_URL: ${{ github.event.pull_request.html_url }} + run: | + gh pr edit $PR_URL --add-label needs-signed-commits + + - name: Remove needs-signed-commits label + if: ${{ success() && contains(github.event.pull_request.labels.*.name, 'needs-signed-commits') }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_URL: ${{ github.event.pull_request.html_url }} + run: | + gh pr edit $PR_URL --remove-label needs-signed-commits diff --git a/.github/workflows/rerun-apply-patches.yml b/.github/workflows/rerun-apply-patches.yml new file mode 100644 index 0000000000000..1ac3d11a642a2 --- /dev/null +++ b/.github/workflows/rerun-apply-patches.yml @@ -0,0 +1,72 @@ +name: Rerun PR Apply Patches + +on: + push: + branches: + - main + - '[1-9][0-9]-x-y' + paths: + - 'DEPS' + - 'patches/**' + - '.github/siso-patches/**' + +permissions: {} + +jobs: + rerun-apply-patches: + runs-on: ubuntu-latest + permissions: + actions: write + checks: read + contents: read + pull-requests: read + steps: + - name: Find PRs and Rerun Apply Patches + env: + GH_REPO: ${{ github.repository }} + GH_TOKEN: ${{ github.token }} + run: | + BRANCH="${GITHUB_REF#refs/heads/}" + + # Find all open PRs targeting this branch + PRS=$(gh pr list --base "$BRANCH" --state open --limit 250 --json number) + + echo "$PRS" | jq -c '.[]' | while read -r pr; do + PR_NUMBER=$(echo "$pr" | jq -r '.number') + echo "Processing PR #${PR_NUMBER}" + + # Find the Apply Patches workflow check for this PR + CHECK=$(gh pr view "$PR_NUMBER" --json statusCheckRollup --jq '[.statusCheckRollup[] | select(.workflowName == "Apply Patches" and .name == "apply-patches")] | first') + + if [ -z "$CHECK" ] || [ "$CHECK" = "null" ]; then + echo " No Apply Patches workflow found for PR #${PR_NUMBER}" + continue + fi + + CONCLUSION=$(echo "$CHECK" | jq -r '.conclusion') + if [ "$CONCLUSION" = "SKIPPED" ]; then + echo " apply-patches job was skipped for PR #${PR_NUMBER} (no patches)" + continue + fi + + LINK=$(echo "$CHECK" | jq -r '.detailsUrl') + + # Extract the run ID from the link (format: .../runs/RUN_ID/job/JOB_ID) + RUN_ID=$(echo "$LINK" | grep -oE 'runs/[0-9]+' | cut -d'/' -f2) + + if [ -z "$RUN_ID" ]; then + echo " Could not extract run ID from link: ${LINK}" + continue + fi + + # Check if the workflow is currently in progress + RUN_STATUS=$(gh run view "$RUN_ID" --json status --jq '.status') + + if [ "$RUN_STATUS" = "in_progress" ] || [ "$RUN_STATUS" = "queued" ] || [ "$RUN_STATUS" = "waiting" ]; then + echo " Workflow run ${RUN_ID} is ${RUN_STATUS}, cancelling..." + gh run cancel "$RUN_ID" --force + gh run watch "$RUN_ID" + fi + + gh run rerun "$RUN_ID" + done diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml new file mode 100644 index 0000000000000..881aa72fbb7e4 --- /dev/null +++ b/.github/workflows/scorecards.yml @@ -0,0 +1,56 @@ +name: Scorecards supply-chain security +on: + # Only the default branch is supported. + branch_protection_rule: + schedule: + - cron: '44 17 * * 0' + push: + branches: [ "main" ] + +# Declare default permissions as read only. +permissions: read-all + +jobs: + analysis: + name: Scorecards analysis + if: github.repository == 'electron/electron' + runs-on: ubuntu-latest + permissions: + # Needed to upload the results to code-scanning dashboard. + security-events: write + # Used to receive a badge. + id-token: write + + steps: + - name: "Checkout code" + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + # This is a pre-submit / pre-release. + - name: "Run analysis" + uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 + with: + results_file: results.sarif + results_format: sarif + + # Publish the results for public repositories to enable scorecard badges. For more details, see + # https://github.com/ossf/scorecard-action#publishing-results. + # For private repositories, `publish_results` will automatically be set to `false`, regardless + # of the value entered here. + publish_results: true + + # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF + # format to the repository Actions tab. + - name: "Upload artifact" + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: SARIF file + path: results.sarif + retention-days: 5 + + # Upload the results to GitHub's code scanning dashboard. + - name: "Upload to code-scanning" + uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v3.29.5 + with: + sarif_file: results.sarif diff --git a/.github/workflows/semantic.yml b/.github/workflows/semantic.yml new file mode 100644 index 0000000000000..92abda9930c34 --- /dev/null +++ b/.github/workflows/semantic.yml @@ -0,0 +1,25 @@ +name: "Check Semantic Commit" + +on: + pull_request: + types: + - opened + - edited + - synchronize + +permissions: {} + +jobs: + main: + permissions: + pull-requests: read # for amannn/action-semantic-pull-request to analyze PRs + statuses: write # for amannn/action-semantic-pull-request to mark status of analyzed PR + name: Validate PR Title + runs-on: ubuntu-latest + steps: + - name: semantic-pull-request + uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6.1.1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + validateSingleCommit: false diff --git a/.github/workflows/stable-prep-items.yml b/.github/workflows/stable-prep-items.yml new file mode 100644 index 0000000000000..f1cc24a2bd459 --- /dev/null +++ b/.github/workflows/stable-prep-items.yml @@ -0,0 +1,37 @@ +name: Check Stable Prep Items + +on: + schedule: + - cron: '0 */12 * * *' + workflow_dispatch: + +permissions: {} + +jobs: + check-stable-prep-items: + name: Check Stable Prep Items + if: github.repository == 'electron/electron' + runs-on: ubuntu-latest + permissions: {} + steps: + - name: Generate GitHub App token + uses: electron/github-app-auth-action@e14e47722ed120360649d0789e25b9baece12725 # v2.0.0 + id: generate-token + with: + creds: ${{ secrets.RELEASE_BOARD_GH_APP_CREDS }} + org: electron + - name: Find Newest Release Project Board + id: find-project-number + env: + GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }} + run: | + set -eo pipefail + PROJECT_NUMBER=$(gh project list --owner electron --format json | jq -r '.projects | map(select(.title | test("^[0-9]+-x-y$"))) | max_by(.number) | .number') + echo "PROJECT_NUMBER=$PROJECT_NUMBER" >> "$GITHUB_OUTPUT" + - name: Update Completed Stable Prep Items + uses: dsanders11/project-actions/completed-by@4b06452b0128cf601dac14399aa668a8eed2d684 # v2.0.1 + with: + field: Prep Status + field-value: ✅ Complete + project-number: ${{ steps.find-project-number.outputs.PROJECT_NUMBER }} + token: ${{ steps.generate-token.outputs.token }} diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000000000..a9ab0c822e614 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,55 @@ +name: 'Close stale issues' +on: + workflow_dispatch: + schedule: + # 1:30am every day + - cron: '30 1 * * *' + +permissions: {} + +jobs: + stale: + if: github.repository == 'electron/electron' + runs-on: ubuntu-latest + permissions: {} + steps: + - name: Generate GitHub App token + uses: electron/github-app-auth-action@e14e47722ed120360649d0789e25b9baece12725 # v2.0.0 + id: generate-token + with: + creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }} + - uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # tag: v10.2.0 + with: + repo-token: ${{ steps.generate-token.outputs.token }} + days-before-stale: 90 + days-before-close: 30 + stale-issue-label: stale + operations-per-run: 1750 + stale-issue-message: > + This issue has been automatically marked as stale. **If this issue is still affecting you, please leave any comment** (for example, "bump"), and we'll keep it open. If you have any new additional information—in particular, if this is still reproducible in the [latest version of Electron](https://www.electronjs.org/releases/stable) or in the [beta](https://www.electronjs.org/releases/beta)—please include it with your comment! + close-issue-message: > + This issue has been closed due to inactivity, and will not be monitored. If this is a bug and you can reproduce this issue on a [supported version of Electron](https://www.electronjs.org/docs/latest/tutorial/electron-timelines#timeline) please open a new issue and include instructions for reproducing the issue. + exempt-issue-labels: "discussion,security \U0001F512,enhancement :sparkles:,status/confirmed,stale-exempt,upgrade-follow-up,tracking-upstream" + only-pr-labels: not-a-real-label + pending-repro: + runs-on: ubuntu-latest + permissions: {} + if: ${{ always() && github.repository == 'electron/electron' }} + needs: stale + steps: + - name: Generate GitHub App token + uses: electron/github-app-auth-action@e14e47722ed120360649d0789e25b9baece12725 # v2.0.0 + id: generate-token + with: + creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }} + - uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # tag: v10.2.0 + with: + repo-token: ${{ steps.generate-token.outputs.token }} + days-before-stale: -1 + days-before-close: 10 + remove-stale-when-updated: false + stale-issue-label: blocked/need-repro + stale-pr-label: not-a-real-label + operations-per-run: 1750 + close-issue-message: > + Unfortunately, without a way to reproduce this issue, we're unable to continue investigation. This issue has been closed and will not be monitored further. If you're able to provide a minimal test case that reproduces this issue on a [supported version of Electron](https://www.electronjs.org/docs/latest/tutorial/electron-timelines#timeline) please open a new issue and include instructions for reproducing the issue. diff --git a/.github/workflows/update-website-docs.yml b/.github/workflows/update-website-docs.yml new file mode 100644 index 0000000000000..2517dedb2d74b --- /dev/null +++ b/.github/workflows/update-website-docs.yml @@ -0,0 +1,39 @@ +name: Update Website Docs + +on: + release: + types: [published] + +permissions: {} + +jobs: + update-website-docs: + name: Update Website Docs + runs-on: ubuntu-latest + environment: website-docs-updater + permissions: + contents: read + id-token: write # needed for secret-service-action + steps: + - name: Get GitHub App token + id: secret-service + uses: electron/secret-service-action@3476425e8b30555aac15b1b7096938e254b0e155 # v1.0.0 + - name: Check if this release is the latest + id: check-if-latest-release + env: + GH_REPO: electron/electron + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + LATEST_RELEASE_TAG="$(gh release view --json tagName --jq '.tagName')" + if [ "$LATEST_RELEASE_TAG" = "${GITHUB_REF#refs/tags/}" ]; then + echo "isLatestRelease=true" >> $GITHUB_OUTPUT + else + echo "isLatestRelease=false" >> $GITHUB_OUTPUT + fi + - name: Trigger website docs update + if: ${{ steps.check-if-latest-release.outputs.isLatestRelease == 'true' }} + env: + GH_REPO: electron/website + GH_TOKEN: ${{ fromJSON(steps.secret-service.outputs.secrets).WEBSITE_DOCS_UPDATER_APP_TOKEN }} + run: | + gh workflow run update-docs.yml -f sha=$GITHUB_SHA diff --git a/.github/workflows/windows-publish.yml b/.github/workflows/windows-publish.yml new file mode 100644 index 0000000000000..748b9c86c1fb5 --- /dev/null +++ b/.github/workflows/windows-publish.yml @@ -0,0 +1,130 @@ +name: Publish Windows + +on: + workflow_dispatch: + inputs: + build-image-sha: + type: string + description: 'SHA for electron/build image' + default: '' + required: false + upload-to-storage: + description: 'Uploads to Azure storage' + required: false + default: '1' + type: string + run-windows-publish: + description: 'Run the publish jobs vs just the build jobs' + type: boolean + default: false + +permissions: {} + +jobs: + setup: + if: github.repository == 'electron/electron' + runs-on: ubuntu-slim + permissions: + contents: read + outputs: + build-image-sha: ${{ steps.build-image-sha.outputs.build-image-sha }} + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + - name: Set Build Image SHA + id: build-image-sha + uses: ./.github/actions/build-image-sha + with: + override: ${{ inputs.build-image-sha }} + + checkout-windows: + needs: setup + runs-on: electron-arc-centralus-linux-amd64-32core + permissions: + contents: read + container: + image: ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }} + options: --user root --device /dev/fuse --cap-add SYS_ADMIN + volumes: + - /mnt/win-cache:/mnt/win-cache + - /var/run/sas:/var/run/sas + env: + CHROMIUM_GIT_COOKIE_WINDOWS_STRING: ${{ secrets.CHROMIUM_GIT_COOKIE_WINDOWS_STRING }} + GCLIENT_EXTRA_ARGS: '--custom-var=checkout_win=True' + TARGET_OS: 'win' + ELECTRON_DEPOT_TOOLS_WIN_TOOLCHAIN: '1' + steps: + - name: Checkout Electron + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + path: src/electron + fetch-depth: 0 + - name: Checkout & Sync & Save + uses: ./src/electron/.github/actions/checkout + with: + generate-sas-token: 'true' + target-platform: win + + # Build the patched siso binary in parallel with checkout-windows; the + # publish-*-win jobs consume it via SISO_PATH. + build-siso-windows: + needs: setup + uses: ./.github/workflows/pipeline-segment-build-siso-windows.yml + permissions: + contents: read + + publish-x64-win: + uses: ./.github/workflows/pipeline-segment-electron-publish.yml + permissions: + artifact-metadata: write + attestations: write + contents: read + id-token: write + needs: [checkout-windows, build-siso-windows] + with: + environment: production-release + build-runs-on: electron-arc-centralus-windows-amd64-32core + target-platform: win + target-arch: x64 + is-release: true + gn-build-type: release + generate-symbols: true + upload-to-storage: ${{ inputs.upload-to-storage }} + secrets: inherit + + publish-arm64-win: + uses: ./.github/workflows/pipeline-segment-electron-publish.yml + permissions: + artifact-metadata: write + attestations: write + contents: read + id-token: write + needs: [checkout-windows, build-siso-windows] + with: + environment: production-release + build-runs-on: electron-arc-centralus-windows-amd64-32core + target-platform: win + target-arch: arm64 + is-release: true + gn-build-type: release + generate-symbols: true + upload-to-storage: ${{ inputs.upload-to-storage }} + secrets: inherit + + publish-x86-win: + uses: ./.github/workflows/pipeline-segment-electron-publish.yml + permissions: + artifact-metadata: write + attestations: write + contents: read + id-token: write + needs: [checkout-windows, build-siso-windows] + with: + environment: production-release + build-runs-on: electron-arc-centralus-windows-amd64-32core + target-platform: win + target-arch: x86 + is-release: true + gn-build-type: release + generate-symbols: true + upload-to-storage: ${{ inputs.upload-to-storage }} + secrets: inherit diff --git a/.gitignore b/.gitignore index 3819e9cb62d45..84644de3540ed 100644 --- a/.gitignore +++ b/.gitignore @@ -17,24 +17,6 @@ *.xcodeproj /.idea/ /dist/ -/external_binaries/ -/out/ -/vendor/.gclient -/vendor/debian_jessie_mips64-sysroot/ -/vendor/debian_stretch_amd64-sysroot/ -/vendor/debian_stretch_arm-sysroot/ -/vendor/debian_stretch_arm64-sysroot/ -/vendor/debian_stretch_i386-sysroot/ -/vendor/gcc-4.8.3-d197-n64-loongson/ -/vendor/readme-gcc483-loongson.txt -/vendor/download/ -/vendor/llvm-build/ -/vendor/llvm/ -/vendor/npm/ -/vendor/python_26/ -/vendor/native_mksnapshot -/vendor/LICENSES.chromium.html -/vendor/pyyaml node_modules/ SHASUMS256.txt **/package-lock.json @@ -44,6 +26,7 @@ compile_commands.json # npm package /npm/dist /npm/path.txt +/npm/checksums.json .npmrc @@ -55,17 +38,21 @@ electron.d.ts spec/.hash # Eslint Cache -.eslintcache +.eslintcache* # Generated native addon files -/spec-main/fixtures/native-addon/echo/build/ +/spec/fixtures/native-addon/echo/build/ +/spec/fixtures/native-addon/dialog-helper/build/ # If someone runs tsc this is where stuff will end up ts-gen # Used to accelerate CI builds .depshash -.depshash-target # Used to accelerate builds after sync -patches/mtime-cache.json \ No newline at end of file +patches/mtime-cache.json + +spec/fixtures/logo.png + +.yarn/install-state.gz \ No newline at end of file diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index f6b899f682ac8..0000000000000 --- a/.gitmodules +++ /dev/null @@ -1,6 +0,0 @@ -[submodule "vendor/requests"] - path = vendor/requests - url = https://github.com/kennethreitz/requests -[submodule "vendor/boto"] - path = vendor/boto - url = https://github.com/boto/boto.git diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000000000..2601a3bb0c46d --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +npm run precommit \ No newline at end of file diff --git a/.husky/pre-push b/.husky/pre-push new file mode 100755 index 0000000000000..91eb47b1b4e5b --- /dev/null +++ b/.husky/pre-push @@ -0,0 +1 @@ +npm run prepack diff --git a/.lint-roller.json b/.lint-roller.json new file mode 100644 index 0000000000000..bdbbd9172cff0 --- /dev/null +++ b/.lint-roller.json @@ -0,0 +1,13 @@ +{ + "markdown-ts-check": { + "defaultImports": [ + "import * as childProcess from 'node:child_process'", + "import * as fs from 'node:fs'", + "import * as path from 'node:path'", + "import { app, autoUpdater, contextBridge, crashReporter, dialog, BrowserWindow, ipcMain, ipcRenderer, Menu, MessageChannelMain, nativeImage, net, protocol, session, systemPreferences, Tray, utilityProcess, webFrame, webFrameMain } from 'electron'" + ], + "typings": [ + "../electron.d.ts" + ] + } +} diff --git a/.markdownlint-cli2.jsonc b/.markdownlint-cli2.jsonc new file mode 100644 index 0000000000000..0e0b2c199cc78 --- /dev/null +++ b/.markdownlint-cli2.jsonc @@ -0,0 +1,34 @@ +{ + "config": { + "extends": "@electron/lint-roller/configs/markdownlint.json", + "descriptive-link-text": false, + "link-image-style": { + "autolink": false, + "shortcut": false + }, + "MD049": { + "style": "underscore" + }, + "no-angle-brackets": true, + "no-curly-braces": true, + "no-inline-html": { + "allowed_elements": [ + "br", + "details", + "img", + "li", + "summary", + "ul", + "unknown", + "Tabs", + "TabItem", + "DocCardList", + "kbd" + ] + }, + "no-newline-in-links": true + }, + "customRules": [ + "./node_modules/@electron/lint-roller/markdownlint-rules/index.mjs" + ] +} diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000000000..2bd5a0a98a36c --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +22 diff --git a/.oxfmtrc.json b/.oxfmtrc.json new file mode 100644 index 0000000000000..1efaab4a0c008 --- /dev/null +++ b/.oxfmtrc.json @@ -0,0 +1,47 @@ +{ + "$schema": "./node_modules/oxfmt/configuration_schema.json", + "printWidth": 120, + "tabWidth": 2, + "singleQuote": true, + "trailingComma": "none", + "sortImports": { + "newlinesBetween": true, + "groups": [ + "electron-internal", + "electron-scoped", + "electron", + "external", + "builtin", + ["sibling", "parent"], + "index", + "type", + "unknown" + ], + "customGroups": [ + { + "groupName": "electron-internal", + "elementNamePattern": ["@electron/internal", "@electron/internal/**"] + }, + { + "groupName": "electron-scoped", + "elementNamePattern": ["@electron/**"] + }, + { + "groupName": "electron", + "elementNamePattern": ["electron", "electron/**"] + } + ] + }, + "ignorePatterns": [ + "node_modules", + "out", + "ts-gen", + "spec/node_modules", + "spec/fixtures/native-addon", + ".github/workflows/node_modules", + "docs/fiddles", + "shell/browser/resources/win/resource.h", + "shell/common/node_includes.h", + "spec/fixtures/pages/jquery-3.6.0.min.js" + ] +} diff --git a/.oxlintrc.json b/.oxlintrc.json new file mode 100644 index 0000000000000..2cfc85aaa3c46 --- /dev/null +++ b/.oxlintrc.json @@ -0,0 +1,329 @@ +{ + "$schema": "./node_modules/oxlint/configuration_schema.json", + "plugins": [ + "typescript", + "import", + "node", + "promise", + "unicorn" + ], + "jsPlugins": [ + { + "name": "no-only-tests", + "specifier": "./script/lint-plugins/no-only-tests.mjs" + } + ], + "categories": { + "correctness": "off" + }, + "options": { + "typeAware": false + }, + "env": { + "builtin": true, + "browser": true + }, + "ignorePatterns": [ + ".github/workflows/node_modules", + "spec/node_modules", + "spec/fixtures/native-addon", + "shell/browser/resources/win/resource.h", + "shell/common/node_includes.h", + "spec/fixtures/pages/jquery-3.6.0.min.js" + ], + "rules": { + "no-var": "error", + "accessor-pairs": [ + "error", + { + "setWithoutGet": true, + "enforceForClassMembers": true + } + ], + "array-callback-return": [ + "error", + { + "allowImplicit": false, + "checkForEach": false + } + ], + "constructor-super": "error", + "curly": [ + "error", + "multi-line" + ], + "default-case-last": "error", + "eqeqeq": [ + "error", + "always", + { + "null": "ignore" + } + ], + "new-cap": [ + "error", + { + "newIsCap": true, + "capIsNew": false, + "properties": true + } + ], + "no-array-constructor": "error", + "no-async-promise-executor": "error", + "no-caller": "error", + "no-case-declarations": "error", + "no-class-assign": "error", + "no-compare-neg-zero": "error", + "no-cond-assign": "error", + "no-const-assign": "error", + "no-constant-condition": [ + "error", + { + "checkLoops": false + } + ], + "no-control-regex": "error", + "no-debugger": "error", + "no-delete-var": "error", + "no-dupe-class-members": "error", + "no-dupe-keys": "error", + "no-duplicate-case": "error", + "no-useless-backreference": "error", + "no-empty": [ + "error", + { + "allowEmptyCatch": true + } + ], + "no-empty-character-class": "error", + "no-empty-pattern": "error", + "no-eval": "error", + "no-ex-assign": "error", + "no-extend-native": "error", + "no-extra-bind": "error", + "no-extra-boolean-cast": "error", + "no-fallthrough": "error", + "no-func-assign": "error", + "no-global-assign": "error", + "no-import-assign": "error", + "no-invalid-regexp": "error", + "no-irregular-whitespace": "error", + "no-iterator": "error", + "no-labels": [ + "error", + { + "allowLoop": false, + "allowSwitch": false + } + ], + "no-lone-blocks": "error", + "no-loss-of-precision": "error", + "no-misleading-character-class": "error", + "no-prototype-builtins": "error", + "no-useless-catch": "error", + "no-useless-constructor": "error", + "no-use-before-define": [ + "error", + { + "functions": false, + "classes": false, + "variables": false + } + ], + "no-multi-str": "error", + "no-new": "error", + "no-new-func": "error", + "no-new-wrappers": "error", + "no-obj-calls": "error", + "no-proto": "error", + "no-redeclare": [ + "error" + ], + "no-regex-spaces": "error", + "no-return-assign": [ + "error", + "except-parens" + ], + "no-self-assign": [ + "error", + { + "props": true + } + ], + "no-self-compare": "error", + "no-sequences": "error", + "no-shadow-restricted-names": "error", + "no-sparse-arrays": "error", + "no-template-curly-in-string": "error", + "no-this-before-super": "error", + "no-throw-literal": "error", + "no-unexpected-multiline": "error", + "no-unmodified-loop-condition": "error", + "no-unneeded-ternary": [ + "error", + { + "defaultAssignment": false + } + ], + "no-unreachable": "error", + "no-unsafe-finally": "error", + "no-unsafe-negation": "error", + "no-unused-vars": [ + "error", + { + "vars": "all", + "args": "after-used", + "argsIgnorePattern": "^_", + "ignoreRestSiblings": true + } + ], + "no-useless-call": "error", + "no-useless-computed-key": "error", + "no-useless-escape": "error", + "no-useless-rename": "error", + "no-useless-return": "error", + "no-void": "error", + "no-with": "error", + "prefer-const": [ + "error", + { + "destructuring": "all" + } + ], + "prefer-promise-reject-errors": "error", + "symbol-description": "error", + "unicode-bom": [ + "error", + "never" + ], + "use-isnan": [ + "error", + { + "enforceForSwitchCase": true, + "enforceForIndexOf": true + } + ], + "valid-typeof": [ + "error", + { + "requireStringLiterals": true + } + ], + "yoda": [ + "error", + "never" + ], + "import/export": "error", + "import/first": "error", + "import/no-absolute-path": [ + "error", + { + "esmodule": true, + "commonjs": true, + "amd": false + } + ], + "import/no-duplicates": "error", + "import/no-named-default": "error", + "import/no-webpack-loader-syntax": "error", + "promise/param-names": "error", + "guard-for-in": "error", + "node/handle-callback-err": [ + "error", + "^(err|error)$" + ], + "node/no-exports-assign": "error", + "node/no-new-require": "error", + "node/no-path-concat": "error" + }, + "overrides": [ + { + "files": ["**/*.ts", "**/*.tsx", "**/*.mts", "**/*.cts"], + "rules": { + "no-use-before-define": "off" + } + }, + { + "files": ["lib/browser/**", "lib/utility/**"], + "rules": { + "no-restricted-imports": [ + "error", + { + "paths": ["electron", "electron/renderer"], + "patterns": [ + "./*", + "../*", + "@electron/internal/isolated_renderer/*", + "@electron/internal/renderer/*", + "@electron/internal/sandboxed_worker/*", + "@electron/internal/worker/*" + ] + } + ] + } + }, + { + "files": [ + "lib/renderer/**", + "lib/worker/**", + "lib/preload_realm/**", + "lib/sandboxed_renderer/**", + "lib/isolated_renderer/**" + ], + "rules": { + "no-restricted-imports": [ + "error", + { + "paths": ["electron", "electron/main"], + "patterns": ["./*", "../*", "@electron/internal/browser/*"] + } + ] + } + }, + { + "files": ["lib/common/**"], + "rules": { + "no-restricted-imports": [ + "error", + { + "paths": ["electron", "electron/main", "electron/renderer"], + "patterns": [ + "./*", + "../*", + "@electron/internal/browser/*", + "@electron/internal/isolated_renderer/*", + "@electron/internal/renderer/*", + "@electron/internal/sandboxed_worker/*", + "@electron/internal/worker/*" + ] + } + ] + } + }, + { + "files": [ + "build/**", + "script/**", + "docs/**", + "default_app/**", + "spec/**" + ], + "rules": { + "unicorn/prefer-node-protocol": "error" + } + }, + { + "files": ["spec/**/*.ts", "spec/**/*.js", "spec/**/*.mjs"], + "rules": { + "no-only-tests/no-only-tests": "error" + } + }, + { + "files": ["**/*.d.ts"], + "rules": { + "no-useless-constructor": "off", + "no-unused-vars": "off" + } + } + ] +} diff --git a/.remarkrc b/.remarkrc deleted file mode 100644 index a64b15136a418..0000000000000 --- a/.remarkrc +++ /dev/null @@ -1,6 +0,0 @@ -{ - "plugins": [ - ["remark-lint-code-block-style", "fenced"], - ["remark-lint-fenced-code-flag"] - ] -} \ No newline at end of file diff --git a/.yarn/README.md b/.yarn/README.md new file mode 100644 index 0000000000000..5e13264d4254e --- /dev/null +++ b/.yarn/README.md @@ -0,0 +1,82 @@ +# Vendored Yarn release + +This directory holds the Yarn release used by this repo (`yarnPath` in +`.yarnrc.yml`). The release file is checked in so every contributor and CI job +runs the exact same Yarn, and so we can carry small local patches when needed. + +`releases/yarn-4.12.0.cjs` currently carries one such patch, described below. +If you bump the Yarn version, read the **Upgrading Yarn** section first. + +## Patch: use `JsZipImpl` for the node-modules link step + +### What changed + +Two call sites in `releases/yarn-4.12.0.cjs` are modified so the +`node-modules` linker (and the `pnpm`-loose linker) construct their read-only +`ZipOpenFS` with `customZipImplementation: ST` — Yarn's pure-JS `JsZipImpl` — +instead of falling through to the default WASM-backed `LibZipImpl`: + +```text +new $f({maxOpenFiles:80,readOnlyArchives:!0}) + → new $f({maxOpenFiles:80,readOnlyArchives:!0,customZipImplementation:ST}) +``` + +A comment block at the top of the `.cjs` file marks the file as patched and +points back here. + +### Why + +On the `linux-arm` CI test shards we run a 32-bit `arm32v7` container. During +`yarn install`'s **Link step**, Yarn opens up to 80 cache zips concurrently. +With `LibZipImpl`, each open zip is `readFileSync`'d into a Node `Buffer` +**and copied again into the WASM linear memory**, and every file read does a +WASM `_malloc(size)` for the entry. The WASM heap has to grow as a single +contiguous region of the 32-bit address space; once enough zips are resident, +the `_malloc` for a large entry — most often `typescript/lib/typescript.js` +(~9 MB inside a ~22 MB zip) — fails. + +Yarn's cross-FS `copyFilePromise` swallows the underlying error and re-throws +a generic one, so CI shows: + +```text +YN0001: While persisting .../typescript-patch-...zip/node_modules/typescript/ + EINVAL: invalid argument, copyfile '/node_modules/typescript/lib/typescript.js' -> '...' +``` + +The unmasked form (occasionally seen on `pdfjs-dist`) is the WASM-heap failure +string `Couldn't allocate enough memory`. This started failing ~1-in-3 +`linux-arm / test` shards at **Install Dependencies** on 2026-04-13, after +[#50692](https://github.com/electron/electron/pull/50692) grew the cache enough +to push the 32-bit process over the edge nondeterministically — e.g. +[run 24739817558](https://github.com/electron/electron/actions/runs/24739817558/job/72380803746). + +`JsZipImpl` avoids the problem entirely: it opens the zip by file descriptor, +reads only the central directory into memory, and `readSync`s individual +entries into ordinary Node `Buffer`s — **no WASM heap involved**. It is +read-only and path-based, which is exactly how the linker uses these archives. + +There is no `.yarnrc.yml` setting or environment variable to select the zip +implementation (verified against the bundle), so editing the vendored release +is the only way to switch it short of re-implementing the linker in a plugin. + +Upstream references: +[yarnpkg/berry#3972](https://github.com/yarnpkg/berry/issues/3972), +[yarnpkg/berry#6722](https://github.com/yarnpkg/berry/issues/6722), +[yarnpkg/berry#6550](https://github.com/yarnpkg/berry/issues/6550). + +### Upgrading Yarn + +When bumping `releases/yarn-*.cjs`: + +1. Check whether upstream now defaults `readOnlyArchives` opens to `JsZipImpl`, + or exposes a config knob for the zip implementation. If so, drop this patch. +2. Otherwise, re-apply: search the new bundle for + `maxOpenFiles:80,readOnlyArchives:!0` (the surrounding minified identifiers + will differ) and add `,customZipImplementation:` — that + symbol is whatever the new bundle exports as `JsZipImpl` from + `@yarnpkg/libzip`. +3. Re-add the header comment pointing back to this README. +4. Verify with + `rm -rf node_modules spec/node_modules && node script/yarn.js install --immutable --mode=skip-build` + and confirm `node_modules/typescript/lib/typescript.js` is byte-identical to + an unpatched install. diff --git a/.yarn/releases/yarn-4.12.0.cjs b/.yarn/releases/yarn-4.12.0.cjs new file mode 100755 index 0000000000000..13a19ed20c084 --- /dev/null +++ b/.yarn/releases/yarn-4.12.0.cjs @@ -0,0 +1,945 @@ +#!/usr/bin/env node +/* eslint-disable */ +//prettier-ignore +// ELECTRON PATCH: see .yarn/README.md — the node-modules linker uses JsZipImpl +// instead of the WASM LibZipImpl for read-only archive extraction to avoid +// 32-bit WASM-heap OOM during the link step on arm32 CI. +(()=>{var xGe=Object.create;var mU=Object.defineProperty;var kGe=Object.getOwnPropertyDescriptor;var QGe=Object.getOwnPropertyNames;var TGe=Object.getPrototypeOf,RGe=Object.prototype.hasOwnProperty;var Ie=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(e,r)=>(typeof require<"u"?require:e)[r]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+t+'" is not supported')});var Xe=(t,e)=>()=>(t&&(e=t(t=0)),e);var _=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports),Vt=(t,e)=>{for(var r in e)mU(t,r,{get:e[r],enumerable:!0})},FGe=(t,e,r,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of QGe(e))!RGe.call(t,a)&&a!==r&&mU(t,a,{get:()=>e[a],enumerable:!(s=kGe(e,a))||s.enumerable});return t};var ut=(t,e,r)=>(r=t!=null?xGe(TGe(t)):{},FGe(e||!t||!t.__esModule?mU(r,"default",{value:t,enumerable:!0}):r,t));var fi={};Vt(fi,{SAFE_TIME:()=>WZ,S_IFDIR:()=>JP,S_IFLNK:()=>KP,S_IFMT:()=>Mf,S_IFREG:()=>N2});var Mf,JP,N2,KP,WZ,YZ=Xe(()=>{Mf=61440,JP=16384,N2=32768,KP=40960,WZ=456789e3});var or={};Vt(or,{EBADF:()=>Mo,EBUSY:()=>NGe,EEXIST:()=>HGe,EINVAL:()=>LGe,EISDIR:()=>_Ge,ENOENT:()=>MGe,ENOSYS:()=>OGe,ENOTDIR:()=>UGe,ENOTEMPTY:()=>GGe,EOPNOTSUPP:()=>qGe,EROFS:()=>jGe,ERR_DIR_CLOSED:()=>yU});function Cc(t,e){return Object.assign(new Error(`${t}: ${e}`),{code:t})}function NGe(t){return Cc("EBUSY",t)}function OGe(t,e){return Cc("ENOSYS",`${t}, ${e}`)}function LGe(t){return Cc("EINVAL",`invalid argument, ${t}`)}function Mo(t){return Cc("EBADF",`bad file descriptor, ${t}`)}function MGe(t){return Cc("ENOENT",`no such file or directory, ${t}`)}function UGe(t){return Cc("ENOTDIR",`not a directory, ${t}`)}function _Ge(t){return Cc("EISDIR",`illegal operation on a directory, ${t}`)}function HGe(t){return Cc("EEXIST",`file already exists, ${t}`)}function jGe(t){return Cc("EROFS",`read-only filesystem, ${t}`)}function GGe(t){return Cc("ENOTEMPTY",`directory not empty, ${t}`)}function qGe(t){return Cc("EOPNOTSUPP",`operation not supported, ${t}`)}function yU(){return Cc("ERR_DIR_CLOSED","Directory handle was closed")}var zP=Xe(()=>{});var $a={};Vt($a,{BigIntStatsEntry:()=>iE,DEFAULT_MODE:()=>CU,DirEntry:()=>EU,StatEntry:()=>nE,areStatsEqual:()=>wU,clearStats:()=>XP,convertToBigIntStats:()=>YGe,makeDefaultStats:()=>VZ,makeEmptyStats:()=>WGe});function VZ(){return new nE}function WGe(){return XP(VZ())}function XP(t){for(let e in t)if(Object.hasOwn(t,e)){let r=t[e];typeof r=="number"?t[e]=0:typeof r=="bigint"?t[e]=BigInt(0):IU.types.isDate(r)&&(t[e]=new Date(0))}return t}function YGe(t){let e=new iE;for(let r in t)if(Object.hasOwn(t,r)){let s=t[r];typeof s=="number"?e[r]=BigInt(s):IU.types.isDate(s)&&(e[r]=new Date(s))}return e.atimeNs=e.atimeMs*BigInt(1e6),e.mtimeNs=e.mtimeMs*BigInt(1e6),e.ctimeNs=e.ctimeMs*BigInt(1e6),e.birthtimeNs=e.birthtimeMs*BigInt(1e6),e}function wU(t,e){if(t.atimeMs!==e.atimeMs||t.birthtimeMs!==e.birthtimeMs||t.blksize!==e.blksize||t.blocks!==e.blocks||t.ctimeMs!==e.ctimeMs||t.dev!==e.dev||t.gid!==e.gid||t.ino!==e.ino||t.isBlockDevice()!==e.isBlockDevice()||t.isCharacterDevice()!==e.isCharacterDevice()||t.isDirectory()!==e.isDirectory()||t.isFIFO()!==e.isFIFO()||t.isFile()!==e.isFile()||t.isSocket()!==e.isSocket()||t.isSymbolicLink()!==e.isSymbolicLink()||t.mode!==e.mode||t.mtimeMs!==e.mtimeMs||t.nlink!==e.nlink||t.rdev!==e.rdev||t.size!==e.size||t.uid!==e.uid)return!1;let r=t,s=e;return!(r.atimeNs!==s.atimeNs||r.mtimeNs!==s.mtimeNs||r.ctimeNs!==s.ctimeNs||r.birthtimeNs!==s.birthtimeNs)}var IU,CU,EU,nE,iE,BU=Xe(()=>{IU=ut(Ie("util")),CU=33188,EU=class{constructor(){this.name="";this.path="";this.mode=0}isBlockDevice(){return!1}isCharacterDevice(){return!1}isDirectory(){return(this.mode&61440)===16384}isFIFO(){return!1}isFile(){return(this.mode&61440)===32768}isSocket(){return!1}isSymbolicLink(){return(this.mode&61440)===40960}},nE=class{constructor(){this.uid=0;this.gid=0;this.size=0;this.blksize=0;this.atimeMs=0;this.mtimeMs=0;this.ctimeMs=0;this.birthtimeMs=0;this.atime=new Date(0);this.mtime=new Date(0);this.ctime=new Date(0);this.birthtime=new Date(0);this.dev=0;this.ino=0;this.mode=CU;this.nlink=1;this.rdev=0;this.blocks=1}isBlockDevice(){return!1}isCharacterDevice(){return!1}isDirectory(){return(this.mode&61440)===16384}isFIFO(){return!1}isFile(){return(this.mode&61440)===32768}isSocket(){return!1}isSymbolicLink(){return(this.mode&61440)===40960}},iE=class{constructor(){this.uid=BigInt(0);this.gid=BigInt(0);this.size=BigInt(0);this.blksize=BigInt(0);this.atimeMs=BigInt(0);this.mtimeMs=BigInt(0);this.ctimeMs=BigInt(0);this.birthtimeMs=BigInt(0);this.atimeNs=BigInt(0);this.mtimeNs=BigInt(0);this.ctimeNs=BigInt(0);this.birthtimeNs=BigInt(0);this.atime=new Date(0);this.mtime=new Date(0);this.ctime=new Date(0);this.birthtime=new Date(0);this.dev=BigInt(0);this.ino=BigInt(0);this.mode=BigInt(CU);this.nlink=BigInt(1);this.rdev=BigInt(0);this.blocks=BigInt(1)}isBlockDevice(){return!1}isCharacterDevice(){return!1}isDirectory(){return(this.mode&BigInt(61440))===BigInt(16384)}isFIFO(){return!1}isFile(){return(this.mode&BigInt(61440))===BigInt(32768)}isSocket(){return!1}isSymbolicLink(){return(this.mode&BigInt(61440))===BigInt(40960)}}});function XGe(t){let e,r;if(e=t.match(KGe))t=e[1];else if(r=t.match(zGe))t=`\\\\${r[1]?".\\":""}${r[2]}`;else return t;return t.replace(/\//g,"\\")}function ZGe(t){t=t.replace(/\\/g,"/");let e,r;return(e=t.match(VGe))?t=`/${e[1]}`:(r=t.match(JGe))&&(t=`/unc/${r[1]?".dot/":""}${r[2]}`),t}function ZP(t,e){return t===fe?KZ(e):vU(e)}var O2,vt,Er,fe,J,JZ,VGe,JGe,KGe,zGe,vU,KZ,el=Xe(()=>{O2=ut(Ie("path")),vt={root:"/",dot:".",parent:".."},Er={home:"~",nodeModules:"node_modules",manifest:"package.json",lockfile:"yarn.lock",virtual:"__virtual__",pnpJs:".pnp.js",pnpCjs:".pnp.cjs",pnpData:".pnp.data.json",pnpEsmLoader:".pnp.loader.mjs",rc:".yarnrc.yml",env:".env"},fe=Object.create(O2.default),J=Object.create(O2.default.posix);fe.cwd=()=>process.cwd();J.cwd=process.platform==="win32"?()=>vU(process.cwd()):process.cwd;process.platform==="win32"&&(J.resolve=(...t)=>t.length>0&&J.isAbsolute(t[0])?O2.default.posix.resolve(...t):O2.default.posix.resolve(J.cwd(),...t));JZ=function(t,e,r){return e=t.normalize(e),r=t.normalize(r),e===r?".":(e.endsWith(t.sep)||(e=e+t.sep),r.startsWith(e)?r.slice(e.length):null)};fe.contains=(t,e)=>JZ(fe,t,e);J.contains=(t,e)=>JZ(J,t,e);VGe=/^([a-zA-Z]:.*)$/,JGe=/^\/\/(\.\/)?(.*)$/,KGe=/^\/([a-zA-Z]:.*)$/,zGe=/^\/unc\/(\.dot\/)?(.*)$/;vU=process.platform==="win32"?ZGe:t=>t,KZ=process.platform==="win32"?XGe:t=>t;fe.fromPortablePath=KZ;fe.toPortablePath=vU});async function $P(t,e){let r="0123456789abcdef";await t.mkdirPromise(e.indexPath,{recursive:!0});let s=[];for(let a of r)for(let n of r)s.push(t.mkdirPromise(t.pathUtils.join(e.indexPath,`${a}${n}`),{recursive:!0}));return await Promise.all(s),e.indexPath}async function zZ(t,e,r,s,a){let n=t.pathUtils.normalize(e),c=r.pathUtils.normalize(s),f=[],p=[],{atime:h,mtime:E}=a.stableTime?{atime:dd,mtime:dd}:await r.lstatPromise(c);await t.mkdirpPromise(t.pathUtils.dirname(e),{utimes:[h,E]}),await SU(f,p,t,n,r,c,{...a,didParentExist:!0});for(let C of f)await C();await Promise.all(p.map(C=>C()))}async function SU(t,e,r,s,a,n,c){let f=c.didParentExist?await XZ(r,s):null,p=await a.lstatPromise(n),{atime:h,mtime:E}=c.stableTime?{atime:dd,mtime:dd}:p,C;switch(!0){case p.isDirectory():C=await e5e(t,e,r,s,f,a,n,p,c);break;case p.isFile():C=await n5e(t,e,r,s,f,a,n,p,c);break;case p.isSymbolicLink():C=await i5e(t,e,r,s,f,a,n,p,c);break;default:throw new Error(`Unsupported file type (${p.mode})`)}return(c.linkStrategy?.type!=="HardlinkFromIndex"||!p.isFile())&&((C||f?.mtime?.getTime()!==E.getTime()||f?.atime?.getTime()!==h.getTime())&&(e.push(()=>r.lutimesPromise(s,h,E)),C=!0),(f===null||(f.mode&511)!==(p.mode&511))&&(e.push(()=>r.chmodPromise(s,p.mode&511)),C=!0)),C}async function XZ(t,e){try{return await t.lstatPromise(e)}catch{return null}}async function e5e(t,e,r,s,a,n,c,f,p){if(a!==null&&!a.isDirectory())if(p.overwrite)t.push(async()=>r.removePromise(s)),a=null;else return!1;let h=!1;a===null&&(t.push(async()=>{try{await r.mkdirPromise(s,{mode:f.mode})}catch(S){if(S.code!=="EEXIST")throw S}}),h=!0);let E=await n.readdirPromise(c),C=p.didParentExist&&!a?{...p,didParentExist:!1}:p;if(p.stableSort)for(let S of E.sort())await SU(t,e,r,r.pathUtils.join(s,S),n,n.pathUtils.join(c,S),C)&&(h=!0);else(await Promise.all(E.map(async P=>{await SU(t,e,r,r.pathUtils.join(s,P),n,n.pathUtils.join(c,P),C)}))).some(P=>P)&&(h=!0);return h}async function t5e(t,e,r,s,a,n,c,f,p,h){let E=await n.checksumFilePromise(c,{algorithm:"sha1"}),C=420,S=f.mode&511,P=`${E}${S!==C?S.toString(8):""}`,I=r.pathUtils.join(h.indexPath,E.slice(0,2),`${P}.dat`),R;(le=>(le[le.Lock=0]="Lock",le[le.Rename=1]="Rename"))(R||={});let N=1,U=await XZ(r,I);if(a){let ie=U&&a.dev===U.dev&&a.ino===U.ino,ue=U?.mtimeMs!==$Ge;if(ie&&ue&&h.autoRepair&&(N=0,U=null),!ie)if(p.overwrite)t.push(async()=>r.removePromise(s)),a=null;else return!1}let W=!U&&N===1?`${I}.${Math.floor(Math.random()*4294967296).toString(16).padStart(8,"0")}`:null,ee=!1;return t.push(async()=>{if(!U&&(N===0&&await r.lockPromise(I,async()=>{let ie=await n.readFilePromise(c);await r.writeFilePromise(I,ie)}),N===1&&W)){let ie=await n.readFilePromise(c);await r.writeFilePromise(W,ie);try{await r.linkPromise(W,I)}catch(ue){if(ue.code==="EEXIST")ee=!0,await r.unlinkPromise(W);else throw ue}}a||await r.linkPromise(I,s)}),e.push(async()=>{U||(await r.lutimesPromise(I,dd,dd),S!==C&&await r.chmodPromise(I,S)),W&&!ee&&await r.unlinkPromise(W)}),!1}async function r5e(t,e,r,s,a,n,c,f,p){if(a!==null)if(p.overwrite)t.push(async()=>r.removePromise(s)),a=null;else return!1;return t.push(async()=>{let h=await n.readFilePromise(c);await r.writeFilePromise(s,h)}),!0}async function n5e(t,e,r,s,a,n,c,f,p){return p.linkStrategy?.type==="HardlinkFromIndex"?t5e(t,e,r,s,a,n,c,f,p,p.linkStrategy):r5e(t,e,r,s,a,n,c,f,p)}async function i5e(t,e,r,s,a,n,c,f,p){if(a!==null)if(p.overwrite)t.push(async()=>r.removePromise(s)),a=null;else return!1;return t.push(async()=>{await r.symlinkPromise(ZP(r.pathUtils,await n.readlinkPromise(c)),s)}),!0}var dd,$Ge,DU=Xe(()=>{el();dd=new Date(456789e3*1e3),$Ge=dd.getTime()});function ex(t,e,r,s){let a=()=>{let n=r.shift();if(typeof n>"u")return null;let c=t.pathUtils.join(e,n);return Object.assign(t.statSync(c),{name:n,path:void 0})};return new L2(e,a,s)}var L2,ZZ=Xe(()=>{zP();L2=class{constructor(e,r,s={}){this.path=e;this.nextDirent=r;this.opts=s;this.closed=!1}throwIfClosed(){if(this.closed)throw yU()}async*[Symbol.asyncIterator](){try{let e;for(;(e=await this.read())!==null;)yield e}finally{await this.close()}}read(e){let r=this.readSync();return typeof e<"u"?e(null,r):Promise.resolve(r)}readSync(){return this.throwIfClosed(),this.nextDirent()}close(e){return this.closeSync(),typeof e<"u"?e(null):Promise.resolve()}closeSync(){this.throwIfClosed(),this.opts.onClose?.(),this.closed=!0}}});function $Z(t,e){if(t!==e)throw new Error(`Invalid StatWatcher status: expected '${e}', got '${t}'`)}var e$,tx,t$=Xe(()=>{e$=Ie("events");BU();tx=class t extends e$.EventEmitter{constructor(r,s,{bigint:a=!1}={}){super();this.status="ready";this.changeListeners=new Map;this.startTimeout=null;this.fakeFs=r,this.path=s,this.bigint=a,this.lastStats=this.stat()}static create(r,s,a){let n=new t(r,s,a);return n.start(),n}start(){$Z(this.status,"ready"),this.status="running",this.startTimeout=setTimeout(()=>{this.startTimeout=null,this.fakeFs.existsSync(this.path)||this.emit("change",this.lastStats,this.lastStats)},3)}stop(){$Z(this.status,"running"),this.status="stopped",this.startTimeout!==null&&(clearTimeout(this.startTimeout),this.startTimeout=null),this.emit("stop")}stat(){try{return this.fakeFs.statSync(this.path,{bigint:this.bigint})}catch{let r=this.bigint?new iE:new nE;return XP(r)}}makeInterval(r){let s=setInterval(()=>{let a=this.stat(),n=this.lastStats;wU(a,n)||(this.lastStats=a,this.emit("change",a,n))},r.interval);return r.persistent?s:s.unref()}registerChangeListener(r,s){this.addListener("change",r),this.changeListeners.set(r,this.makeInterval(s))}unregisterChangeListener(r){this.removeListener("change",r);let s=this.changeListeners.get(r);typeof s<"u"&&clearInterval(s),this.changeListeners.delete(r)}unregisterAllChangeListeners(){for(let r of this.changeListeners.keys())this.unregisterChangeListener(r)}hasChangeListeners(){return this.changeListeners.size>0}ref(){for(let r of this.changeListeners.values())r.ref();return this}unref(){for(let r of this.changeListeners.values())r.unref();return this}}});function sE(t,e,r,s){let a,n,c,f;switch(typeof r){case"function":a=!1,n=!0,c=5007,f=r;break;default:({bigint:a=!1,persistent:n=!0,interval:c=5007}=r),f=s;break}let p=rx.get(t);typeof p>"u"&&rx.set(t,p=new Map);let h=p.get(e);return typeof h>"u"&&(h=tx.create(t,e,{bigint:a}),p.set(e,h)),h.registerChangeListener(f,{persistent:n,interval:c}),h}function md(t,e,r){let s=rx.get(t);if(typeof s>"u")return;let a=s.get(e);typeof a>"u"||(typeof r>"u"?a.unregisterAllChangeListeners():a.unregisterChangeListener(r),a.hasChangeListeners()||(a.stop(),s.delete(e)))}function yd(t){let e=rx.get(t);if(!(typeof e>"u"))for(let r of e.keys())md(t,r)}var rx,bU=Xe(()=>{t$();rx=new WeakMap});function s5e(t){let e=t.match(/\r?\n/g);if(e===null)return n$.EOL;let r=e.filter(a=>a===`\r +`).length,s=e.length-r;return r>s?`\r +`:` +`}function Ed(t,e){return e.replace(/\r?\n/g,s5e(t))}var r$,n$,mp,Uf,Id=Xe(()=>{r$=Ie("crypto"),n$=Ie("os");DU();el();mp=class{constructor(e){this.pathUtils=e}async*genTraversePromise(e,{stableSort:r=!1}={}){let s=[e];for(;s.length>0;){let a=s.shift();if((await this.lstatPromise(a)).isDirectory()){let c=await this.readdirPromise(a);if(r)for(let f of c.sort())s.push(this.pathUtils.join(a,f));else throw new Error("Not supported")}else yield a}}async checksumFilePromise(e,{algorithm:r="sha512"}={}){let s=await this.openPromise(e,"r");try{let n=Buffer.allocUnsafeSlow(65536),c=(0,r$.createHash)(r),f=0;for(;(f=await this.readPromise(s,n,0,65536))!==0;)c.update(f===65536?n:n.slice(0,f));return c.digest("hex")}finally{await this.closePromise(s)}}async removePromise(e,{recursive:r=!0,maxRetries:s=5}={}){let a;try{a=await this.lstatPromise(e)}catch(n){if(n.code==="ENOENT")return;throw n}if(a.isDirectory()){if(r){let n=await this.readdirPromise(e);await Promise.all(n.map(c=>this.removePromise(this.pathUtils.resolve(e,c))))}for(let n=0;n<=s;n++)try{await this.rmdirPromise(e);break}catch(c){if(c.code!=="EBUSY"&&c.code!=="ENOTEMPTY")throw c;nsetTimeout(f,n*100))}}else await this.unlinkPromise(e)}removeSync(e,{recursive:r=!0}={}){let s;try{s=this.lstatSync(e)}catch(a){if(a.code==="ENOENT")return;throw a}if(s.isDirectory()){if(r)for(let a of this.readdirSync(e))this.removeSync(this.pathUtils.resolve(e,a));this.rmdirSync(e)}else this.unlinkSync(e)}async mkdirpPromise(e,{chmod:r,utimes:s}={}){if(e=this.resolve(e),e===this.pathUtils.dirname(e))return;let a=e.split(this.pathUtils.sep),n;for(let c=2;c<=a.length;++c){let f=a.slice(0,c).join(this.pathUtils.sep);if(!this.existsSync(f)){try{await this.mkdirPromise(f)}catch(p){if(p.code==="EEXIST")continue;throw p}if(n??=f,r!=null&&await this.chmodPromise(f,r),s!=null)await this.utimesPromise(f,s[0],s[1]);else{let p=await this.statPromise(this.pathUtils.dirname(f));await this.utimesPromise(f,p.atime,p.mtime)}}}return n}mkdirpSync(e,{chmod:r,utimes:s}={}){if(e=this.resolve(e),e===this.pathUtils.dirname(e))return;let a=e.split(this.pathUtils.sep),n;for(let c=2;c<=a.length;++c){let f=a.slice(0,c).join(this.pathUtils.sep);if(!this.existsSync(f)){try{this.mkdirSync(f)}catch(p){if(p.code==="EEXIST")continue;throw p}if(n??=f,r!=null&&this.chmodSync(f,r),s!=null)this.utimesSync(f,s[0],s[1]);else{let p=this.statSync(this.pathUtils.dirname(f));this.utimesSync(f,p.atime,p.mtime)}}}return n}async copyPromise(e,r,{baseFs:s=this,overwrite:a=!0,stableSort:n=!1,stableTime:c=!1,linkStrategy:f=null}={}){return await zZ(this,e,s,r,{overwrite:a,stableSort:n,stableTime:c,linkStrategy:f})}copySync(e,r,{baseFs:s=this,overwrite:a=!0}={}){let n=s.lstatSync(r),c=this.existsSync(e);if(n.isDirectory()){this.mkdirpSync(e);let p=s.readdirSync(r);for(let h of p)this.copySync(this.pathUtils.join(e,h),s.pathUtils.join(r,h),{baseFs:s,overwrite:a})}else if(n.isFile()){if(!c||a){c&&this.removeSync(e);let p=s.readFileSync(r);this.writeFileSync(e,p)}}else if(n.isSymbolicLink()){if(!c||a){c&&this.removeSync(e);let p=s.readlinkSync(r);this.symlinkSync(ZP(this.pathUtils,p),e)}}else throw new Error(`Unsupported file type (file: ${r}, mode: 0o${n.mode.toString(8).padStart(6,"0")})`);let f=n.mode&511;this.chmodSync(e,f)}async changeFilePromise(e,r,s={}){return Buffer.isBuffer(r)?this.changeFileBufferPromise(e,r,s):this.changeFileTextPromise(e,r,s)}async changeFileBufferPromise(e,r,{mode:s}={}){let a=Buffer.alloc(0);try{a=await this.readFilePromise(e)}catch{}Buffer.compare(a,r)!==0&&await this.writeFilePromise(e,r,{mode:s})}async changeFileTextPromise(e,r,{automaticNewlines:s,mode:a}={}){let n="";try{n=await this.readFilePromise(e,"utf8")}catch{}let c=s?Ed(n,r):r;n!==c&&await this.writeFilePromise(e,c,{mode:a})}changeFileSync(e,r,s={}){return Buffer.isBuffer(r)?this.changeFileBufferSync(e,r,s):this.changeFileTextSync(e,r,s)}changeFileBufferSync(e,r,{mode:s}={}){let a=Buffer.alloc(0);try{a=this.readFileSync(e)}catch{}Buffer.compare(a,r)!==0&&this.writeFileSync(e,r,{mode:s})}changeFileTextSync(e,r,{automaticNewlines:s=!1,mode:a}={}){let n="";try{n=this.readFileSync(e,"utf8")}catch{}let c=s?Ed(n,r):r;n!==c&&this.writeFileSync(e,c,{mode:a})}async movePromise(e,r){try{await this.renamePromise(e,r)}catch(s){if(s.code==="EXDEV")await this.copyPromise(r,e),await this.removePromise(e);else throw s}}moveSync(e,r){try{this.renameSync(e,r)}catch(s){if(s.code==="EXDEV")this.copySync(r,e),this.removeSync(e);else throw s}}async lockPromise(e,r){let s=`${e}.flock`,a=1e3/60,n=Date.now(),c=null,f=async()=>{let p;try{[p]=await this.readJsonPromise(s)}catch{return Date.now()-n<500}try{return process.kill(p,0),!0}catch{return!1}};for(;c===null;)try{c=await this.openPromise(s,"wx")}catch(p){if(p.code==="EEXIST"){if(!await f())try{await this.unlinkPromise(s);continue}catch{}if(Date.now()-n<60*1e3)await new Promise(h=>setTimeout(h,a));else throw new Error(`Couldn't acquire a lock in a reasonable time (via ${s})`)}else throw p}await this.writePromise(c,JSON.stringify([process.pid]));try{return await r()}finally{try{await this.closePromise(c),await this.unlinkPromise(s)}catch{}}}async readJsonPromise(e){let r=await this.readFilePromise(e,"utf8");try{return JSON.parse(r)}catch(s){throw s.message+=` (in ${e})`,s}}readJsonSync(e){let r=this.readFileSync(e,"utf8");try{return JSON.parse(r)}catch(s){throw s.message+=` (in ${e})`,s}}async writeJsonPromise(e,r,{compact:s=!1}={}){let a=s?0:2;return await this.writeFilePromise(e,`${JSON.stringify(r,null,a)} +`)}writeJsonSync(e,r,{compact:s=!1}={}){let a=s?0:2;return this.writeFileSync(e,`${JSON.stringify(r,null,a)} +`)}async preserveTimePromise(e,r){let s=await this.lstatPromise(e),a=await r();typeof a<"u"&&(e=a),await this.lutimesPromise(e,s.atime,s.mtime)}async preserveTimeSync(e,r){let s=this.lstatSync(e),a=r();typeof a<"u"&&(e=a),this.lutimesSync(e,s.atime,s.mtime)}},Uf=class extends mp{constructor(){super(J)}}});var _s,yp=Xe(()=>{Id();_s=class extends mp{getExtractHint(e){return this.baseFs.getExtractHint(e)}resolve(e){return this.mapFromBase(this.baseFs.resolve(this.mapToBase(e)))}getRealPath(){return this.mapFromBase(this.baseFs.getRealPath())}async openPromise(e,r,s){return this.baseFs.openPromise(this.mapToBase(e),r,s)}openSync(e,r,s){return this.baseFs.openSync(this.mapToBase(e),r,s)}async opendirPromise(e,r){return Object.assign(await this.baseFs.opendirPromise(this.mapToBase(e),r),{path:e})}opendirSync(e,r){return Object.assign(this.baseFs.opendirSync(this.mapToBase(e),r),{path:e})}async readPromise(e,r,s,a,n){return await this.baseFs.readPromise(e,r,s,a,n)}readSync(e,r,s,a,n){return this.baseFs.readSync(e,r,s,a,n)}async writePromise(e,r,s,a,n){return typeof r=="string"?await this.baseFs.writePromise(e,r,s):await this.baseFs.writePromise(e,r,s,a,n)}writeSync(e,r,s,a,n){return typeof r=="string"?this.baseFs.writeSync(e,r,s):this.baseFs.writeSync(e,r,s,a,n)}async closePromise(e){return this.baseFs.closePromise(e)}closeSync(e){this.baseFs.closeSync(e)}createReadStream(e,r){return this.baseFs.createReadStream(e!==null?this.mapToBase(e):e,r)}createWriteStream(e,r){return this.baseFs.createWriteStream(e!==null?this.mapToBase(e):e,r)}async realpathPromise(e){return this.mapFromBase(await this.baseFs.realpathPromise(this.mapToBase(e)))}realpathSync(e){return this.mapFromBase(this.baseFs.realpathSync(this.mapToBase(e)))}async existsPromise(e){return this.baseFs.existsPromise(this.mapToBase(e))}existsSync(e){return this.baseFs.existsSync(this.mapToBase(e))}accessSync(e,r){return this.baseFs.accessSync(this.mapToBase(e),r)}async accessPromise(e,r){return this.baseFs.accessPromise(this.mapToBase(e),r)}async statPromise(e,r){return this.baseFs.statPromise(this.mapToBase(e),r)}statSync(e,r){return this.baseFs.statSync(this.mapToBase(e),r)}async fstatPromise(e,r){return this.baseFs.fstatPromise(e,r)}fstatSync(e,r){return this.baseFs.fstatSync(e,r)}lstatPromise(e,r){return this.baseFs.lstatPromise(this.mapToBase(e),r)}lstatSync(e,r){return this.baseFs.lstatSync(this.mapToBase(e),r)}async fchmodPromise(e,r){return this.baseFs.fchmodPromise(e,r)}fchmodSync(e,r){return this.baseFs.fchmodSync(e,r)}async chmodPromise(e,r){return this.baseFs.chmodPromise(this.mapToBase(e),r)}chmodSync(e,r){return this.baseFs.chmodSync(this.mapToBase(e),r)}async fchownPromise(e,r,s){return this.baseFs.fchownPromise(e,r,s)}fchownSync(e,r,s){return this.baseFs.fchownSync(e,r,s)}async chownPromise(e,r,s){return this.baseFs.chownPromise(this.mapToBase(e),r,s)}chownSync(e,r,s){return this.baseFs.chownSync(this.mapToBase(e),r,s)}async renamePromise(e,r){return this.baseFs.renamePromise(this.mapToBase(e),this.mapToBase(r))}renameSync(e,r){return this.baseFs.renameSync(this.mapToBase(e),this.mapToBase(r))}async copyFilePromise(e,r,s=0){return this.baseFs.copyFilePromise(this.mapToBase(e),this.mapToBase(r),s)}copyFileSync(e,r,s=0){return this.baseFs.copyFileSync(this.mapToBase(e),this.mapToBase(r),s)}async appendFilePromise(e,r,s){return this.baseFs.appendFilePromise(this.fsMapToBase(e),r,s)}appendFileSync(e,r,s){return this.baseFs.appendFileSync(this.fsMapToBase(e),r,s)}async writeFilePromise(e,r,s){return this.baseFs.writeFilePromise(this.fsMapToBase(e),r,s)}writeFileSync(e,r,s){return this.baseFs.writeFileSync(this.fsMapToBase(e),r,s)}async unlinkPromise(e){return this.baseFs.unlinkPromise(this.mapToBase(e))}unlinkSync(e){return this.baseFs.unlinkSync(this.mapToBase(e))}async utimesPromise(e,r,s){return this.baseFs.utimesPromise(this.mapToBase(e),r,s)}utimesSync(e,r,s){return this.baseFs.utimesSync(this.mapToBase(e),r,s)}async lutimesPromise(e,r,s){return this.baseFs.lutimesPromise(this.mapToBase(e),r,s)}lutimesSync(e,r,s){return this.baseFs.lutimesSync(this.mapToBase(e),r,s)}async mkdirPromise(e,r){return this.baseFs.mkdirPromise(this.mapToBase(e),r)}mkdirSync(e,r){return this.baseFs.mkdirSync(this.mapToBase(e),r)}async rmdirPromise(e,r){return this.baseFs.rmdirPromise(this.mapToBase(e),r)}rmdirSync(e,r){return this.baseFs.rmdirSync(this.mapToBase(e),r)}async rmPromise(e,r){return this.baseFs.rmPromise(this.mapToBase(e),r)}rmSync(e,r){return this.baseFs.rmSync(this.mapToBase(e),r)}async linkPromise(e,r){return this.baseFs.linkPromise(this.mapToBase(e),this.mapToBase(r))}linkSync(e,r){return this.baseFs.linkSync(this.mapToBase(e),this.mapToBase(r))}async symlinkPromise(e,r,s){let a=this.mapToBase(r);if(this.pathUtils.isAbsolute(e))return this.baseFs.symlinkPromise(this.mapToBase(e),a,s);let n=this.mapToBase(this.pathUtils.join(this.pathUtils.dirname(r),e)),c=this.baseFs.pathUtils.relative(this.baseFs.pathUtils.dirname(a),n);return this.baseFs.symlinkPromise(c,a,s)}symlinkSync(e,r,s){let a=this.mapToBase(r);if(this.pathUtils.isAbsolute(e))return this.baseFs.symlinkSync(this.mapToBase(e),a,s);let n=this.mapToBase(this.pathUtils.join(this.pathUtils.dirname(r),e)),c=this.baseFs.pathUtils.relative(this.baseFs.pathUtils.dirname(a),n);return this.baseFs.symlinkSync(c,a,s)}async readFilePromise(e,r){return this.baseFs.readFilePromise(this.fsMapToBase(e),r)}readFileSync(e,r){return this.baseFs.readFileSync(this.fsMapToBase(e),r)}readdirPromise(e,r){return this.baseFs.readdirPromise(this.mapToBase(e),r)}readdirSync(e,r){return this.baseFs.readdirSync(this.mapToBase(e),r)}async readlinkPromise(e){return this.mapFromBase(await this.baseFs.readlinkPromise(this.mapToBase(e)))}readlinkSync(e){return this.mapFromBase(this.baseFs.readlinkSync(this.mapToBase(e)))}async truncatePromise(e,r){return this.baseFs.truncatePromise(this.mapToBase(e),r)}truncateSync(e,r){return this.baseFs.truncateSync(this.mapToBase(e),r)}async ftruncatePromise(e,r){return this.baseFs.ftruncatePromise(e,r)}ftruncateSync(e,r){return this.baseFs.ftruncateSync(e,r)}watch(e,r,s){return this.baseFs.watch(this.mapToBase(e),r,s)}watchFile(e,r,s){return this.baseFs.watchFile(this.mapToBase(e),r,s)}unwatchFile(e,r){return this.baseFs.unwatchFile(this.mapToBase(e),r)}fsMapToBase(e){return typeof e=="number"?e:this.mapToBase(e)}}});var _f,i$=Xe(()=>{yp();_f=class extends _s{constructor(e,{baseFs:r,pathUtils:s}){super(s),this.target=e,this.baseFs=r}getRealPath(){return this.target}getBaseFs(){return this.baseFs}mapFromBase(e){return e}mapToBase(e){return e}}});function s$(t){let e=t;return typeof t.path=="string"&&(e.path=fe.toPortablePath(t.path)),e}var o$,Yn,Cd=Xe(()=>{o$=ut(Ie("fs"));Id();el();Yn=class extends Uf{constructor(e=o$.default){super(),this.realFs=e}getExtractHint(){return!1}getRealPath(){return vt.root}resolve(e){return J.resolve(e)}async openPromise(e,r,s){return await new Promise((a,n)=>{this.realFs.open(fe.fromPortablePath(e),r,s,this.makeCallback(a,n))})}openSync(e,r,s){return this.realFs.openSync(fe.fromPortablePath(e),r,s)}async opendirPromise(e,r){return await new Promise((s,a)=>{typeof r<"u"?this.realFs.opendir(fe.fromPortablePath(e),r,this.makeCallback(s,a)):this.realFs.opendir(fe.fromPortablePath(e),this.makeCallback(s,a))}).then(s=>{let a=s;return Object.defineProperty(a,"path",{value:e,configurable:!0,writable:!0}),a})}opendirSync(e,r){let a=typeof r<"u"?this.realFs.opendirSync(fe.fromPortablePath(e),r):this.realFs.opendirSync(fe.fromPortablePath(e));return Object.defineProperty(a,"path",{value:e,configurable:!0,writable:!0}),a}async readPromise(e,r,s=0,a=0,n=-1){return await new Promise((c,f)=>{this.realFs.read(e,r,s,a,n,(p,h)=>{p?f(p):c(h)})})}readSync(e,r,s,a,n){return this.realFs.readSync(e,r,s,a,n)}async writePromise(e,r,s,a,n){return await new Promise((c,f)=>typeof r=="string"?this.realFs.write(e,r,s,this.makeCallback(c,f)):this.realFs.write(e,r,s,a,n,this.makeCallback(c,f)))}writeSync(e,r,s,a,n){return typeof r=="string"?this.realFs.writeSync(e,r,s):this.realFs.writeSync(e,r,s,a,n)}async closePromise(e){await new Promise((r,s)=>{this.realFs.close(e,this.makeCallback(r,s))})}closeSync(e){this.realFs.closeSync(e)}createReadStream(e,r){let s=e!==null?fe.fromPortablePath(e):e;return this.realFs.createReadStream(s,r)}createWriteStream(e,r){let s=e!==null?fe.fromPortablePath(e):e;return this.realFs.createWriteStream(s,r)}async realpathPromise(e){return await new Promise((r,s)=>{this.realFs.realpath(fe.fromPortablePath(e),{},this.makeCallback(r,s))}).then(r=>fe.toPortablePath(r))}realpathSync(e){return fe.toPortablePath(this.realFs.realpathSync(fe.fromPortablePath(e),{}))}async existsPromise(e){return await new Promise(r=>{this.realFs.exists(fe.fromPortablePath(e),r)})}accessSync(e,r){return this.realFs.accessSync(fe.fromPortablePath(e),r)}async accessPromise(e,r){return await new Promise((s,a)=>{this.realFs.access(fe.fromPortablePath(e),r,this.makeCallback(s,a))})}existsSync(e){return this.realFs.existsSync(fe.fromPortablePath(e))}async statPromise(e,r){return await new Promise((s,a)=>{r?this.realFs.stat(fe.fromPortablePath(e),r,this.makeCallback(s,a)):this.realFs.stat(fe.fromPortablePath(e),this.makeCallback(s,a))})}statSync(e,r){return r?this.realFs.statSync(fe.fromPortablePath(e),r):this.realFs.statSync(fe.fromPortablePath(e))}async fstatPromise(e,r){return await new Promise((s,a)=>{r?this.realFs.fstat(e,r,this.makeCallback(s,a)):this.realFs.fstat(e,this.makeCallback(s,a))})}fstatSync(e,r){return r?this.realFs.fstatSync(e,r):this.realFs.fstatSync(e)}async lstatPromise(e,r){return await new Promise((s,a)=>{r?this.realFs.lstat(fe.fromPortablePath(e),r,this.makeCallback(s,a)):this.realFs.lstat(fe.fromPortablePath(e),this.makeCallback(s,a))})}lstatSync(e,r){return r?this.realFs.lstatSync(fe.fromPortablePath(e),r):this.realFs.lstatSync(fe.fromPortablePath(e))}async fchmodPromise(e,r){return await new Promise((s,a)=>{this.realFs.fchmod(e,r,this.makeCallback(s,a))})}fchmodSync(e,r){return this.realFs.fchmodSync(e,r)}async chmodPromise(e,r){return await new Promise((s,a)=>{this.realFs.chmod(fe.fromPortablePath(e),r,this.makeCallback(s,a))})}chmodSync(e,r){return this.realFs.chmodSync(fe.fromPortablePath(e),r)}async fchownPromise(e,r,s){return await new Promise((a,n)=>{this.realFs.fchown(e,r,s,this.makeCallback(a,n))})}fchownSync(e,r,s){return this.realFs.fchownSync(e,r,s)}async chownPromise(e,r,s){return await new Promise((a,n)=>{this.realFs.chown(fe.fromPortablePath(e),r,s,this.makeCallback(a,n))})}chownSync(e,r,s){return this.realFs.chownSync(fe.fromPortablePath(e),r,s)}async renamePromise(e,r){return await new Promise((s,a)=>{this.realFs.rename(fe.fromPortablePath(e),fe.fromPortablePath(r),this.makeCallback(s,a))})}renameSync(e,r){return this.realFs.renameSync(fe.fromPortablePath(e),fe.fromPortablePath(r))}async copyFilePromise(e,r,s=0){return await new Promise((a,n)=>{this.realFs.copyFile(fe.fromPortablePath(e),fe.fromPortablePath(r),s,this.makeCallback(a,n))})}copyFileSync(e,r,s=0){return this.realFs.copyFileSync(fe.fromPortablePath(e),fe.fromPortablePath(r),s)}async appendFilePromise(e,r,s){return await new Promise((a,n)=>{let c=typeof e=="string"?fe.fromPortablePath(e):e;s?this.realFs.appendFile(c,r,s,this.makeCallback(a,n)):this.realFs.appendFile(c,r,this.makeCallback(a,n))})}appendFileSync(e,r,s){let a=typeof e=="string"?fe.fromPortablePath(e):e;s?this.realFs.appendFileSync(a,r,s):this.realFs.appendFileSync(a,r)}async writeFilePromise(e,r,s){return await new Promise((a,n)=>{let c=typeof e=="string"?fe.fromPortablePath(e):e;s?this.realFs.writeFile(c,r,s,this.makeCallback(a,n)):this.realFs.writeFile(c,r,this.makeCallback(a,n))})}writeFileSync(e,r,s){let a=typeof e=="string"?fe.fromPortablePath(e):e;s?this.realFs.writeFileSync(a,r,s):this.realFs.writeFileSync(a,r)}async unlinkPromise(e){return await new Promise((r,s)=>{this.realFs.unlink(fe.fromPortablePath(e),this.makeCallback(r,s))})}unlinkSync(e){return this.realFs.unlinkSync(fe.fromPortablePath(e))}async utimesPromise(e,r,s){return await new Promise((a,n)=>{this.realFs.utimes(fe.fromPortablePath(e),r,s,this.makeCallback(a,n))})}utimesSync(e,r,s){this.realFs.utimesSync(fe.fromPortablePath(e),r,s)}async lutimesPromise(e,r,s){return await new Promise((a,n)=>{this.realFs.lutimes(fe.fromPortablePath(e),r,s,this.makeCallback(a,n))})}lutimesSync(e,r,s){this.realFs.lutimesSync(fe.fromPortablePath(e),r,s)}async mkdirPromise(e,r){return await new Promise((s,a)=>{this.realFs.mkdir(fe.fromPortablePath(e),r,this.makeCallback(s,a))})}mkdirSync(e,r){return this.realFs.mkdirSync(fe.fromPortablePath(e),r)}async rmdirPromise(e,r){return await new Promise((s,a)=>{r?this.realFs.rmdir(fe.fromPortablePath(e),r,this.makeCallback(s,a)):this.realFs.rmdir(fe.fromPortablePath(e),this.makeCallback(s,a))})}rmdirSync(e,r){return this.realFs.rmdirSync(fe.fromPortablePath(e),r)}async rmPromise(e,r){return await new Promise((s,a)=>{r?this.realFs.rm(fe.fromPortablePath(e),r,this.makeCallback(s,a)):this.realFs.rm(fe.fromPortablePath(e),this.makeCallback(s,a))})}rmSync(e,r){return this.realFs.rmSync(fe.fromPortablePath(e),r)}async linkPromise(e,r){return await new Promise((s,a)=>{this.realFs.link(fe.fromPortablePath(e),fe.fromPortablePath(r),this.makeCallback(s,a))})}linkSync(e,r){return this.realFs.linkSync(fe.fromPortablePath(e),fe.fromPortablePath(r))}async symlinkPromise(e,r,s){return await new Promise((a,n)=>{this.realFs.symlink(fe.fromPortablePath(e.replace(/\/+$/,"")),fe.fromPortablePath(r),s,this.makeCallback(a,n))})}symlinkSync(e,r,s){return this.realFs.symlinkSync(fe.fromPortablePath(e.replace(/\/+$/,"")),fe.fromPortablePath(r),s)}async readFilePromise(e,r){return await new Promise((s,a)=>{let n=typeof e=="string"?fe.fromPortablePath(e):e;this.realFs.readFile(n,r,this.makeCallback(s,a))})}readFileSync(e,r){let s=typeof e=="string"?fe.fromPortablePath(e):e;return this.realFs.readFileSync(s,r)}async readdirPromise(e,r){return await new Promise((s,a)=>{r?r.recursive&&process.platform==="win32"?r.withFileTypes?this.realFs.readdir(fe.fromPortablePath(e),r,this.makeCallback(n=>s(n.map(s$)),a)):this.realFs.readdir(fe.fromPortablePath(e),r,this.makeCallback(n=>s(n.map(fe.toPortablePath)),a)):this.realFs.readdir(fe.fromPortablePath(e),r,this.makeCallback(s,a)):this.realFs.readdir(fe.fromPortablePath(e),this.makeCallback(s,a))})}readdirSync(e,r){return r?r.recursive&&process.platform==="win32"?r.withFileTypes?this.realFs.readdirSync(fe.fromPortablePath(e),r).map(s$):this.realFs.readdirSync(fe.fromPortablePath(e),r).map(fe.toPortablePath):this.realFs.readdirSync(fe.fromPortablePath(e),r):this.realFs.readdirSync(fe.fromPortablePath(e))}async readlinkPromise(e){return await new Promise((r,s)=>{this.realFs.readlink(fe.fromPortablePath(e),this.makeCallback(r,s))}).then(r=>fe.toPortablePath(r))}readlinkSync(e){return fe.toPortablePath(this.realFs.readlinkSync(fe.fromPortablePath(e)))}async truncatePromise(e,r){return await new Promise((s,a)=>{this.realFs.truncate(fe.fromPortablePath(e),r,this.makeCallback(s,a))})}truncateSync(e,r){return this.realFs.truncateSync(fe.fromPortablePath(e),r)}async ftruncatePromise(e,r){return await new Promise((s,a)=>{this.realFs.ftruncate(e,r,this.makeCallback(s,a))})}ftruncateSync(e,r){return this.realFs.ftruncateSync(e,r)}watch(e,r,s){return this.realFs.watch(fe.fromPortablePath(e),r,s)}watchFile(e,r,s){return this.realFs.watchFile(fe.fromPortablePath(e),r,s)}unwatchFile(e,r){return this.realFs.unwatchFile(fe.fromPortablePath(e),r)}makeCallback(e,r){return(s,a)=>{s?r(s):e(a)}}}});var Sn,a$=Xe(()=>{Cd();yp();el();Sn=class extends _s{constructor(e,{baseFs:r=new Yn}={}){super(J),this.target=this.pathUtils.normalize(e),this.baseFs=r}getRealPath(){return this.pathUtils.resolve(this.baseFs.getRealPath(),this.target)}resolve(e){return this.pathUtils.isAbsolute(e)?J.normalize(e):this.baseFs.resolve(J.join(this.target,e))}mapFromBase(e){return e}mapToBase(e){return this.pathUtils.isAbsolute(e)?e:this.pathUtils.join(this.target,e)}}});var l$,Hf,c$=Xe(()=>{Cd();yp();el();l$=vt.root,Hf=class extends _s{constructor(e,{baseFs:r=new Yn}={}){super(J),this.target=this.pathUtils.resolve(vt.root,e),this.baseFs=r}getRealPath(){return this.pathUtils.resolve(this.baseFs.getRealPath(),this.pathUtils.relative(vt.root,this.target))}getTarget(){return this.target}getBaseFs(){return this.baseFs}mapToBase(e){let r=this.pathUtils.normalize(e);if(this.pathUtils.isAbsolute(e))return this.pathUtils.resolve(this.target,this.pathUtils.relative(l$,e));if(r.match(/^\.\.\/?/))throw new Error(`Resolving this path (${e}) would escape the jail`);return this.pathUtils.resolve(this.target,e)}mapFromBase(e){return this.pathUtils.resolve(l$,this.pathUtils.relative(this.target,e))}}});var oE,u$=Xe(()=>{yp();oE=class extends _s{constructor(r,s){super(s);this.instance=null;this.factory=r}get baseFs(){return this.instance||(this.instance=this.factory()),this.instance}set baseFs(r){this.instance=r}mapFromBase(r){return r}mapToBase(r){return r}}});var wd,tl,e0,f$=Xe(()=>{wd=Ie("fs");Id();Cd();bU();zP();el();tl=4278190080,e0=class extends Uf{constructor({baseFs:r=new Yn,filter:s=null,magicByte:a=42,maxOpenFiles:n=1/0,useCache:c=!0,maxAge:f=5e3,typeCheck:p=wd.constants.S_IFREG,getMountPoint:h,factoryPromise:E,factorySync:C}){if(Math.floor(a)!==a||!(a>1&&a<=127))throw new Error("The magic byte must be set to a round value between 1 and 127 included");super();this.fdMap=new Map;this.nextFd=3;this.isMount=new Set;this.notMount=new Set;this.realPaths=new Map;this.limitOpenFilesTimeout=null;this.baseFs=r,this.mountInstances=c?new Map:null,this.factoryPromise=E,this.factorySync=C,this.filter=s,this.getMountPoint=h,this.magic=a<<24,this.maxAge=f,this.maxOpenFiles=n,this.typeCheck=p}getExtractHint(r){return this.baseFs.getExtractHint(r)}getRealPath(){return this.baseFs.getRealPath()}saveAndClose(){if(yd(this),this.mountInstances)for(let[r,{childFs:s}]of this.mountInstances.entries())s.saveAndClose?.(),this.mountInstances.delete(r)}discardAndClose(){if(yd(this),this.mountInstances)for(let[r,{childFs:s}]of this.mountInstances.entries())s.discardAndClose?.(),this.mountInstances.delete(r)}resolve(r){return this.baseFs.resolve(r)}remapFd(r,s){let a=this.nextFd++|this.magic;return this.fdMap.set(a,[r,s]),a}async openPromise(r,s,a){return await this.makeCallPromise(r,async()=>await this.baseFs.openPromise(r,s,a),async(n,{subPath:c})=>this.remapFd(n,await n.openPromise(c,s,a)))}openSync(r,s,a){return this.makeCallSync(r,()=>this.baseFs.openSync(r,s,a),(n,{subPath:c})=>this.remapFd(n,n.openSync(c,s,a)))}async opendirPromise(r,s){return await this.makeCallPromise(r,async()=>await this.baseFs.opendirPromise(r,s),async(a,{subPath:n})=>await a.opendirPromise(n,s),{requireSubpath:!1})}opendirSync(r,s){return this.makeCallSync(r,()=>this.baseFs.opendirSync(r,s),(a,{subPath:n})=>a.opendirSync(n,s),{requireSubpath:!1})}async readPromise(r,s,a,n,c){if((r&tl)!==this.magic)return await this.baseFs.readPromise(r,s,a,n,c);let f=this.fdMap.get(r);if(typeof f>"u")throw Mo("read");let[p,h]=f;return await p.readPromise(h,s,a,n,c)}readSync(r,s,a,n,c){if((r&tl)!==this.magic)return this.baseFs.readSync(r,s,a,n,c);let f=this.fdMap.get(r);if(typeof f>"u")throw Mo("readSync");let[p,h]=f;return p.readSync(h,s,a,n,c)}async writePromise(r,s,a,n,c){if((r&tl)!==this.magic)return typeof s=="string"?await this.baseFs.writePromise(r,s,a):await this.baseFs.writePromise(r,s,a,n,c);let f=this.fdMap.get(r);if(typeof f>"u")throw Mo("write");let[p,h]=f;return typeof s=="string"?await p.writePromise(h,s,a):await p.writePromise(h,s,a,n,c)}writeSync(r,s,a,n,c){if((r&tl)!==this.magic)return typeof s=="string"?this.baseFs.writeSync(r,s,a):this.baseFs.writeSync(r,s,a,n,c);let f=this.fdMap.get(r);if(typeof f>"u")throw Mo("writeSync");let[p,h]=f;return typeof s=="string"?p.writeSync(h,s,a):p.writeSync(h,s,a,n,c)}async closePromise(r){if((r&tl)!==this.magic)return await this.baseFs.closePromise(r);let s=this.fdMap.get(r);if(typeof s>"u")throw Mo("close");this.fdMap.delete(r);let[a,n]=s;return await a.closePromise(n)}closeSync(r){if((r&tl)!==this.magic)return this.baseFs.closeSync(r);let s=this.fdMap.get(r);if(typeof s>"u")throw Mo("closeSync");this.fdMap.delete(r);let[a,n]=s;return a.closeSync(n)}createReadStream(r,s){return r===null?this.baseFs.createReadStream(r,s):this.makeCallSync(r,()=>this.baseFs.createReadStream(r,s),(a,{archivePath:n,subPath:c})=>{let f=a.createReadStream(c,s);return f.path=fe.fromPortablePath(this.pathUtils.join(n,c)),f})}createWriteStream(r,s){return r===null?this.baseFs.createWriteStream(r,s):this.makeCallSync(r,()=>this.baseFs.createWriteStream(r,s),(a,{subPath:n})=>a.createWriteStream(n,s))}async realpathPromise(r){return await this.makeCallPromise(r,async()=>await this.baseFs.realpathPromise(r),async(s,{archivePath:a,subPath:n})=>{let c=this.realPaths.get(a);return typeof c>"u"&&(c=await this.baseFs.realpathPromise(a),this.realPaths.set(a,c)),this.pathUtils.join(c,this.pathUtils.relative(vt.root,await s.realpathPromise(n)))})}realpathSync(r){return this.makeCallSync(r,()=>this.baseFs.realpathSync(r),(s,{archivePath:a,subPath:n})=>{let c=this.realPaths.get(a);return typeof c>"u"&&(c=this.baseFs.realpathSync(a),this.realPaths.set(a,c)),this.pathUtils.join(c,this.pathUtils.relative(vt.root,s.realpathSync(n)))})}async existsPromise(r){return await this.makeCallPromise(r,async()=>await this.baseFs.existsPromise(r),async(s,{subPath:a})=>await s.existsPromise(a))}existsSync(r){return this.makeCallSync(r,()=>this.baseFs.existsSync(r),(s,{subPath:a})=>s.existsSync(a))}async accessPromise(r,s){return await this.makeCallPromise(r,async()=>await this.baseFs.accessPromise(r,s),async(a,{subPath:n})=>await a.accessPromise(n,s))}accessSync(r,s){return this.makeCallSync(r,()=>this.baseFs.accessSync(r,s),(a,{subPath:n})=>a.accessSync(n,s))}async statPromise(r,s){return await this.makeCallPromise(r,async()=>await this.baseFs.statPromise(r,s),async(a,{subPath:n})=>await a.statPromise(n,s))}statSync(r,s){return this.makeCallSync(r,()=>this.baseFs.statSync(r,s),(a,{subPath:n})=>a.statSync(n,s))}async fstatPromise(r,s){if((r&tl)!==this.magic)return this.baseFs.fstatPromise(r,s);let a=this.fdMap.get(r);if(typeof a>"u")throw Mo("fstat");let[n,c]=a;return n.fstatPromise(c,s)}fstatSync(r,s){if((r&tl)!==this.magic)return this.baseFs.fstatSync(r,s);let a=this.fdMap.get(r);if(typeof a>"u")throw Mo("fstatSync");let[n,c]=a;return n.fstatSync(c,s)}async lstatPromise(r,s){return await this.makeCallPromise(r,async()=>await this.baseFs.lstatPromise(r,s),async(a,{subPath:n})=>await a.lstatPromise(n,s))}lstatSync(r,s){return this.makeCallSync(r,()=>this.baseFs.lstatSync(r,s),(a,{subPath:n})=>a.lstatSync(n,s))}async fchmodPromise(r,s){if((r&tl)!==this.magic)return this.baseFs.fchmodPromise(r,s);let a=this.fdMap.get(r);if(typeof a>"u")throw Mo("fchmod");let[n,c]=a;return n.fchmodPromise(c,s)}fchmodSync(r,s){if((r&tl)!==this.magic)return this.baseFs.fchmodSync(r,s);let a=this.fdMap.get(r);if(typeof a>"u")throw Mo("fchmodSync");let[n,c]=a;return n.fchmodSync(c,s)}async chmodPromise(r,s){return await this.makeCallPromise(r,async()=>await this.baseFs.chmodPromise(r,s),async(a,{subPath:n})=>await a.chmodPromise(n,s))}chmodSync(r,s){return this.makeCallSync(r,()=>this.baseFs.chmodSync(r,s),(a,{subPath:n})=>a.chmodSync(n,s))}async fchownPromise(r,s,a){if((r&tl)!==this.magic)return this.baseFs.fchownPromise(r,s,a);let n=this.fdMap.get(r);if(typeof n>"u")throw Mo("fchown");let[c,f]=n;return c.fchownPromise(f,s,a)}fchownSync(r,s,a){if((r&tl)!==this.magic)return this.baseFs.fchownSync(r,s,a);let n=this.fdMap.get(r);if(typeof n>"u")throw Mo("fchownSync");let[c,f]=n;return c.fchownSync(f,s,a)}async chownPromise(r,s,a){return await this.makeCallPromise(r,async()=>await this.baseFs.chownPromise(r,s,a),async(n,{subPath:c})=>await n.chownPromise(c,s,a))}chownSync(r,s,a){return this.makeCallSync(r,()=>this.baseFs.chownSync(r,s,a),(n,{subPath:c})=>n.chownSync(c,s,a))}async renamePromise(r,s){return await this.makeCallPromise(r,async()=>await this.makeCallPromise(s,async()=>await this.baseFs.renamePromise(r,s),async()=>{throw Object.assign(new Error("EEXDEV: cross-device link not permitted"),{code:"EEXDEV"})}),async(a,{subPath:n})=>await this.makeCallPromise(s,async()=>{throw Object.assign(new Error("EEXDEV: cross-device link not permitted"),{code:"EEXDEV"})},async(c,{subPath:f})=>{if(a!==c)throw Object.assign(new Error("EEXDEV: cross-device link not permitted"),{code:"EEXDEV"});return await a.renamePromise(n,f)}))}renameSync(r,s){return this.makeCallSync(r,()=>this.makeCallSync(s,()=>this.baseFs.renameSync(r,s),()=>{throw Object.assign(new Error("EEXDEV: cross-device link not permitted"),{code:"EEXDEV"})}),(a,{subPath:n})=>this.makeCallSync(s,()=>{throw Object.assign(new Error("EEXDEV: cross-device link not permitted"),{code:"EEXDEV"})},(c,{subPath:f})=>{if(a!==c)throw Object.assign(new Error("EEXDEV: cross-device link not permitted"),{code:"EEXDEV"});return a.renameSync(n,f)}))}async copyFilePromise(r,s,a=0){let n=async(c,f,p,h)=>{if(a&wd.constants.COPYFILE_FICLONE_FORCE)throw Object.assign(new Error(`EXDEV: cross-device clone not permitted, copyfile '${f}' -> ${h}'`),{code:"EXDEV"});if(a&wd.constants.COPYFILE_EXCL&&await this.existsPromise(f))throw Object.assign(new Error(`EEXIST: file already exists, copyfile '${f}' -> '${h}'`),{code:"EEXIST"});let E;try{E=await c.readFilePromise(f)}catch{throw Object.assign(new Error(`EINVAL: invalid argument, copyfile '${f}' -> '${h}'`),{code:"EINVAL"})}await p.writeFilePromise(h,E)};return await this.makeCallPromise(r,async()=>await this.makeCallPromise(s,async()=>await this.baseFs.copyFilePromise(r,s,a),async(c,{subPath:f})=>await n(this.baseFs,r,c,f)),async(c,{subPath:f})=>await this.makeCallPromise(s,async()=>await n(c,f,this.baseFs,s),async(p,{subPath:h})=>c!==p?await n(c,f,p,h):await c.copyFilePromise(f,h,a)))}copyFileSync(r,s,a=0){let n=(c,f,p,h)=>{if(a&wd.constants.COPYFILE_FICLONE_FORCE)throw Object.assign(new Error(`EXDEV: cross-device clone not permitted, copyfile '${f}' -> ${h}'`),{code:"EXDEV"});if(a&wd.constants.COPYFILE_EXCL&&this.existsSync(f))throw Object.assign(new Error(`EEXIST: file already exists, copyfile '${f}' -> '${h}'`),{code:"EEXIST"});let E;try{E=c.readFileSync(f)}catch{throw Object.assign(new Error(`EINVAL: invalid argument, copyfile '${f}' -> '${h}'`),{code:"EINVAL"})}p.writeFileSync(h,E)};return this.makeCallSync(r,()=>this.makeCallSync(s,()=>this.baseFs.copyFileSync(r,s,a),(c,{subPath:f})=>n(this.baseFs,r,c,f)),(c,{subPath:f})=>this.makeCallSync(s,()=>n(c,f,this.baseFs,s),(p,{subPath:h})=>c!==p?n(c,f,p,h):c.copyFileSync(f,h,a)))}async appendFilePromise(r,s,a){return await this.makeCallPromise(r,async()=>await this.baseFs.appendFilePromise(r,s,a),async(n,{subPath:c})=>await n.appendFilePromise(c,s,a))}appendFileSync(r,s,a){return this.makeCallSync(r,()=>this.baseFs.appendFileSync(r,s,a),(n,{subPath:c})=>n.appendFileSync(c,s,a))}async writeFilePromise(r,s,a){return await this.makeCallPromise(r,async()=>await this.baseFs.writeFilePromise(r,s,a),async(n,{subPath:c})=>await n.writeFilePromise(c,s,a))}writeFileSync(r,s,a){return this.makeCallSync(r,()=>this.baseFs.writeFileSync(r,s,a),(n,{subPath:c})=>n.writeFileSync(c,s,a))}async unlinkPromise(r){return await this.makeCallPromise(r,async()=>await this.baseFs.unlinkPromise(r),async(s,{subPath:a})=>await s.unlinkPromise(a))}unlinkSync(r){return this.makeCallSync(r,()=>this.baseFs.unlinkSync(r),(s,{subPath:a})=>s.unlinkSync(a))}async utimesPromise(r,s,a){return await this.makeCallPromise(r,async()=>await this.baseFs.utimesPromise(r,s,a),async(n,{subPath:c})=>await n.utimesPromise(c,s,a))}utimesSync(r,s,a){return this.makeCallSync(r,()=>this.baseFs.utimesSync(r,s,a),(n,{subPath:c})=>n.utimesSync(c,s,a))}async lutimesPromise(r,s,a){return await this.makeCallPromise(r,async()=>await this.baseFs.lutimesPromise(r,s,a),async(n,{subPath:c})=>await n.lutimesPromise(c,s,a))}lutimesSync(r,s,a){return this.makeCallSync(r,()=>this.baseFs.lutimesSync(r,s,a),(n,{subPath:c})=>n.lutimesSync(c,s,a))}async mkdirPromise(r,s){return await this.makeCallPromise(r,async()=>await this.baseFs.mkdirPromise(r,s),async(a,{subPath:n})=>await a.mkdirPromise(n,s))}mkdirSync(r,s){return this.makeCallSync(r,()=>this.baseFs.mkdirSync(r,s),(a,{subPath:n})=>a.mkdirSync(n,s))}async rmdirPromise(r,s){return await this.makeCallPromise(r,async()=>await this.baseFs.rmdirPromise(r,s),async(a,{subPath:n})=>await a.rmdirPromise(n,s))}rmdirSync(r,s){return this.makeCallSync(r,()=>this.baseFs.rmdirSync(r,s),(a,{subPath:n})=>a.rmdirSync(n,s))}async rmPromise(r,s){return await this.makeCallPromise(r,async()=>await this.baseFs.rmPromise(r,s),async(a,{subPath:n})=>await a.rmPromise(n,s))}rmSync(r,s){return this.makeCallSync(r,()=>this.baseFs.rmSync(r,s),(a,{subPath:n})=>a.rmSync(n,s))}async linkPromise(r,s){return await this.makeCallPromise(s,async()=>await this.baseFs.linkPromise(r,s),async(a,{subPath:n})=>await a.linkPromise(r,n))}linkSync(r,s){return this.makeCallSync(s,()=>this.baseFs.linkSync(r,s),(a,{subPath:n})=>a.linkSync(r,n))}async symlinkPromise(r,s,a){return await this.makeCallPromise(s,async()=>await this.baseFs.symlinkPromise(r,s,a),async(n,{subPath:c})=>await n.symlinkPromise(r,c))}symlinkSync(r,s,a){return this.makeCallSync(s,()=>this.baseFs.symlinkSync(r,s,a),(n,{subPath:c})=>n.symlinkSync(r,c))}async readFilePromise(r,s){return this.makeCallPromise(r,async()=>await this.baseFs.readFilePromise(r,s),async(a,{subPath:n})=>await a.readFilePromise(n,s))}readFileSync(r,s){return this.makeCallSync(r,()=>this.baseFs.readFileSync(r,s),(a,{subPath:n})=>a.readFileSync(n,s))}async readdirPromise(r,s){return await this.makeCallPromise(r,async()=>await this.baseFs.readdirPromise(r,s),async(a,{subPath:n})=>await a.readdirPromise(n,s),{requireSubpath:!1})}readdirSync(r,s){return this.makeCallSync(r,()=>this.baseFs.readdirSync(r,s),(a,{subPath:n})=>a.readdirSync(n,s),{requireSubpath:!1})}async readlinkPromise(r){return await this.makeCallPromise(r,async()=>await this.baseFs.readlinkPromise(r),async(s,{subPath:a})=>await s.readlinkPromise(a))}readlinkSync(r){return this.makeCallSync(r,()=>this.baseFs.readlinkSync(r),(s,{subPath:a})=>s.readlinkSync(a))}async truncatePromise(r,s){return await this.makeCallPromise(r,async()=>await this.baseFs.truncatePromise(r,s),async(a,{subPath:n})=>await a.truncatePromise(n,s))}truncateSync(r,s){return this.makeCallSync(r,()=>this.baseFs.truncateSync(r,s),(a,{subPath:n})=>a.truncateSync(n,s))}async ftruncatePromise(r,s){if((r&tl)!==this.magic)return this.baseFs.ftruncatePromise(r,s);let a=this.fdMap.get(r);if(typeof a>"u")throw Mo("ftruncate");let[n,c]=a;return n.ftruncatePromise(c,s)}ftruncateSync(r,s){if((r&tl)!==this.magic)return this.baseFs.ftruncateSync(r,s);let a=this.fdMap.get(r);if(typeof a>"u")throw Mo("ftruncateSync");let[n,c]=a;return n.ftruncateSync(c,s)}watch(r,s,a){return this.makeCallSync(r,()=>this.baseFs.watch(r,s,a),(n,{subPath:c})=>n.watch(c,s,a))}watchFile(r,s,a){return this.makeCallSync(r,()=>this.baseFs.watchFile(r,s,a),()=>sE(this,r,s,a))}unwatchFile(r,s){return this.makeCallSync(r,()=>this.baseFs.unwatchFile(r,s),()=>md(this,r,s))}async makeCallPromise(r,s,a,{requireSubpath:n=!0}={}){if(typeof r!="string")return await s();let c=this.resolve(r),f=this.findMount(c);return f?n&&f.subPath==="/"?await s():await this.getMountPromise(f.archivePath,async p=>await a(p,f)):await s()}makeCallSync(r,s,a,{requireSubpath:n=!0}={}){if(typeof r!="string")return s();let c=this.resolve(r),f=this.findMount(c);return!f||n&&f.subPath==="/"?s():this.getMountSync(f.archivePath,p=>a(p,f))}findMount(r){if(this.filter&&!this.filter.test(r))return null;let s="";for(;;){let a=r.substring(s.length),n=this.getMountPoint(a,s);if(!n)return null;if(s=this.pathUtils.join(s,n),!this.isMount.has(s)){if(this.notMount.has(s))continue;try{if(this.typeCheck!==null&&(this.baseFs.statSync(s).mode&wd.constants.S_IFMT)!==this.typeCheck){this.notMount.add(s);continue}}catch{return null}this.isMount.add(s)}return{archivePath:s,subPath:this.pathUtils.join(vt.root,r.substring(s.length))}}}limitOpenFiles(r){if(this.mountInstances===null)return;let s=Date.now(),a=s+this.maxAge,n=r===null?0:this.mountInstances.size-r;for(let[c,{childFs:f,expiresAt:p,refCount:h}]of this.mountInstances.entries())if(!(h!==0||f.hasOpenFileHandles?.())){if(s>=p){f.saveAndClose?.(),this.mountInstances.delete(c),n-=1;continue}else if(r===null||n<=0){a=p;break}f.saveAndClose?.(),this.mountInstances.delete(c),n-=1}this.limitOpenFilesTimeout===null&&(r===null&&this.mountInstances.size>0||r!==null)&&isFinite(a)&&(this.limitOpenFilesTimeout=setTimeout(()=>{this.limitOpenFilesTimeout=null,this.limitOpenFiles(null)},a-s).unref())}async getMountPromise(r,s){if(this.mountInstances){let a=this.mountInstances.get(r);if(!a){let n=await this.factoryPromise(this.baseFs,r);a=this.mountInstances.get(r),a||(a={childFs:n(),expiresAt:0,refCount:0})}this.mountInstances.delete(r),this.limitOpenFiles(this.maxOpenFiles-1),this.mountInstances.set(r,a),a.expiresAt=Date.now()+this.maxAge,a.refCount+=1;try{return await s(a.childFs)}finally{a.refCount-=1}}else{let a=(await this.factoryPromise(this.baseFs,r))();try{return await s(a)}finally{a.saveAndClose?.()}}}getMountSync(r,s){if(this.mountInstances){let a=this.mountInstances.get(r);return a||(a={childFs:this.factorySync(this.baseFs,r),expiresAt:0,refCount:0}),this.mountInstances.delete(r),this.limitOpenFiles(this.maxOpenFiles-1),this.mountInstances.set(r,a),a.expiresAt=Date.now()+this.maxAge,s(a.childFs)}else{let a=this.factorySync(this.baseFs,r);try{return s(a)}finally{a.saveAndClose?.()}}}}});var er,nx,A$=Xe(()=>{Id();el();er=()=>Object.assign(new Error("ENOSYS: unsupported filesystem access"),{code:"ENOSYS"}),nx=class t extends mp{static{this.instance=new t}constructor(){super(J)}getExtractHint(){throw er()}getRealPath(){throw er()}resolve(){throw er()}async openPromise(){throw er()}openSync(){throw er()}async opendirPromise(){throw er()}opendirSync(){throw er()}async readPromise(){throw er()}readSync(){throw er()}async writePromise(){throw er()}writeSync(){throw er()}async closePromise(){throw er()}closeSync(){throw er()}createWriteStream(){throw er()}createReadStream(){throw er()}async realpathPromise(){throw er()}realpathSync(){throw er()}async readdirPromise(){throw er()}readdirSync(){throw er()}async existsPromise(e){throw er()}existsSync(e){throw er()}async accessPromise(){throw er()}accessSync(){throw er()}async statPromise(){throw er()}statSync(){throw er()}async fstatPromise(e){throw er()}fstatSync(e){throw er()}async lstatPromise(e){throw er()}lstatSync(e){throw er()}async fchmodPromise(){throw er()}fchmodSync(){throw er()}async chmodPromise(){throw er()}chmodSync(){throw er()}async fchownPromise(){throw er()}fchownSync(){throw er()}async chownPromise(){throw er()}chownSync(){throw er()}async mkdirPromise(){throw er()}mkdirSync(){throw er()}async rmdirPromise(){throw er()}rmdirSync(){throw er()}async rmPromise(){throw er()}rmSync(){throw er()}async linkPromise(){throw er()}linkSync(){throw er()}async symlinkPromise(){throw er()}symlinkSync(){throw er()}async renamePromise(){throw er()}renameSync(){throw er()}async copyFilePromise(){throw er()}copyFileSync(){throw er()}async appendFilePromise(){throw er()}appendFileSync(){throw er()}async writeFilePromise(){throw er()}writeFileSync(){throw er()}async unlinkPromise(){throw er()}unlinkSync(){throw er()}async utimesPromise(){throw er()}utimesSync(){throw er()}async lutimesPromise(){throw er()}lutimesSync(){throw er()}async readFilePromise(){throw er()}readFileSync(){throw er()}async readlinkPromise(){throw er()}readlinkSync(){throw er()}async truncatePromise(){throw er()}truncateSync(){throw er()}async ftruncatePromise(e,r){throw er()}ftruncateSync(e,r){throw er()}watch(){throw er()}watchFile(){throw er()}unwatchFile(){throw er()}}});var t0,p$=Xe(()=>{yp();el();t0=class extends _s{constructor(e){super(fe),this.baseFs=e}mapFromBase(e){return fe.fromPortablePath(e)}mapToBase(e){return fe.toPortablePath(e)}}});var o5e,PU,a5e,uo,h$=Xe(()=>{Cd();yp();el();o5e=/^[0-9]+$/,PU=/^(\/(?:[^/]+\/)*?(?:\$\$virtual|__virtual__))((?:\/((?:[^/]+-)?[a-f0-9]+)(?:\/([^/]+))?)?((?:\/.*)?))$/,a5e=/^([^/]+-)?[a-f0-9]+$/,uo=class t extends _s{static makeVirtualPath(e,r,s){if(J.basename(e)!=="__virtual__")throw new Error('Assertion failed: Virtual folders must be named "__virtual__"');if(!J.basename(r).match(a5e))throw new Error("Assertion failed: Virtual components must be ended by an hexadecimal hash");let n=J.relative(J.dirname(e),s).split("/"),c=0;for(;c{xU=ut(Ie("buffer")),g$=Ie("url"),d$=Ie("util");yp();el();ix=class extends _s{constructor(e){super(fe),this.baseFs=e}mapFromBase(e){return e}mapToBase(e){if(typeof e=="string")return e;if(e instanceof URL)return(0,g$.fileURLToPath)(e);if(Buffer.isBuffer(e)){let r=e.toString();if(!l5e(e,r))throw new Error("Non-utf8 buffers are not supported at the moment. Please upvote the following issue if you encounter this error: https://github.com/yarnpkg/berry/issues/4942");return r}throw new Error(`Unsupported path type: ${(0,d$.inspect)(e)}`)}}});var w$,Uo,Ep,r0,sx,ox,aE,Ru,Fu,y$,E$,I$,C$,M2,B$=Xe(()=>{w$=Ie("readline"),Uo=Symbol("kBaseFs"),Ep=Symbol("kFd"),r0=Symbol("kClosePromise"),sx=Symbol("kCloseResolve"),ox=Symbol("kCloseReject"),aE=Symbol("kRefs"),Ru=Symbol("kRef"),Fu=Symbol("kUnref"),M2=class{constructor(e,r){this[C$]=1;this[I$]=void 0;this[E$]=void 0;this[y$]=void 0;this[Uo]=r,this[Ep]=e}get fd(){return this[Ep]}async appendFile(e,r){try{this[Ru](this.appendFile);let s=(typeof r=="string"?r:r?.encoding)??void 0;return await this[Uo].appendFilePromise(this.fd,e,s?{encoding:s}:void 0)}finally{this[Fu]()}}async chown(e,r){try{return this[Ru](this.chown),await this[Uo].fchownPromise(this.fd,e,r)}finally{this[Fu]()}}async chmod(e){try{return this[Ru](this.chmod),await this[Uo].fchmodPromise(this.fd,e)}finally{this[Fu]()}}createReadStream(e){return this[Uo].createReadStream(null,{...e,fd:this.fd})}createWriteStream(e){return this[Uo].createWriteStream(null,{...e,fd:this.fd})}datasync(){throw new Error("Method not implemented.")}sync(){throw new Error("Method not implemented.")}async read(e,r,s,a){try{this[Ru](this.read);let n,c;return ArrayBuffer.isView(e)?typeof r=="object"&&r!==null?(n=e,c=r?.offset??0,s=r?.length??n.byteLength-c,a=r?.position??null):(n=e,c=r??0,s??=0):(n=e?.buffer??Buffer.alloc(16384),c=e?.offset??0,s=e?.length??n.byteLength-c,a=e?.position??null),s===0?{bytesRead:s,buffer:n}:{bytesRead:await this[Uo].readPromise(this.fd,Buffer.isBuffer(n)?n:Buffer.from(n.buffer,n.byteOffset,n.byteLength),c,s,a),buffer:n}}finally{this[Fu]()}}async readFile(e){try{this[Ru](this.readFile);let r=(typeof e=="string"?e:e?.encoding)??void 0;return await this[Uo].readFilePromise(this.fd,r)}finally{this[Fu]()}}readLines(e){return(0,w$.createInterface)({input:this.createReadStream(e),crlfDelay:1/0})}async stat(e){try{return this[Ru](this.stat),await this[Uo].fstatPromise(this.fd,e)}finally{this[Fu]()}}async truncate(e){try{return this[Ru](this.truncate),await this[Uo].ftruncatePromise(this.fd,e)}finally{this[Fu]()}}utimes(e,r){throw new Error("Method not implemented.")}async writeFile(e,r){try{this[Ru](this.writeFile);let s=(typeof r=="string"?r:r?.encoding)??void 0;await this[Uo].writeFilePromise(this.fd,e,s)}finally{this[Fu]()}}async write(...e){try{if(this[Ru](this.write),ArrayBuffer.isView(e[0])){let[r,s,a,n]=e;return{bytesWritten:await this[Uo].writePromise(this.fd,r,s??void 0,a??void 0,n??void 0),buffer:r}}else{let[r,s,a]=e;return{bytesWritten:await this[Uo].writePromise(this.fd,r,s,a),buffer:r}}}finally{this[Fu]()}}async writev(e,r){try{this[Ru](this.writev);let s=0;if(typeof r<"u")for(let a of e){let n=await this.write(a,void 0,void 0,r);s+=n.bytesWritten,r+=n.bytesWritten}else for(let a of e){let n=await this.write(a);s+=n.bytesWritten}return{buffers:e,bytesWritten:s}}finally{this[Fu]()}}readv(e,r){throw new Error("Method not implemented.")}close(){if(this[Ep]===-1)return Promise.resolve();if(this[r0])return this[r0];if(this[aE]--,this[aE]===0){let e=this[Ep];this[Ep]=-1,this[r0]=this[Uo].closePromise(e).finally(()=>{this[r0]=void 0})}else this[r0]=new Promise((e,r)=>{this[sx]=e,this[ox]=r}).finally(()=>{this[r0]=void 0,this[ox]=void 0,this[sx]=void 0});return this[r0]}[(Uo,Ep,C$=aE,I$=r0,E$=sx,y$=ox,Ru)](e){if(this[Ep]===-1){let r=new Error("file closed");throw r.code="EBADF",r.syscall=e.name,r}this[aE]++}[Fu](){if(this[aE]--,this[aE]===0){let e=this[Ep];this[Ep]=-1,this[Uo].closePromise(e).then(this[sx],this[ox])}}}});function U2(t,e){e=new ix(e);let r=(s,a,n)=>{let c=s[a];s[a]=n,typeof c?.[lE.promisify.custom]<"u"&&(n[lE.promisify.custom]=c[lE.promisify.custom])};{r(t,"exists",(s,...a)=>{let c=typeof a[a.length-1]=="function"?a.pop():()=>{};process.nextTick(()=>{e.existsPromise(s).then(f=>{c(f)},()=>{c(!1)})})}),r(t,"read",(...s)=>{let[a,n,c,f,p,h]=s;if(s.length<=3){let E={};s.length<3?h=s[1]:(E=s[1],h=s[2]),{buffer:n=Buffer.alloc(16384),offset:c=0,length:f=n.byteLength,position:p}=E}if(c==null&&(c=0),f|=0,f===0){process.nextTick(()=>{h(null,0,n)});return}p==null&&(p=-1),process.nextTick(()=>{e.readPromise(a,n,c,f,p).then(E=>{h(null,E,n)},E=>{h(E,0,n)})})});for(let s of v$){let a=s.replace(/Promise$/,"");if(typeof t[a]>"u")continue;let n=e[s];if(typeof n>"u")continue;r(t,a,(...f)=>{let h=typeof f[f.length-1]=="function"?f.pop():()=>{};process.nextTick(()=>{n.apply(e,f).then(E=>{h(null,E)},E=>{h(E)})})})}t.realpath.native=t.realpath}{r(t,"existsSync",s=>{try{return e.existsSync(s)}catch{return!1}}),r(t,"readSync",(...s)=>{let[a,n,c,f,p]=s;return s.length<=3&&({offset:c=0,length:f=n.byteLength,position:p}=s[2]||{}),c==null&&(c=0),f|=0,f===0?0:(p==null&&(p=-1),e.readSync(a,n,c,f,p))});for(let s of c5e){let a=s;if(typeof t[a]>"u")continue;let n=e[s];typeof n>"u"||r(t,a,n.bind(e))}t.realpathSync.native=t.realpathSync}{let s=t.promises;for(let a of v$){let n=a.replace(/Promise$/,"");if(typeof s[n]>"u")continue;let c=e[a];typeof c>"u"||a!=="open"&&r(s,n,(f,...p)=>f instanceof M2?f[n].apply(f,p):c.call(e,f,...p))}r(s,"open",async(...a)=>{let n=await e.openPromise(...a);return new M2(n,e)})}t.read[lE.promisify.custom]=async(s,a,...n)=>({bytesRead:await e.readPromise(s,a,...n),buffer:a}),t.write[lE.promisify.custom]=async(s,a,...n)=>({bytesWritten:await e.writePromise(s,a,...n),buffer:a})}function ax(t,e){let r=Object.create(t);return U2(r,e),r}var lE,c5e,v$,S$=Xe(()=>{lE=Ie("util");m$();B$();c5e=new Set(["accessSync","appendFileSync","createReadStream","createWriteStream","chmodSync","fchmodSync","chownSync","fchownSync","closeSync","copyFileSync","linkSync","lstatSync","fstatSync","lutimesSync","mkdirSync","openSync","opendirSync","readlinkSync","readFileSync","readdirSync","readlinkSync","realpathSync","renameSync","rmdirSync","rmSync","statSync","symlinkSync","truncateSync","ftruncateSync","unlinkSync","unwatchFile","utimesSync","watch","watchFile","writeFileSync","writeSync"]),v$=new Set(["accessPromise","appendFilePromise","fchmodPromise","chmodPromise","fchownPromise","chownPromise","closePromise","copyFilePromise","linkPromise","fstatPromise","lstatPromise","lutimesPromise","mkdirPromise","openPromise","opendirPromise","readdirPromise","realpathPromise","readFilePromise","readdirPromise","readlinkPromise","renamePromise","rmdirPromise","rmPromise","statPromise","symlinkPromise","truncatePromise","ftruncatePromise","unlinkPromise","utimesPromise","writeFilePromise","writeSync"])});function D$(t){let e=Math.ceil(Math.random()*4294967296).toString(16).padStart(8,"0");return`${t}${e}`}function b$(){if(kU)return kU;let t=fe.toPortablePath(P$.default.tmpdir()),e=ce.realpathSync(t);return process.once("exit",()=>{ce.rmtempSync()}),kU={tmpdir:t,realTmpdir:e}}var P$,Nu,kU,ce,x$=Xe(()=>{P$=ut(Ie("os"));Cd();el();Nu=new Set,kU=null;ce=Object.assign(new Yn,{detachTemp(t){Nu.delete(t)},mktempSync(t){let{tmpdir:e,realTmpdir:r}=b$();for(;;){let s=D$("xfs-");try{this.mkdirSync(J.join(e,s))}catch(n){if(n.code==="EEXIST")continue;throw n}let a=J.join(r,s);if(Nu.add(a),typeof t>"u")return a;try{return t(a)}finally{if(Nu.has(a)){Nu.delete(a);try{this.removeSync(a)}catch{}}}}},async mktempPromise(t){let{tmpdir:e,realTmpdir:r}=b$();for(;;){let s=D$("xfs-");try{await this.mkdirPromise(J.join(e,s))}catch(n){if(n.code==="EEXIST")continue;throw n}let a=J.join(r,s);if(Nu.add(a),typeof t>"u")return a;try{return await t(a)}finally{if(Nu.has(a)){Nu.delete(a);try{await this.removePromise(a)}catch{}}}}},async rmtempPromise(){await Promise.all(Array.from(Nu.values()).map(async t=>{try{await ce.removePromise(t,{maxRetries:0}),Nu.delete(t)}catch{}}))},rmtempSync(){for(let t of Nu)try{ce.removeSync(t),Nu.delete(t)}catch{}}})});var _2={};Vt(_2,{AliasFS:()=>_f,BasePortableFakeFS:()=>Uf,CustomDir:()=>L2,CwdFS:()=>Sn,FakeFS:()=>mp,Filename:()=>Er,JailFS:()=>Hf,LazyFS:()=>oE,MountFS:()=>e0,NoFS:()=>nx,NodeFS:()=>Yn,PortablePath:()=>vt,PosixFS:()=>t0,ProxiedFS:()=>_s,VirtualFS:()=>uo,constants:()=>fi,errors:()=>or,extendFs:()=>ax,normalizeLineEndings:()=>Ed,npath:()=>fe,opendir:()=>ex,patchFs:()=>U2,ppath:()=>J,setupCopyIndex:()=>$P,statUtils:()=>$a,unwatchAllFiles:()=>yd,unwatchFile:()=>md,watchFile:()=>sE,xfs:()=>ce});var Dt=Xe(()=>{YZ();zP();BU();DU();ZZ();bU();Id();el();el();i$();Id();a$();c$();u$();f$();A$();Cd();p$();yp();h$();S$();x$()});var F$=_((Dkt,R$)=>{R$.exports=T$;T$.sync=f5e;var k$=Ie("fs");function u5e(t,e){var r=e.pathExt!==void 0?e.pathExt:process.env.PATHEXT;if(!r||(r=r.split(";"),r.indexOf("")!==-1))return!0;for(var s=0;s{M$.exports=O$;O$.sync=A5e;var N$=Ie("fs");function O$(t,e,r){N$.stat(t,function(s,a){r(s,s?!1:L$(a,e))})}function A5e(t,e){return L$(N$.statSync(t),e)}function L$(t,e){return t.isFile()&&p5e(t,e)}function p5e(t,e){var r=t.mode,s=t.uid,a=t.gid,n=e.uid!==void 0?e.uid:process.getuid&&process.getuid(),c=e.gid!==void 0?e.gid:process.getgid&&process.getgid(),f=parseInt("100",8),p=parseInt("010",8),h=parseInt("001",8),E=f|p,C=r&h||r&p&&a===c||r&f&&s===n||r&E&&n===0;return C}});var H$=_((xkt,_$)=>{var Pkt=Ie("fs"),lx;process.platform==="win32"||global.TESTING_WINDOWS?lx=F$():lx=U$();_$.exports=QU;QU.sync=h5e;function QU(t,e,r){if(typeof e=="function"&&(r=e,e={}),!r){if(typeof Promise!="function")throw new TypeError("callback not provided");return new Promise(function(s,a){QU(t,e||{},function(n,c){n?a(n):s(c)})})}lx(t,e||{},function(s,a){s&&(s.code==="EACCES"||e&&e.ignoreErrors)&&(s=null,a=!1),r(s,a)})}function h5e(t,e){try{return lx.sync(t,e||{})}catch(r){if(e&&e.ignoreErrors||r.code==="EACCES")return!1;throw r}}});var J$=_((kkt,V$)=>{var cE=process.platform==="win32"||process.env.OSTYPE==="cygwin"||process.env.OSTYPE==="msys",j$=Ie("path"),g5e=cE?";":":",G$=H$(),q$=t=>Object.assign(new Error(`not found: ${t}`),{code:"ENOENT"}),W$=(t,e)=>{let r=e.colon||g5e,s=t.match(/\//)||cE&&t.match(/\\/)?[""]:[...cE?[process.cwd()]:[],...(e.path||process.env.PATH||"").split(r)],a=cE?e.pathExt||process.env.PATHEXT||".EXE;.CMD;.BAT;.COM":"",n=cE?a.split(r):[""];return cE&&t.indexOf(".")!==-1&&n[0]!==""&&n.unshift(""),{pathEnv:s,pathExt:n,pathExtExe:a}},Y$=(t,e,r)=>{typeof e=="function"&&(r=e,e={}),e||(e={});let{pathEnv:s,pathExt:a,pathExtExe:n}=W$(t,e),c=[],f=h=>new Promise((E,C)=>{if(h===s.length)return e.all&&c.length?E(c):C(q$(t));let S=s[h],P=/^".*"$/.test(S)?S.slice(1,-1):S,I=j$.join(P,t),R=!P&&/^\.[\\\/]/.test(t)?t.slice(0,2)+I:I;E(p(R,h,0))}),p=(h,E,C)=>new Promise((S,P)=>{if(C===a.length)return S(f(E+1));let I=a[C];G$(h+I,{pathExt:n},(R,N)=>{if(!R&&N)if(e.all)c.push(h+I);else return S(h+I);return S(p(h,E,C+1))})});return r?f(0).then(h=>r(null,h),r):f(0)},d5e=(t,e)=>{e=e||{};let{pathEnv:r,pathExt:s,pathExtExe:a}=W$(t,e),n=[];for(let c=0;c{"use strict";var K$=(t={})=>{let e=t.env||process.env;return(t.platform||process.platform)!=="win32"?"PATH":Object.keys(e).reverse().find(s=>s.toUpperCase()==="PATH")||"Path"};TU.exports=K$;TU.exports.default=K$});var eee=_((Tkt,$$)=>{"use strict";var X$=Ie("path"),m5e=J$(),y5e=z$();function Z$(t,e){let r=t.options.env||process.env,s=process.cwd(),a=t.options.cwd!=null,n=a&&process.chdir!==void 0&&!process.chdir.disabled;if(n)try{process.chdir(t.options.cwd)}catch{}let c;try{c=m5e.sync(t.command,{path:r[y5e({env:r})],pathExt:e?X$.delimiter:void 0})}catch{}finally{n&&process.chdir(s)}return c&&(c=X$.resolve(a?t.options.cwd:"",c)),c}function E5e(t){return Z$(t)||Z$(t,!0)}$$.exports=E5e});var tee=_((Rkt,FU)=>{"use strict";var RU=/([()\][%!^"`<>&|;, *?])/g;function I5e(t){return t=t.replace(RU,"^$1"),t}function C5e(t,e){return t=`${t}`,t=t.replace(/(?=(\\+?)?)\1"/g,'$1$1\\"'),t=t.replace(/(?=(\\+?)?)\1$/,"$1$1"),t=`"${t}"`,t=t.replace(RU,"^$1"),e&&(t=t.replace(RU,"^$1")),t}FU.exports.command=I5e;FU.exports.argument=C5e});var nee=_((Fkt,ree)=>{"use strict";ree.exports=/^#!(.*)/});var see=_((Nkt,iee)=>{"use strict";var w5e=nee();iee.exports=(t="")=>{let e=t.match(w5e);if(!e)return null;let[r,s]=e[0].replace(/#! ?/,"").split(" "),a=r.split("/").pop();return a==="env"?s:s?`${a} ${s}`:a}});var aee=_((Okt,oee)=>{"use strict";var NU=Ie("fs"),B5e=see();function v5e(t){let r=Buffer.alloc(150),s;try{s=NU.openSync(t,"r"),NU.readSync(s,r,0,150,0),NU.closeSync(s)}catch{}return B5e(r.toString())}oee.exports=v5e});var fee=_((Lkt,uee)=>{"use strict";var S5e=Ie("path"),lee=eee(),cee=tee(),D5e=aee(),b5e=process.platform==="win32",P5e=/\.(?:com|exe)$/i,x5e=/node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i;function k5e(t){t.file=lee(t);let e=t.file&&D5e(t.file);return e?(t.args.unshift(t.file),t.command=e,lee(t)):t.file}function Q5e(t){if(!b5e)return t;let e=k5e(t),r=!P5e.test(e);if(t.options.forceShell||r){let s=x5e.test(e);t.command=S5e.normalize(t.command),t.command=cee.command(t.command),t.args=t.args.map(n=>cee.argument(n,s));let a=[t.command].concat(t.args).join(" ");t.args=["/d","/s","/c",`"${a}"`],t.command=process.env.comspec||"cmd.exe",t.options.windowsVerbatimArguments=!0}return t}function T5e(t,e,r){e&&!Array.isArray(e)&&(r=e,e=null),e=e?e.slice(0):[],r=Object.assign({},r);let s={command:t,args:e,options:r,file:void 0,original:{command:t,args:e}};return r.shell?s:Q5e(s)}uee.exports=T5e});var hee=_((Mkt,pee)=>{"use strict";var OU=process.platform==="win32";function LU(t,e){return Object.assign(new Error(`${e} ${t.command} ENOENT`),{code:"ENOENT",errno:"ENOENT",syscall:`${e} ${t.command}`,path:t.command,spawnargs:t.args})}function R5e(t,e){if(!OU)return;let r=t.emit;t.emit=function(s,a){if(s==="exit"){let n=Aee(a,e);if(n)return r.call(t,"error",n)}return r.apply(t,arguments)}}function Aee(t,e){return OU&&t===1&&!e.file?LU(e.original,"spawn"):null}function F5e(t,e){return OU&&t===1&&!e.file?LU(e.original,"spawnSync"):null}pee.exports={hookChildProcess:R5e,verifyENOENT:Aee,verifyENOENTSync:F5e,notFoundError:LU}});var _U=_((Ukt,uE)=>{"use strict";var gee=Ie("child_process"),MU=fee(),UU=hee();function dee(t,e,r){let s=MU(t,e,r),a=gee.spawn(s.command,s.args,s.options);return UU.hookChildProcess(a,s),a}function N5e(t,e,r){let s=MU(t,e,r),a=gee.spawnSync(s.command,s.args,s.options);return a.error=a.error||UU.verifyENOENTSync(a.status,s),a}uE.exports=dee;uE.exports.spawn=dee;uE.exports.sync=N5e;uE.exports._parse=MU;uE.exports._enoent=UU});var yee=_((_kt,mee)=>{"use strict";function O5e(t,e){function r(){this.constructor=t}r.prototype=e.prototype,t.prototype=new r}function Bd(t,e,r,s){this.message=t,this.expected=e,this.found=r,this.location=s,this.name="SyntaxError",typeof Error.captureStackTrace=="function"&&Error.captureStackTrace(this,Bd)}O5e(Bd,Error);Bd.buildMessage=function(t,e){var r={literal:function(h){return'"'+a(h.text)+'"'},class:function(h){var E="",C;for(C=0;C0){for(C=1,S=1;C>",b=ur(">>",!1),y=">&",F=ur(">&",!1),z=">",X=ur(">",!1),$="<<<",oe=ur("<<<",!1),xe="<&",Te=ur("<&",!1),lt="<",Ct=ur("<",!1),qt=function(O){return{type:"argument",segments:[].concat(...O)}},ir=function(O){return O},Pt="$'",gn=ur("$'",!1),Pr="'",Ir=ur("'",!1),Or=function(O){return[{type:"text",text:O}]},on='""',ai=ur('""',!1),Io=function(){return{type:"text",text:""}},rs='"',$s=ur('"',!1),Co=function(O){return O},ji=function(O){return{type:"arithmetic",arithmetic:O,quoted:!0}},eo=function(O){return{type:"shell",shell:O,quoted:!0}},wo=function(O){return{type:"variable",...O,quoted:!0}},QA=function(O){return{type:"text",text:O}},Af=function(O){return{type:"arithmetic",arithmetic:O,quoted:!1}},dh=function(O){return{type:"shell",shell:O,quoted:!1}},mh=function(O){return{type:"variable",...O,quoted:!1}},to=function(O){return{type:"glob",pattern:O}},jn=/^[^']/,Ts=zi(["'"],!0,!1),ro=function(O){return O.join("")},ou=/^[^$"]/,au=zi(["$",'"'],!0,!1),lu=`\\ +`,TA=ur(`\\ +`,!1),RA=function(){return""},oa="\\",aa=ur("\\",!1),FA=/^[\\$"`]/,gr=zi(["\\","$",'"',"`"],!1,!1),Bo=function(O){return O},Me="\\a",cu=ur("\\a",!1),Cr=function(){return"a"},pf="\\b",NA=ur("\\b",!1),OA=function(){return"\b"},uu=/^[Ee]/,fu=zi(["E","e"],!1,!1),oc=function(){return"\x1B"},ve="\\f",Nt=ur("\\f",!1),ac=function(){return"\f"},Oi="\\n",no=ur("\\n",!1),Rt=function(){return` +`},xn="\\r",la=ur("\\r",!1),Gi=function(){return"\r"},Li="\\t",Na=ur("\\t",!1),dn=function(){return" "},Kn="\\v",Au=ur("\\v",!1),yh=function(){return"\v"},Oa=/^[\\'"?]/,La=zi(["\\","'",'"',"?"],!1,!1),Ma=function(O){return String.fromCharCode(parseInt(O,16))},$e="\\x",Ua=ur("\\x",!1),hf="\\u",lc=ur("\\u",!1),wn="\\U",ca=ur("\\U",!1),LA=function(O){return String.fromCodePoint(parseInt(O,16))},MA=/^[0-7]/,ua=zi([["0","7"]],!1,!1),Bl=/^[0-9a-fA-f]/,Mt=zi([["0","9"],["a","f"],["A","f"]],!1,!1),kn=yf(),fa="{}",Ha=ur("{}",!1),ns=function(){return"{}"},cc="-",pu=ur("-",!1),uc="+",ja=ur("+",!1),Mi=".",Is=ur(".",!1),vl=function(O,K,re){return{type:"number",value:(O==="-"?-1:1)*parseFloat(K.join("")+"."+re.join(""))}},gf=function(O,K){return{type:"number",value:(O==="-"?-1:1)*parseInt(K.join(""))}},fc=function(O){return{type:"variable",...O}},wi=function(O){return{type:"variable",name:O}},Qn=function(O){return O},Ac="*",Ke=ur("*",!1),st="/",St=ur("/",!1),lr=function(O,K,re){return{type:K==="*"?"multiplication":"division",right:re}},te=function(O,K){return K.reduce((re,de)=>({left:re,...de}),O)},Ee=function(O,K,re){return{type:K==="+"?"addition":"subtraction",right:re}},Oe="$((",dt=ur("$((",!1),Et="))",bt=ur("))",!1),tr=function(O){return O},An="$(",li=ur("$(",!1),qi=function(O){return O},Tn="${",Ga=ur("${",!1),my=":-",Z1=ur(":-",!1),vo=function(O,K){return{name:O,defaultValue:K}},yy=":-}",Eh=ur(":-}",!1),$1=function(O){return{name:O,defaultValue:[]}},So=":+",Ih=ur(":+",!1),Ch=function(O,K){return{name:O,alternativeValue:K}},hu=":+}",wh=ur(":+}",!1),Fg=function(O){return{name:O,alternativeValue:[]}},Ng=function(O){return{name:O}},Og="$",Ey=ur("$",!1),df=function(O){return e.isGlobPattern(O)},Do=function(O){return O},Sl=/^[a-zA-Z0-9_]/,Bh=zi([["a","z"],["A","Z"],["0","9"],"_"],!1,!1),Lg=function(){return By()},Dl=/^[$@*?#a-zA-Z0-9_\-]/,bl=zi(["$","@","*","?","#",["a","z"],["A","Z"],["0","9"],"_","-"],!1,!1),Iy=/^[()}<>$|&; \t"']/,UA=zi(["(",")","}","<",">","$","|","&",";"," "," ",'"',"'"],!1,!1),Cy=/^[<>&; \t"']/,wy=zi(["<",">","&",";"," "," ",'"',"'"],!1,!1),_A=/^[ \t]/,HA=zi([" "," "],!1,!1),Y=0,xt=0,jA=[{line:1,column:1}],bo=0,mf=[],yt=0,gu;if("startRule"in e){if(!(e.startRule in s))throw new Error(`Can't start parsing from rule "`+e.startRule+'".');a=s[e.startRule]}function By(){return t.substring(xt,Y)}function Mg(){return Ef(xt,Y)}function e2(O,K){throw K=K!==void 0?K:Ef(xt,Y),GA([Ug(O)],t.substring(xt,Y),K)}function vh(O,K){throw K=K!==void 0?K:Ef(xt,Y),di(O,K)}function ur(O,K){return{type:"literal",text:O,ignoreCase:K}}function zi(O,K,re){return{type:"class",parts:O,inverted:K,ignoreCase:re}}function yf(){return{type:"any"}}function qa(){return{type:"end"}}function Ug(O){return{type:"other",description:O}}function du(O){var K=jA[O],re;if(K)return K;for(re=O-1;!jA[re];)re--;for(K=jA[re],K={line:K.line,column:K.column};rebo&&(bo=Y,mf=[]),mf.push(O))}function di(O,K){return new Bd(O,null,null,K)}function GA(O,K,re){return new Bd(Bd.buildMessage(O,K),O,K,re)}function Wa(){var O,K,re;for(O=Y,K=[],re=kt();re!==r;)K.push(re),re=kt();return K!==r?(re=Aa(),re===r&&(re=null),re!==r?(xt=O,K=n(re),O=K):(Y=O,O=r)):(Y=O,O=r),O}function Aa(){var O,K,re,de,Je;if(O=Y,K=Sh(),K!==r){for(re=[],de=kt();de!==r;)re.push(de),de=kt();re!==r?(de=_g(),de!==r?(Je=Ya(),Je===r&&(Je=null),Je!==r?(xt=O,K=c(K,de,Je),O=K):(Y=O,O=r)):(Y=O,O=r)):(Y=O,O=r)}else Y=O,O=r;if(O===r)if(O=Y,K=Sh(),K!==r){for(re=[],de=kt();de!==r;)re.push(de),de=kt();re!==r?(de=_g(),de===r&&(de=null),de!==r?(xt=O,K=f(K,de),O=K):(Y=O,O=r)):(Y=O,O=r)}else Y=O,O=r;return O}function Ya(){var O,K,re,de,Je;for(O=Y,K=[],re=kt();re!==r;)K.push(re),re=kt();if(K!==r)if(re=Aa(),re!==r){for(de=[],Je=kt();Je!==r;)de.push(Je),Je=kt();de!==r?(xt=O,K=p(re),O=K):(Y=O,O=r)}else Y=O,O=r;else Y=O,O=r;return O}function _g(){var O;return t.charCodeAt(Y)===59?(O=h,Y++):(O=r,yt===0&&wt(E)),O===r&&(t.charCodeAt(Y)===38?(O=C,Y++):(O=r,yt===0&&wt(S))),O}function Sh(){var O,K,re;return O=Y,K=qA(),K!==r?(re=Hg(),re===r&&(re=null),re!==r?(xt=O,K=P(K,re),O=K):(Y=O,O=r)):(Y=O,O=r),O}function Hg(){var O,K,re,de,Je,At,dr;for(O=Y,K=[],re=kt();re!==r;)K.push(re),re=kt();if(K!==r)if(re=vy(),re!==r){for(de=[],Je=kt();Je!==r;)de.push(Je),Je=kt();if(de!==r)if(Je=Sh(),Je!==r){for(At=[],dr=kt();dr!==r;)At.push(dr),dr=kt();At!==r?(xt=O,K=I(re,Je),O=K):(Y=O,O=r)}else Y=O,O=r;else Y=O,O=r}else Y=O,O=r;else Y=O,O=r;return O}function vy(){var O;return t.substr(Y,2)===R?(O=R,Y+=2):(O=r,yt===0&&wt(N)),O===r&&(t.substr(Y,2)===U?(O=U,Y+=2):(O=r,yt===0&&wt(W))),O}function qA(){var O,K,re;return O=Y,K=If(),K!==r?(re=jg(),re===r&&(re=null),re!==r?(xt=O,K=ee(K,re),O=K):(Y=O,O=r)):(Y=O,O=r),O}function jg(){var O,K,re,de,Je,At,dr;for(O=Y,K=[],re=kt();re!==r;)K.push(re),re=kt();if(K!==r)if(re=mu(),re!==r){for(de=[],Je=kt();Je!==r;)de.push(Je),Je=kt();if(de!==r)if(Je=qA(),Je!==r){for(At=[],dr=kt();dr!==r;)At.push(dr),dr=kt();At!==r?(xt=O,K=ie(re,Je),O=K):(Y=O,O=r)}else Y=O,O=r;else Y=O,O=r}else Y=O,O=r;else Y=O,O=r;return O}function mu(){var O;return t.substr(Y,2)===ue?(O=ue,Y+=2):(O=r,yt===0&&wt(le)),O===r&&(t.charCodeAt(Y)===124?(O=me,Y++):(O=r,yt===0&&wt(pe))),O}function yu(){var O,K,re,de,Je,At;if(O=Y,K=Ph(),K!==r)if(t.charCodeAt(Y)===61?(re=Be,Y++):(re=r,yt===0&&wt(Ce)),re!==r)if(de=WA(),de!==r){for(Je=[],At=kt();At!==r;)Je.push(At),At=kt();Je!==r?(xt=O,K=g(K,de),O=K):(Y=O,O=r)}else Y=O,O=r;else Y=O,O=r;else Y=O,O=r;if(O===r)if(O=Y,K=Ph(),K!==r)if(t.charCodeAt(Y)===61?(re=Be,Y++):(re=r,yt===0&&wt(Ce)),re!==r){for(de=[],Je=kt();Je!==r;)de.push(Je),Je=kt();de!==r?(xt=O,K=we(K),O=K):(Y=O,O=r)}else Y=O,O=r;else Y=O,O=r;return O}function If(){var O,K,re,de,Je,At,dr,vr,Un,mi,Cs;for(O=Y,K=[],re=kt();re!==r;)K.push(re),re=kt();if(K!==r)if(t.charCodeAt(Y)===40?(re=ye,Y++):(re=r,yt===0&&wt(Ae)),re!==r){for(de=[],Je=kt();Je!==r;)de.push(Je),Je=kt();if(de!==r)if(Je=Aa(),Je!==r){for(At=[],dr=kt();dr!==r;)At.push(dr),dr=kt();if(At!==r)if(t.charCodeAt(Y)===41?(dr=se,Y++):(dr=r,yt===0&&wt(Z)),dr!==r){for(vr=[],Un=kt();Un!==r;)vr.push(Un),Un=kt();if(vr!==r){for(Un=[],mi=Gn();mi!==r;)Un.push(mi),mi=Gn();if(Un!==r){for(mi=[],Cs=kt();Cs!==r;)mi.push(Cs),Cs=kt();mi!==r?(xt=O,K=De(Je,Un),O=K):(Y=O,O=r)}else Y=O,O=r}else Y=O,O=r}else Y=O,O=r;else Y=O,O=r}else Y=O,O=r;else Y=O,O=r}else Y=O,O=r;else Y=O,O=r;if(O===r){for(O=Y,K=[],re=kt();re!==r;)K.push(re),re=kt();if(K!==r)if(t.charCodeAt(Y)===123?(re=Re,Y++):(re=r,yt===0&&wt(mt)),re!==r){for(de=[],Je=kt();Je!==r;)de.push(Je),Je=kt();if(de!==r)if(Je=Aa(),Je!==r){for(At=[],dr=kt();dr!==r;)At.push(dr),dr=kt();if(At!==r)if(t.charCodeAt(Y)===125?(dr=j,Y++):(dr=r,yt===0&&wt(rt)),dr!==r){for(vr=[],Un=kt();Un!==r;)vr.push(Un),Un=kt();if(vr!==r){for(Un=[],mi=Gn();mi!==r;)Un.push(mi),mi=Gn();if(Un!==r){for(mi=[],Cs=kt();Cs!==r;)mi.push(Cs),Cs=kt();mi!==r?(xt=O,K=Fe(Je,Un),O=K):(Y=O,O=r)}else Y=O,O=r}else Y=O,O=r}else Y=O,O=r;else Y=O,O=r}else Y=O,O=r;else Y=O,O=r}else Y=O,O=r;else Y=O,O=r;if(O===r){for(O=Y,K=[],re=kt();re!==r;)K.push(re),re=kt();if(K!==r){for(re=[],de=yu();de!==r;)re.push(de),de=yu();if(re!==r){for(de=[],Je=kt();Je!==r;)de.push(Je),Je=kt();if(de!==r){if(Je=[],At=Eu(),At!==r)for(;At!==r;)Je.push(At),At=Eu();else Je=r;if(Je!==r){for(At=[],dr=kt();dr!==r;)At.push(dr),dr=kt();At!==r?(xt=O,K=Ne(re,Je),O=K):(Y=O,O=r)}else Y=O,O=r}else Y=O,O=r}else Y=O,O=r}else Y=O,O=r;if(O===r){for(O=Y,K=[],re=kt();re!==r;)K.push(re),re=kt();if(K!==r){if(re=[],de=yu(),de!==r)for(;de!==r;)re.push(de),de=yu();else re=r;if(re!==r){for(de=[],Je=kt();Je!==r;)de.push(Je),Je=kt();de!==r?(xt=O,K=Pe(re),O=K):(Y=O,O=r)}else Y=O,O=r}else Y=O,O=r}}}return O}function Rs(){var O,K,re,de,Je;for(O=Y,K=[],re=kt();re!==r;)K.push(re),re=kt();if(K!==r){if(re=[],de=Pi(),de!==r)for(;de!==r;)re.push(de),de=Pi();else re=r;if(re!==r){for(de=[],Je=kt();Je!==r;)de.push(Je),Je=kt();de!==r?(xt=O,K=Ve(re),O=K):(Y=O,O=r)}else Y=O,O=r}else Y=O,O=r;return O}function Eu(){var O,K,re;for(O=Y,K=[],re=kt();re!==r;)K.push(re),re=kt();if(K!==r?(re=Gn(),re!==r?(xt=O,K=ke(re),O=K):(Y=O,O=r)):(Y=O,O=r),O===r){for(O=Y,K=[],re=kt();re!==r;)K.push(re),re=kt();K!==r?(re=Pi(),re!==r?(xt=O,K=ke(re),O=K):(Y=O,O=r)):(Y=O,O=r)}return O}function Gn(){var O,K,re,de,Je;for(O=Y,K=[],re=kt();re!==r;)K.push(re),re=kt();return K!==r?(it.test(t.charAt(Y))?(re=t.charAt(Y),Y++):(re=r,yt===0&&wt(Ue)),re===r&&(re=null),re!==r?(de=is(),de!==r?(Je=Pi(),Je!==r?(xt=O,K=x(re,de,Je),O=K):(Y=O,O=r)):(Y=O,O=r)):(Y=O,O=r)):(Y=O,O=r),O}function is(){var O;return t.substr(Y,2)===w?(O=w,Y+=2):(O=r,yt===0&&wt(b)),O===r&&(t.substr(Y,2)===y?(O=y,Y+=2):(O=r,yt===0&&wt(F)),O===r&&(t.charCodeAt(Y)===62?(O=z,Y++):(O=r,yt===0&&wt(X)),O===r&&(t.substr(Y,3)===$?(O=$,Y+=3):(O=r,yt===0&&wt(oe)),O===r&&(t.substr(Y,2)===xe?(O=xe,Y+=2):(O=r,yt===0&&wt(Te)),O===r&&(t.charCodeAt(Y)===60?(O=lt,Y++):(O=r,yt===0&&wt(Ct))))))),O}function Pi(){var O,K,re;for(O=Y,K=[],re=kt();re!==r;)K.push(re),re=kt();return K!==r?(re=WA(),re!==r?(xt=O,K=ke(re),O=K):(Y=O,O=r)):(Y=O,O=r),O}function WA(){var O,K,re;if(O=Y,K=[],re=Cf(),re!==r)for(;re!==r;)K.push(re),re=Cf();else K=r;return K!==r&&(xt=O,K=qt(K)),O=K,O}function Cf(){var O,K;return O=Y,K=mn(),K!==r&&(xt=O,K=ir(K)),O=K,O===r&&(O=Y,K=Gg(),K!==r&&(xt=O,K=ir(K)),O=K,O===r&&(O=Y,K=qg(),K!==r&&(xt=O,K=ir(K)),O=K,O===r&&(O=Y,K=ss(),K!==r&&(xt=O,K=ir(K)),O=K))),O}function mn(){var O,K,re,de;return O=Y,t.substr(Y,2)===Pt?(K=Pt,Y+=2):(K=r,yt===0&&wt(gn)),K!==r?(re=yn(),re!==r?(t.charCodeAt(Y)===39?(de=Pr,Y++):(de=r,yt===0&&wt(Ir)),de!==r?(xt=O,K=Or(re),O=K):(Y=O,O=r)):(Y=O,O=r)):(Y=O,O=r),O}function Gg(){var O,K,re,de;return O=Y,t.charCodeAt(Y)===39?(K=Pr,Y++):(K=r,yt===0&&wt(Ir)),K!==r?(re=wf(),re!==r?(t.charCodeAt(Y)===39?(de=Pr,Y++):(de=r,yt===0&&wt(Ir)),de!==r?(xt=O,K=Or(re),O=K):(Y=O,O=r)):(Y=O,O=r)):(Y=O,O=r),O}function qg(){var O,K,re,de;if(O=Y,t.substr(Y,2)===on?(K=on,Y+=2):(K=r,yt===0&&wt(ai)),K!==r&&(xt=O,K=Io()),O=K,O===r)if(O=Y,t.charCodeAt(Y)===34?(K=rs,Y++):(K=r,yt===0&&wt($s)),K!==r){for(re=[],de=Pl();de!==r;)re.push(de),de=Pl();re!==r?(t.charCodeAt(Y)===34?(de=rs,Y++):(de=r,yt===0&&wt($s)),de!==r?(xt=O,K=Co(re),O=K):(Y=O,O=r)):(Y=O,O=r)}else Y=O,O=r;return O}function ss(){var O,K,re;if(O=Y,K=[],re=Po(),re!==r)for(;re!==r;)K.push(re),re=Po();else K=r;return K!==r&&(xt=O,K=Co(K)),O=K,O}function Pl(){var O,K;return O=Y,K=Zr(),K!==r&&(xt=O,K=ji(K)),O=K,O===r&&(O=Y,K=bh(),K!==r&&(xt=O,K=eo(K)),O=K,O===r&&(O=Y,K=VA(),K!==r&&(xt=O,K=wo(K)),O=K,O===r&&(O=Y,K=Bf(),K!==r&&(xt=O,K=QA(K)),O=K))),O}function Po(){var O,K;return O=Y,K=Zr(),K!==r&&(xt=O,K=Af(K)),O=K,O===r&&(O=Y,K=bh(),K!==r&&(xt=O,K=dh(K)),O=K,O===r&&(O=Y,K=VA(),K!==r&&(xt=O,K=mh(K)),O=K,O===r&&(O=Y,K=Sy(),K!==r&&(xt=O,K=to(K)),O=K,O===r&&(O=Y,K=Dh(),K!==r&&(xt=O,K=QA(K)),O=K)))),O}function wf(){var O,K,re;for(O=Y,K=[],jn.test(t.charAt(Y))?(re=t.charAt(Y),Y++):(re=r,yt===0&&wt(Ts));re!==r;)K.push(re),jn.test(t.charAt(Y))?(re=t.charAt(Y),Y++):(re=r,yt===0&&wt(Ts));return K!==r&&(xt=O,K=ro(K)),O=K,O}function Bf(){var O,K,re;if(O=Y,K=[],re=xl(),re===r&&(ou.test(t.charAt(Y))?(re=t.charAt(Y),Y++):(re=r,yt===0&&wt(au))),re!==r)for(;re!==r;)K.push(re),re=xl(),re===r&&(ou.test(t.charAt(Y))?(re=t.charAt(Y),Y++):(re=r,yt===0&&wt(au)));else K=r;return K!==r&&(xt=O,K=ro(K)),O=K,O}function xl(){var O,K,re;return O=Y,t.substr(Y,2)===lu?(K=lu,Y+=2):(K=r,yt===0&&wt(TA)),K!==r&&(xt=O,K=RA()),O=K,O===r&&(O=Y,t.charCodeAt(Y)===92?(K=oa,Y++):(K=r,yt===0&&wt(aa)),K!==r?(FA.test(t.charAt(Y))?(re=t.charAt(Y),Y++):(re=r,yt===0&&wt(gr)),re!==r?(xt=O,K=Bo(re),O=K):(Y=O,O=r)):(Y=O,O=r)),O}function yn(){var O,K,re;for(O=Y,K=[],re=xo(),re===r&&(jn.test(t.charAt(Y))?(re=t.charAt(Y),Y++):(re=r,yt===0&&wt(Ts)));re!==r;)K.push(re),re=xo(),re===r&&(jn.test(t.charAt(Y))?(re=t.charAt(Y),Y++):(re=r,yt===0&&wt(Ts)));return K!==r&&(xt=O,K=ro(K)),O=K,O}function xo(){var O,K,re;return O=Y,t.substr(Y,2)===Me?(K=Me,Y+=2):(K=r,yt===0&&wt(cu)),K!==r&&(xt=O,K=Cr()),O=K,O===r&&(O=Y,t.substr(Y,2)===pf?(K=pf,Y+=2):(K=r,yt===0&&wt(NA)),K!==r&&(xt=O,K=OA()),O=K,O===r&&(O=Y,t.charCodeAt(Y)===92?(K=oa,Y++):(K=r,yt===0&&wt(aa)),K!==r?(uu.test(t.charAt(Y))?(re=t.charAt(Y),Y++):(re=r,yt===0&&wt(fu)),re!==r?(xt=O,K=oc(),O=K):(Y=O,O=r)):(Y=O,O=r),O===r&&(O=Y,t.substr(Y,2)===ve?(K=ve,Y+=2):(K=r,yt===0&&wt(Nt)),K!==r&&(xt=O,K=ac()),O=K,O===r&&(O=Y,t.substr(Y,2)===Oi?(K=Oi,Y+=2):(K=r,yt===0&&wt(no)),K!==r&&(xt=O,K=Rt()),O=K,O===r&&(O=Y,t.substr(Y,2)===xn?(K=xn,Y+=2):(K=r,yt===0&&wt(la)),K!==r&&(xt=O,K=Gi()),O=K,O===r&&(O=Y,t.substr(Y,2)===Li?(K=Li,Y+=2):(K=r,yt===0&&wt(Na)),K!==r&&(xt=O,K=dn()),O=K,O===r&&(O=Y,t.substr(Y,2)===Kn?(K=Kn,Y+=2):(K=r,yt===0&&wt(Au)),K!==r&&(xt=O,K=yh()),O=K,O===r&&(O=Y,t.charCodeAt(Y)===92?(K=oa,Y++):(K=r,yt===0&&wt(aa)),K!==r?(Oa.test(t.charAt(Y))?(re=t.charAt(Y),Y++):(re=r,yt===0&&wt(La)),re!==r?(xt=O,K=Bo(re),O=K):(Y=O,O=r)):(Y=O,O=r),O===r&&(O=Iu()))))))))),O}function Iu(){var O,K,re,de,Je,At,dr,vr,Un,mi,Cs,JA;return O=Y,t.charCodeAt(Y)===92?(K=oa,Y++):(K=r,yt===0&&wt(aa)),K!==r?(re=pa(),re!==r?(xt=O,K=Ma(re),O=K):(Y=O,O=r)):(Y=O,O=r),O===r&&(O=Y,t.substr(Y,2)===$e?(K=$e,Y+=2):(K=r,yt===0&&wt(Ua)),K!==r?(re=Y,de=Y,Je=pa(),Je!==r?(At=Fs(),At!==r?(Je=[Je,At],de=Je):(Y=de,de=r)):(Y=de,de=r),de===r&&(de=pa()),de!==r?re=t.substring(re,Y):re=de,re!==r?(xt=O,K=Ma(re),O=K):(Y=O,O=r)):(Y=O,O=r),O===r&&(O=Y,t.substr(Y,2)===hf?(K=hf,Y+=2):(K=r,yt===0&&wt(lc)),K!==r?(re=Y,de=Y,Je=Fs(),Je!==r?(At=Fs(),At!==r?(dr=Fs(),dr!==r?(vr=Fs(),vr!==r?(Je=[Je,At,dr,vr],de=Je):(Y=de,de=r)):(Y=de,de=r)):(Y=de,de=r)):(Y=de,de=r),de!==r?re=t.substring(re,Y):re=de,re!==r?(xt=O,K=Ma(re),O=K):(Y=O,O=r)):(Y=O,O=r),O===r&&(O=Y,t.substr(Y,2)===wn?(K=wn,Y+=2):(K=r,yt===0&&wt(ca)),K!==r?(re=Y,de=Y,Je=Fs(),Je!==r?(At=Fs(),At!==r?(dr=Fs(),dr!==r?(vr=Fs(),vr!==r?(Un=Fs(),Un!==r?(mi=Fs(),mi!==r?(Cs=Fs(),Cs!==r?(JA=Fs(),JA!==r?(Je=[Je,At,dr,vr,Un,mi,Cs,JA],de=Je):(Y=de,de=r)):(Y=de,de=r)):(Y=de,de=r)):(Y=de,de=r)):(Y=de,de=r)):(Y=de,de=r)):(Y=de,de=r)):(Y=de,de=r),de!==r?re=t.substring(re,Y):re=de,re!==r?(xt=O,K=LA(re),O=K):(Y=O,O=r)):(Y=O,O=r)))),O}function pa(){var O;return MA.test(t.charAt(Y))?(O=t.charAt(Y),Y++):(O=r,yt===0&&wt(ua)),O}function Fs(){var O;return Bl.test(t.charAt(Y))?(O=t.charAt(Y),Y++):(O=r,yt===0&&wt(Mt)),O}function Dh(){var O,K,re,de,Je;if(O=Y,K=[],re=Y,t.charCodeAt(Y)===92?(de=oa,Y++):(de=r,yt===0&&wt(aa)),de!==r?(t.length>Y?(Je=t.charAt(Y),Y++):(Je=r,yt===0&&wt(kn)),Je!==r?(xt=re,de=Bo(Je),re=de):(Y=re,re=r)):(Y=re,re=r),re===r&&(re=Y,t.substr(Y,2)===fa?(de=fa,Y+=2):(de=r,yt===0&&wt(Ha)),de!==r&&(xt=re,de=ns()),re=de,re===r&&(re=Y,de=Y,yt++,Je=Dy(),yt--,Je===r?de=void 0:(Y=de,de=r),de!==r?(t.length>Y?(Je=t.charAt(Y),Y++):(Je=r,yt===0&&wt(kn)),Je!==r?(xt=re,de=Bo(Je),re=de):(Y=re,re=r)):(Y=re,re=r))),re!==r)for(;re!==r;)K.push(re),re=Y,t.charCodeAt(Y)===92?(de=oa,Y++):(de=r,yt===0&&wt(aa)),de!==r?(t.length>Y?(Je=t.charAt(Y),Y++):(Je=r,yt===0&&wt(kn)),Je!==r?(xt=re,de=Bo(Je),re=de):(Y=re,re=r)):(Y=re,re=r),re===r&&(re=Y,t.substr(Y,2)===fa?(de=fa,Y+=2):(de=r,yt===0&&wt(Ha)),de!==r&&(xt=re,de=ns()),re=de,re===r&&(re=Y,de=Y,yt++,Je=Dy(),yt--,Je===r?de=void 0:(Y=de,de=r),de!==r?(t.length>Y?(Je=t.charAt(Y),Y++):(Je=r,yt===0&&wt(kn)),Je!==r?(xt=re,de=Bo(Je),re=de):(Y=re,re=r)):(Y=re,re=r)));else K=r;return K!==r&&(xt=O,K=ro(K)),O=K,O}function YA(){var O,K,re,de,Je,At;if(O=Y,t.charCodeAt(Y)===45?(K=cc,Y++):(K=r,yt===0&&wt(pu)),K===r&&(t.charCodeAt(Y)===43?(K=uc,Y++):(K=r,yt===0&&wt(ja))),K===r&&(K=null),K!==r){if(re=[],it.test(t.charAt(Y))?(de=t.charAt(Y),Y++):(de=r,yt===0&&wt(Ue)),de!==r)for(;de!==r;)re.push(de),it.test(t.charAt(Y))?(de=t.charAt(Y),Y++):(de=r,yt===0&&wt(Ue));else re=r;if(re!==r)if(t.charCodeAt(Y)===46?(de=Mi,Y++):(de=r,yt===0&&wt(Is)),de!==r){if(Je=[],it.test(t.charAt(Y))?(At=t.charAt(Y),Y++):(At=r,yt===0&&wt(Ue)),At!==r)for(;At!==r;)Je.push(At),it.test(t.charAt(Y))?(At=t.charAt(Y),Y++):(At=r,yt===0&&wt(Ue));else Je=r;Je!==r?(xt=O,K=vl(K,re,Je),O=K):(Y=O,O=r)}else Y=O,O=r;else Y=O,O=r}else Y=O,O=r;if(O===r){if(O=Y,t.charCodeAt(Y)===45?(K=cc,Y++):(K=r,yt===0&&wt(pu)),K===r&&(t.charCodeAt(Y)===43?(K=uc,Y++):(K=r,yt===0&&wt(ja))),K===r&&(K=null),K!==r){if(re=[],it.test(t.charAt(Y))?(de=t.charAt(Y),Y++):(de=r,yt===0&&wt(Ue)),de!==r)for(;de!==r;)re.push(de),it.test(t.charAt(Y))?(de=t.charAt(Y),Y++):(de=r,yt===0&&wt(Ue));else re=r;re!==r?(xt=O,K=gf(K,re),O=K):(Y=O,O=r)}else Y=O,O=r;if(O===r&&(O=Y,K=VA(),K!==r&&(xt=O,K=fc(K)),O=K,O===r&&(O=Y,K=pc(),K!==r&&(xt=O,K=wi(K)),O=K,O===r)))if(O=Y,t.charCodeAt(Y)===40?(K=ye,Y++):(K=r,yt===0&&wt(Ae)),K!==r){for(re=[],de=kt();de!==r;)re.push(de),de=kt();if(re!==r)if(de=io(),de!==r){for(Je=[],At=kt();At!==r;)Je.push(At),At=kt();Je!==r?(t.charCodeAt(Y)===41?(At=se,Y++):(At=r,yt===0&&wt(Z)),At!==r?(xt=O,K=Qn(de),O=K):(Y=O,O=r)):(Y=O,O=r)}else Y=O,O=r;else Y=O,O=r}else Y=O,O=r}return O}function vf(){var O,K,re,de,Je,At,dr,vr;if(O=Y,K=YA(),K!==r){for(re=[],de=Y,Je=[],At=kt();At!==r;)Je.push(At),At=kt();if(Je!==r)if(t.charCodeAt(Y)===42?(At=Ac,Y++):(At=r,yt===0&&wt(Ke)),At===r&&(t.charCodeAt(Y)===47?(At=st,Y++):(At=r,yt===0&&wt(St))),At!==r){for(dr=[],vr=kt();vr!==r;)dr.push(vr),vr=kt();dr!==r?(vr=YA(),vr!==r?(xt=de,Je=lr(K,At,vr),de=Je):(Y=de,de=r)):(Y=de,de=r)}else Y=de,de=r;else Y=de,de=r;for(;de!==r;){for(re.push(de),de=Y,Je=[],At=kt();At!==r;)Je.push(At),At=kt();if(Je!==r)if(t.charCodeAt(Y)===42?(At=Ac,Y++):(At=r,yt===0&&wt(Ke)),At===r&&(t.charCodeAt(Y)===47?(At=st,Y++):(At=r,yt===0&&wt(St))),At!==r){for(dr=[],vr=kt();vr!==r;)dr.push(vr),vr=kt();dr!==r?(vr=YA(),vr!==r?(xt=de,Je=lr(K,At,vr),de=Je):(Y=de,de=r)):(Y=de,de=r)}else Y=de,de=r;else Y=de,de=r}re!==r?(xt=O,K=te(K,re),O=K):(Y=O,O=r)}else Y=O,O=r;return O}function io(){var O,K,re,de,Je,At,dr,vr;if(O=Y,K=vf(),K!==r){for(re=[],de=Y,Je=[],At=kt();At!==r;)Je.push(At),At=kt();if(Je!==r)if(t.charCodeAt(Y)===43?(At=uc,Y++):(At=r,yt===0&&wt(ja)),At===r&&(t.charCodeAt(Y)===45?(At=cc,Y++):(At=r,yt===0&&wt(pu))),At!==r){for(dr=[],vr=kt();vr!==r;)dr.push(vr),vr=kt();dr!==r?(vr=vf(),vr!==r?(xt=de,Je=Ee(K,At,vr),de=Je):(Y=de,de=r)):(Y=de,de=r)}else Y=de,de=r;else Y=de,de=r;for(;de!==r;){for(re.push(de),de=Y,Je=[],At=kt();At!==r;)Je.push(At),At=kt();if(Je!==r)if(t.charCodeAt(Y)===43?(At=uc,Y++):(At=r,yt===0&&wt(ja)),At===r&&(t.charCodeAt(Y)===45?(At=cc,Y++):(At=r,yt===0&&wt(pu))),At!==r){for(dr=[],vr=kt();vr!==r;)dr.push(vr),vr=kt();dr!==r?(vr=vf(),vr!==r?(xt=de,Je=Ee(K,At,vr),de=Je):(Y=de,de=r)):(Y=de,de=r)}else Y=de,de=r;else Y=de,de=r}re!==r?(xt=O,K=te(K,re),O=K):(Y=O,O=r)}else Y=O,O=r;return O}function Zr(){var O,K,re,de,Je,At;if(O=Y,t.substr(Y,3)===Oe?(K=Oe,Y+=3):(K=r,yt===0&&wt(dt)),K!==r){for(re=[],de=kt();de!==r;)re.push(de),de=kt();if(re!==r)if(de=io(),de!==r){for(Je=[],At=kt();At!==r;)Je.push(At),At=kt();Je!==r?(t.substr(Y,2)===Et?(At=Et,Y+=2):(At=r,yt===0&&wt(bt)),At!==r?(xt=O,K=tr(de),O=K):(Y=O,O=r)):(Y=O,O=r)}else Y=O,O=r;else Y=O,O=r}else Y=O,O=r;return O}function bh(){var O,K,re,de;return O=Y,t.substr(Y,2)===An?(K=An,Y+=2):(K=r,yt===0&&wt(li)),K!==r?(re=Aa(),re!==r?(t.charCodeAt(Y)===41?(de=se,Y++):(de=r,yt===0&&wt(Z)),de!==r?(xt=O,K=qi(re),O=K):(Y=O,O=r)):(Y=O,O=r)):(Y=O,O=r),O}function VA(){var O,K,re,de,Je,At;return O=Y,t.substr(Y,2)===Tn?(K=Tn,Y+=2):(K=r,yt===0&&wt(Ga)),K!==r?(re=pc(),re!==r?(t.substr(Y,2)===my?(de=my,Y+=2):(de=r,yt===0&&wt(Z1)),de!==r?(Je=Rs(),Je!==r?(t.charCodeAt(Y)===125?(At=j,Y++):(At=r,yt===0&&wt(rt)),At!==r?(xt=O,K=vo(re,Je),O=K):(Y=O,O=r)):(Y=O,O=r)):(Y=O,O=r)):(Y=O,O=r)):(Y=O,O=r),O===r&&(O=Y,t.substr(Y,2)===Tn?(K=Tn,Y+=2):(K=r,yt===0&&wt(Ga)),K!==r?(re=pc(),re!==r?(t.substr(Y,3)===yy?(de=yy,Y+=3):(de=r,yt===0&&wt(Eh)),de!==r?(xt=O,K=$1(re),O=K):(Y=O,O=r)):(Y=O,O=r)):(Y=O,O=r),O===r&&(O=Y,t.substr(Y,2)===Tn?(K=Tn,Y+=2):(K=r,yt===0&&wt(Ga)),K!==r?(re=pc(),re!==r?(t.substr(Y,2)===So?(de=So,Y+=2):(de=r,yt===0&&wt(Ih)),de!==r?(Je=Rs(),Je!==r?(t.charCodeAt(Y)===125?(At=j,Y++):(At=r,yt===0&&wt(rt)),At!==r?(xt=O,K=Ch(re,Je),O=K):(Y=O,O=r)):(Y=O,O=r)):(Y=O,O=r)):(Y=O,O=r)):(Y=O,O=r),O===r&&(O=Y,t.substr(Y,2)===Tn?(K=Tn,Y+=2):(K=r,yt===0&&wt(Ga)),K!==r?(re=pc(),re!==r?(t.substr(Y,3)===hu?(de=hu,Y+=3):(de=r,yt===0&&wt(wh)),de!==r?(xt=O,K=Fg(re),O=K):(Y=O,O=r)):(Y=O,O=r)):(Y=O,O=r),O===r&&(O=Y,t.substr(Y,2)===Tn?(K=Tn,Y+=2):(K=r,yt===0&&wt(Ga)),K!==r?(re=pc(),re!==r?(t.charCodeAt(Y)===125?(de=j,Y++):(de=r,yt===0&&wt(rt)),de!==r?(xt=O,K=Ng(re),O=K):(Y=O,O=r)):(Y=O,O=r)):(Y=O,O=r),O===r&&(O=Y,t.charCodeAt(Y)===36?(K=Og,Y++):(K=r,yt===0&&wt(Ey)),K!==r?(re=pc(),re!==r?(xt=O,K=Ng(re),O=K):(Y=O,O=r)):(Y=O,O=r)))))),O}function Sy(){var O,K,re;return O=Y,K=Wg(),K!==r?(xt=Y,re=df(K),re?re=void 0:re=r,re!==r?(xt=O,K=Do(K),O=K):(Y=O,O=r)):(Y=O,O=r),O}function Wg(){var O,K,re,de,Je;if(O=Y,K=[],re=Y,de=Y,yt++,Je=xh(),yt--,Je===r?de=void 0:(Y=de,de=r),de!==r?(t.length>Y?(Je=t.charAt(Y),Y++):(Je=r,yt===0&&wt(kn)),Je!==r?(xt=re,de=Bo(Je),re=de):(Y=re,re=r)):(Y=re,re=r),re!==r)for(;re!==r;)K.push(re),re=Y,de=Y,yt++,Je=xh(),yt--,Je===r?de=void 0:(Y=de,de=r),de!==r?(t.length>Y?(Je=t.charAt(Y),Y++):(Je=r,yt===0&&wt(kn)),Je!==r?(xt=re,de=Bo(Je),re=de):(Y=re,re=r)):(Y=re,re=r);else K=r;return K!==r&&(xt=O,K=ro(K)),O=K,O}function Ph(){var O,K,re;if(O=Y,K=[],Sl.test(t.charAt(Y))?(re=t.charAt(Y),Y++):(re=r,yt===0&&wt(Bh)),re!==r)for(;re!==r;)K.push(re),Sl.test(t.charAt(Y))?(re=t.charAt(Y),Y++):(re=r,yt===0&&wt(Bh));else K=r;return K!==r&&(xt=O,K=Lg()),O=K,O}function pc(){var O,K,re;if(O=Y,K=[],Dl.test(t.charAt(Y))?(re=t.charAt(Y),Y++):(re=r,yt===0&&wt(bl)),re!==r)for(;re!==r;)K.push(re),Dl.test(t.charAt(Y))?(re=t.charAt(Y),Y++):(re=r,yt===0&&wt(bl));else K=r;return K!==r&&(xt=O,K=Lg()),O=K,O}function Dy(){var O;return Iy.test(t.charAt(Y))?(O=t.charAt(Y),Y++):(O=r,yt===0&&wt(UA)),O}function xh(){var O;return Cy.test(t.charAt(Y))?(O=t.charAt(Y),Y++):(O=r,yt===0&&wt(wy)),O}function kt(){var O,K;if(O=[],_A.test(t.charAt(Y))?(K=t.charAt(Y),Y++):(K=r,yt===0&&wt(HA)),K!==r)for(;K!==r;)O.push(K),_A.test(t.charAt(Y))?(K=t.charAt(Y),Y++):(K=r,yt===0&&wt(HA));else O=r;return O}if(gu=a(),gu!==r&&Y===t.length)return gu;throw gu!==r&&Y!1}){try{return(0,Eee.parse)(t,e)}catch(r){throw r.location&&(r.message=r.message.replace(/(\.)?$/,` (line ${r.location.start.line}, column ${r.location.start.column})$1`)),r}}function fE(t,{endSemicolon:e=!1}={}){return t.map(({command:r,type:s},a)=>`${fx(r)}${s===";"?a!==t.length-1||e?";":"":" &"}`).join(" ")}function fx(t){return`${AE(t.chain)}${t.then?` ${HU(t.then)}`:""}`}function HU(t){return`${t.type} ${fx(t.line)}`}function AE(t){return`${GU(t)}${t.then?` ${jU(t.then)}`:""}`}function jU(t){return`${t.type} ${AE(t.chain)}`}function GU(t){switch(t.type){case"command":return`${t.envs.length>0?`${t.envs.map(e=>cx(e)).join(" ")} `:""}${t.args.map(e=>qU(e)).join(" ")}`;case"subshell":return`(${fE(t.subshell)})${t.args.length>0?` ${t.args.map(e=>H2(e)).join(" ")}`:""}`;case"group":return`{ ${fE(t.group,{endSemicolon:!0})} }${t.args.length>0?` ${t.args.map(e=>H2(e)).join(" ")}`:""}`;case"envs":return t.envs.map(e=>cx(e)).join(" ");default:throw new Error(`Unsupported command type: "${t.type}"`)}}function cx(t){return`${t.name}=${t.args[0]?vd(t.args[0]):""}`}function qU(t){switch(t.type){case"redirection":return H2(t);case"argument":return vd(t);default:throw new Error(`Unsupported argument type: "${t.type}"`)}}function H2(t){return`${t.subtype} ${t.args.map(e=>vd(e)).join(" ")}`}function vd(t){return t.segments.map(e=>WU(e)).join("")}function WU(t){let e=(s,a)=>a?`"${s}"`:s,r=s=>s===""?"''":s.match(/[()}<>$|&;"'\n\t ]/)?s.match(/['\t\p{C}]/u)?s.match(/'/)?`"${s.replace(/["$\t\p{C}]/u,U5e)}"`:`$'${s.replace(/[\t\p{C}]/u,Cee)}'`:`'${s}'`:s;switch(t.type){case"text":return r(t.text);case"glob":return t.pattern;case"shell":return e(`$(${fE(t.shell)})`,t.quoted);case"variable":return e(typeof t.defaultValue>"u"?typeof t.alternativeValue>"u"?`\${${t.name}}`:t.alternativeValue.length===0?`\${${t.name}:+}`:`\${${t.name}:+${t.alternativeValue.map(s=>vd(s)).join(" ")}}`:t.defaultValue.length===0?`\${${t.name}:-}`:`\${${t.name}:-${t.defaultValue.map(s=>vd(s)).join(" ")}}`,t.quoted);case"arithmetic":return`$(( ${Ax(t.arithmetic)} ))`;default:throw new Error(`Unsupported argument segment type: "${t.type}"`)}}function Ax(t){let e=a=>{switch(a){case"addition":return"+";case"subtraction":return"-";case"multiplication":return"*";case"division":return"/";default:throw new Error(`Can't extract operator from arithmetic expression of type "${a}"`)}},r=(a,n)=>n?`( ${a} )`:a,s=a=>r(Ax(a),!["number","variable"].includes(a.type));switch(t.type){case"number":return String(t.value);case"variable":return t.name;default:return`${s(t.left)} ${e(t.type)} ${s(t.right)}`}}var Eee,Iee,M5e,Cee,U5e,wee=Xe(()=>{Eee=ut(yee());Iee=new Map([["\f","\\f"],[` +`,"\\n"],["\r","\\r"],[" ","\\t"],["\v","\\v"],["\0","\\0"]]),M5e=new Map([["\\","\\\\"],["$","\\$"],['"','\\"'],...Array.from(Iee,([t,e])=>[t,`"$'${e}'"`])]),Cee=t=>Iee.get(t)??`\\x${t.charCodeAt(0).toString(16).padStart(2,"0")}`,U5e=t=>M5e.get(t)??`"$'${Cee(t)}'"`});var vee=_((eQt,Bee)=>{"use strict";function _5e(t,e){function r(){this.constructor=t}r.prototype=e.prototype,t.prototype=new r}function Sd(t,e,r,s){this.message=t,this.expected=e,this.found=r,this.location=s,this.name="SyntaxError",typeof Error.captureStackTrace=="function"&&Error.captureStackTrace(this,Sd)}_5e(Sd,Error);Sd.buildMessage=function(t,e){var r={literal:function(h){return'"'+a(h.text)+'"'},class:function(h){var E="",C;for(C=0;C0){for(C=1,S=1;Cue&&(ue=W,le=[]),le.push(Ue))}function rt(Ue,x){return new Sd(Ue,null,null,x)}function Fe(Ue,x,w){return new Sd(Sd.buildMessage(Ue,x),Ue,x,w)}function Ne(){var Ue,x,w,b;return Ue=W,x=Pe(),x!==r?(t.charCodeAt(W)===47?(w=n,W++):(w=r,me===0&&j(c)),w!==r?(b=Pe(),b!==r?(ee=Ue,x=f(x,b),Ue=x):(W=Ue,Ue=r)):(W=Ue,Ue=r)):(W=Ue,Ue=r),Ue===r&&(Ue=W,x=Pe(),x!==r&&(ee=Ue,x=p(x)),Ue=x),Ue}function Pe(){var Ue,x,w,b;return Ue=W,x=Ve(),x!==r?(t.charCodeAt(W)===64?(w=h,W++):(w=r,me===0&&j(E)),w!==r?(b=it(),b!==r?(ee=Ue,x=C(x,b),Ue=x):(W=Ue,Ue=r)):(W=Ue,Ue=r)):(W=Ue,Ue=r),Ue===r&&(Ue=W,x=Ve(),x!==r&&(ee=Ue,x=S(x)),Ue=x),Ue}function Ve(){var Ue,x,w,b,y;return Ue=W,t.charCodeAt(W)===64?(x=h,W++):(x=r,me===0&&j(E)),x!==r?(w=ke(),w!==r?(t.charCodeAt(W)===47?(b=n,W++):(b=r,me===0&&j(c)),b!==r?(y=ke(),y!==r?(ee=Ue,x=P(),Ue=x):(W=Ue,Ue=r)):(W=Ue,Ue=r)):(W=Ue,Ue=r)):(W=Ue,Ue=r),Ue===r&&(Ue=W,x=ke(),x!==r&&(ee=Ue,x=P()),Ue=x),Ue}function ke(){var Ue,x,w;if(Ue=W,x=[],I.test(t.charAt(W))?(w=t.charAt(W),W++):(w=r,me===0&&j(R)),w!==r)for(;w!==r;)x.push(w),I.test(t.charAt(W))?(w=t.charAt(W),W++):(w=r,me===0&&j(R));else x=r;return x!==r&&(ee=Ue,x=P()),Ue=x,Ue}function it(){var Ue,x,w;if(Ue=W,x=[],N.test(t.charAt(W))?(w=t.charAt(W),W++):(w=r,me===0&&j(U)),w!==r)for(;w!==r;)x.push(w),N.test(t.charAt(W))?(w=t.charAt(W),W++):(w=r,me===0&&j(U));else x=r;return x!==r&&(ee=Ue,x=P()),Ue=x,Ue}if(pe=a(),pe!==r&&W===t.length)return pe;throw pe!==r&&W{See=ut(vee())});var bd=_((rQt,Dd)=>{"use strict";function bee(t){return typeof t>"u"||t===null}function j5e(t){return typeof t=="object"&&t!==null}function G5e(t){return Array.isArray(t)?t:bee(t)?[]:[t]}function q5e(t,e){var r,s,a,n;if(e)for(n=Object.keys(e),r=0,s=n.length;r{"use strict";function j2(t,e){Error.call(this),this.name="YAMLException",this.reason=t,this.mark=e,this.message=(this.reason||"(unknown reason)")+(this.mark?" "+this.mark.toString():""),Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=new Error().stack||""}j2.prototype=Object.create(Error.prototype);j2.prototype.constructor=j2;j2.prototype.toString=function(e){var r=this.name+": ";return r+=this.reason||"(unknown reason)",!e&&this.mark&&(r+=" "+this.mark.toString()),r};Pee.exports=j2});var Qee=_((iQt,kee)=>{"use strict";var xee=bd();function YU(t,e,r,s,a){this.name=t,this.buffer=e,this.position=r,this.line=s,this.column=a}YU.prototype.getSnippet=function(e,r){var s,a,n,c,f;if(!this.buffer)return null;for(e=e||4,r=r||75,s="",a=this.position;a>0&&`\0\r +\x85\u2028\u2029`.indexOf(this.buffer.charAt(a-1))===-1;)if(a-=1,this.position-a>r/2-1){s=" ... ",a+=5;break}for(n="",c=this.position;cr/2-1){n=" ... ",c-=5;break}return f=this.buffer.slice(a,c),xee.repeat(" ",e)+s+f+n+` +`+xee.repeat(" ",e+this.position-a+s.length)+"^"};YU.prototype.toString=function(e){var r,s="";return this.name&&(s+='in "'+this.name+'" '),s+="at line "+(this.line+1)+", column "+(this.column+1),e||(r=this.getSnippet(),r&&(s+=`: +`+r)),s};kee.exports=YU});var Ss=_((sQt,Ree)=>{"use strict";var Tee=pE(),V5e=["kind","resolve","construct","instanceOf","predicate","represent","defaultStyle","styleAliases"],J5e=["scalar","sequence","mapping"];function K5e(t){var e={};return t!==null&&Object.keys(t).forEach(function(r){t[r].forEach(function(s){e[String(s)]=r})}),e}function z5e(t,e){if(e=e||{},Object.keys(e).forEach(function(r){if(V5e.indexOf(r)===-1)throw new Tee('Unknown option "'+r+'" is met in definition of "'+t+'" YAML type.')}),this.tag=t,this.kind=e.kind||null,this.resolve=e.resolve||function(){return!0},this.construct=e.construct||function(r){return r},this.instanceOf=e.instanceOf||null,this.predicate=e.predicate||null,this.represent=e.represent||null,this.defaultStyle=e.defaultStyle||null,this.styleAliases=K5e(e.styleAliases||null),J5e.indexOf(this.kind)===-1)throw new Tee('Unknown kind "'+this.kind+'" is specified for "'+t+'" YAML type.')}Ree.exports=z5e});var Pd=_((oQt,Nee)=>{"use strict";var Fee=bd(),gx=pE(),X5e=Ss();function VU(t,e,r){var s=[];return t.include.forEach(function(a){r=VU(a,e,r)}),t[e].forEach(function(a){r.forEach(function(n,c){n.tag===a.tag&&n.kind===a.kind&&s.push(c)}),r.push(a)}),r.filter(function(a,n){return s.indexOf(n)===-1})}function Z5e(){var t={scalar:{},sequence:{},mapping:{},fallback:{}},e,r;function s(a){t[a.kind][a.tag]=t.fallback[a.tag]=a}for(e=0,r=arguments.length;e{"use strict";var $5e=Ss();Oee.exports=new $5e("tag:yaml.org,2002:str",{kind:"scalar",construct:function(t){return t!==null?t:""}})});var Uee=_((lQt,Mee)=>{"use strict";var eqe=Ss();Mee.exports=new eqe("tag:yaml.org,2002:seq",{kind:"sequence",construct:function(t){return t!==null?t:[]}})});var Hee=_((cQt,_ee)=>{"use strict";var tqe=Ss();_ee.exports=new tqe("tag:yaml.org,2002:map",{kind:"mapping",construct:function(t){return t!==null?t:{}}})});var dx=_((uQt,jee)=>{"use strict";var rqe=Pd();jee.exports=new rqe({explicit:[Lee(),Uee(),Hee()]})});var qee=_((fQt,Gee)=>{"use strict";var nqe=Ss();function iqe(t){if(t===null)return!0;var e=t.length;return e===1&&t==="~"||e===4&&(t==="null"||t==="Null"||t==="NULL")}function sqe(){return null}function oqe(t){return t===null}Gee.exports=new nqe("tag:yaml.org,2002:null",{kind:"scalar",resolve:iqe,construct:sqe,predicate:oqe,represent:{canonical:function(){return"~"},lowercase:function(){return"null"},uppercase:function(){return"NULL"},camelcase:function(){return"Null"}},defaultStyle:"lowercase"})});var Yee=_((AQt,Wee)=>{"use strict";var aqe=Ss();function lqe(t){if(t===null)return!1;var e=t.length;return e===4&&(t==="true"||t==="True"||t==="TRUE")||e===5&&(t==="false"||t==="False"||t==="FALSE")}function cqe(t){return t==="true"||t==="True"||t==="TRUE"}function uqe(t){return Object.prototype.toString.call(t)==="[object Boolean]"}Wee.exports=new aqe("tag:yaml.org,2002:bool",{kind:"scalar",resolve:lqe,construct:cqe,predicate:uqe,represent:{lowercase:function(t){return t?"true":"false"},uppercase:function(t){return t?"TRUE":"FALSE"},camelcase:function(t){return t?"True":"False"}},defaultStyle:"lowercase"})});var Jee=_((pQt,Vee)=>{"use strict";var fqe=bd(),Aqe=Ss();function pqe(t){return 48<=t&&t<=57||65<=t&&t<=70||97<=t&&t<=102}function hqe(t){return 48<=t&&t<=55}function gqe(t){return 48<=t&&t<=57}function dqe(t){if(t===null)return!1;var e=t.length,r=0,s=!1,a;if(!e)return!1;if(a=t[r],(a==="-"||a==="+")&&(a=t[++r]),a==="0"){if(r+1===e)return!0;if(a=t[++r],a==="b"){for(r++;r=0?"0b"+t.toString(2):"-0b"+t.toString(2).slice(1)},octal:function(t){return t>=0?"0"+t.toString(8):"-0"+t.toString(8).slice(1)},decimal:function(t){return t.toString(10)},hexadecimal:function(t){return t>=0?"0x"+t.toString(16).toUpperCase():"-0x"+t.toString(16).toUpperCase().slice(1)}},defaultStyle:"decimal",styleAliases:{binary:[2,"bin"],octal:[8,"oct"],decimal:[10,"dec"],hexadecimal:[16,"hex"]}})});var Xee=_((hQt,zee)=>{"use strict";var Kee=bd(),Eqe=Ss(),Iqe=new RegExp("^(?:[-+]?(?:0|[1-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$");function Cqe(t){return!(t===null||!Iqe.test(t)||t[t.length-1]==="_")}function wqe(t){var e,r,s,a;return e=t.replace(/_/g,"").toLowerCase(),r=e[0]==="-"?-1:1,a=[],"+-".indexOf(e[0])>=0&&(e=e.slice(1)),e===".inf"?r===1?Number.POSITIVE_INFINITY:Number.NEGATIVE_INFINITY:e===".nan"?NaN:e.indexOf(":")>=0?(e.split(":").forEach(function(n){a.unshift(parseFloat(n,10))}),e=0,s=1,a.forEach(function(n){e+=n*s,s*=60}),r*e):r*parseFloat(e,10)}var Bqe=/^[-+]?[0-9]+e/;function vqe(t,e){var r;if(isNaN(t))switch(e){case"lowercase":return".nan";case"uppercase":return".NAN";case"camelcase":return".NaN"}else if(Number.POSITIVE_INFINITY===t)switch(e){case"lowercase":return".inf";case"uppercase":return".INF";case"camelcase":return".Inf"}else if(Number.NEGATIVE_INFINITY===t)switch(e){case"lowercase":return"-.inf";case"uppercase":return"-.INF";case"camelcase":return"-.Inf"}else if(Kee.isNegativeZero(t))return"-0.0";return r=t.toString(10),Bqe.test(r)?r.replace("e",".e"):r}function Sqe(t){return Object.prototype.toString.call(t)==="[object Number]"&&(t%1!==0||Kee.isNegativeZero(t))}zee.exports=new Eqe("tag:yaml.org,2002:float",{kind:"scalar",resolve:Cqe,construct:wqe,predicate:Sqe,represent:vqe,defaultStyle:"lowercase"})});var JU=_((gQt,Zee)=>{"use strict";var Dqe=Pd();Zee.exports=new Dqe({include:[dx()],implicit:[qee(),Yee(),Jee(),Xee()]})});var KU=_((dQt,$ee)=>{"use strict";var bqe=Pd();$ee.exports=new bqe({include:[JU()]})});var nte=_((mQt,rte)=>{"use strict";var Pqe=Ss(),ete=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])$"),tte=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:[Tt]|[ \\t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \\t]*(Z|([-+])([0-9][0-9]?)(?::([0-9][0-9]))?))?$");function xqe(t){return t===null?!1:ete.exec(t)!==null||tte.exec(t)!==null}function kqe(t){var e,r,s,a,n,c,f,p=0,h=null,E,C,S;if(e=ete.exec(t),e===null&&(e=tte.exec(t)),e===null)throw new Error("Date resolve error");if(r=+e[1],s=+e[2]-1,a=+e[3],!e[4])return new Date(Date.UTC(r,s,a));if(n=+e[4],c=+e[5],f=+e[6],e[7]){for(p=e[7].slice(0,3);p.length<3;)p+="0";p=+p}return e[9]&&(E=+e[10],C=+(e[11]||0),h=(E*60+C)*6e4,e[9]==="-"&&(h=-h)),S=new Date(Date.UTC(r,s,a,n,c,f,p)),h&&S.setTime(S.getTime()-h),S}function Qqe(t){return t.toISOString()}rte.exports=new Pqe("tag:yaml.org,2002:timestamp",{kind:"scalar",resolve:xqe,construct:kqe,instanceOf:Date,represent:Qqe})});var ste=_((yQt,ite)=>{"use strict";var Tqe=Ss();function Rqe(t){return t==="<<"||t===null}ite.exports=new Tqe("tag:yaml.org,2002:merge",{kind:"scalar",resolve:Rqe})});var lte=_((EQt,ate)=>{"use strict";var xd;try{ote=Ie,xd=ote("buffer").Buffer}catch{}var ote,Fqe=Ss(),zU=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/= +\r`;function Nqe(t){if(t===null)return!1;var e,r,s=0,a=t.length,n=zU;for(r=0;r64)){if(e<0)return!1;s+=6}return s%8===0}function Oqe(t){var e,r,s=t.replace(/[\r\n=]/g,""),a=s.length,n=zU,c=0,f=[];for(e=0;e>16&255),f.push(c>>8&255),f.push(c&255)),c=c<<6|n.indexOf(s.charAt(e));return r=a%4*6,r===0?(f.push(c>>16&255),f.push(c>>8&255),f.push(c&255)):r===18?(f.push(c>>10&255),f.push(c>>2&255)):r===12&&f.push(c>>4&255),xd?xd.from?xd.from(f):new xd(f):f}function Lqe(t){var e="",r=0,s,a,n=t.length,c=zU;for(s=0;s>18&63],e+=c[r>>12&63],e+=c[r>>6&63],e+=c[r&63]),r=(r<<8)+t[s];return a=n%3,a===0?(e+=c[r>>18&63],e+=c[r>>12&63],e+=c[r>>6&63],e+=c[r&63]):a===2?(e+=c[r>>10&63],e+=c[r>>4&63],e+=c[r<<2&63],e+=c[64]):a===1&&(e+=c[r>>2&63],e+=c[r<<4&63],e+=c[64],e+=c[64]),e}function Mqe(t){return xd&&xd.isBuffer(t)}ate.exports=new Fqe("tag:yaml.org,2002:binary",{kind:"scalar",resolve:Nqe,construct:Oqe,predicate:Mqe,represent:Lqe})});var ute=_((CQt,cte)=>{"use strict";var Uqe=Ss(),_qe=Object.prototype.hasOwnProperty,Hqe=Object.prototype.toString;function jqe(t){if(t===null)return!0;var e=[],r,s,a,n,c,f=t;for(r=0,s=f.length;r{"use strict";var qqe=Ss(),Wqe=Object.prototype.toString;function Yqe(t){if(t===null)return!0;var e,r,s,a,n,c=t;for(n=new Array(c.length),e=0,r=c.length;e{"use strict";var Jqe=Ss(),Kqe=Object.prototype.hasOwnProperty;function zqe(t){if(t===null)return!0;var e,r=t;for(e in r)if(Kqe.call(r,e)&&r[e]!==null)return!1;return!0}function Xqe(t){return t!==null?t:{}}pte.exports=new Jqe("tag:yaml.org,2002:set",{kind:"mapping",resolve:zqe,construct:Xqe})});var gE=_((vQt,gte)=>{"use strict";var Zqe=Pd();gte.exports=new Zqe({include:[KU()],implicit:[nte(),ste()],explicit:[lte(),ute(),Ate(),hte()]})});var mte=_((SQt,dte)=>{"use strict";var $qe=Ss();function e9e(){return!0}function t9e(){}function r9e(){return""}function n9e(t){return typeof t>"u"}dte.exports=new $qe("tag:yaml.org,2002:js/undefined",{kind:"scalar",resolve:e9e,construct:t9e,predicate:n9e,represent:r9e})});var Ete=_((DQt,yte)=>{"use strict";var i9e=Ss();function s9e(t){if(t===null||t.length===0)return!1;var e=t,r=/\/([gim]*)$/.exec(t),s="";return!(e[0]==="/"&&(r&&(s=r[1]),s.length>3||e[e.length-s.length-1]!=="/"))}function o9e(t){var e=t,r=/\/([gim]*)$/.exec(t),s="";return e[0]==="/"&&(r&&(s=r[1]),e=e.slice(1,e.length-s.length-1)),new RegExp(e,s)}function a9e(t){var e="/"+t.source+"/";return t.global&&(e+="g"),t.multiline&&(e+="m"),t.ignoreCase&&(e+="i"),e}function l9e(t){return Object.prototype.toString.call(t)==="[object RegExp]"}yte.exports=new i9e("tag:yaml.org,2002:js/regexp",{kind:"scalar",resolve:s9e,construct:o9e,predicate:l9e,represent:a9e})});var wte=_((bQt,Cte)=>{"use strict";var mx;try{Ite=Ie,mx=Ite("esprima")}catch{typeof window<"u"&&(mx=window.esprima)}var Ite,c9e=Ss();function u9e(t){if(t===null)return!1;try{var e="("+t+")",r=mx.parse(e,{range:!0});return!(r.type!=="Program"||r.body.length!==1||r.body[0].type!=="ExpressionStatement"||r.body[0].expression.type!=="ArrowFunctionExpression"&&r.body[0].expression.type!=="FunctionExpression")}catch{return!1}}function f9e(t){var e="("+t+")",r=mx.parse(e,{range:!0}),s=[],a;if(r.type!=="Program"||r.body.length!==1||r.body[0].type!=="ExpressionStatement"||r.body[0].expression.type!=="ArrowFunctionExpression"&&r.body[0].expression.type!=="FunctionExpression")throw new Error("Failed to resolve function");return r.body[0].expression.params.forEach(function(n){s.push(n.name)}),a=r.body[0].expression.body.range,r.body[0].expression.body.type==="BlockStatement"?new Function(s,e.slice(a[0]+1,a[1]-1)):new Function(s,"return "+e.slice(a[0],a[1]))}function A9e(t){return t.toString()}function p9e(t){return Object.prototype.toString.call(t)==="[object Function]"}Cte.exports=new c9e("tag:yaml.org,2002:js/function",{kind:"scalar",resolve:u9e,construct:f9e,predicate:p9e,represent:A9e})});var G2=_((xQt,vte)=>{"use strict";var Bte=Pd();vte.exports=Bte.DEFAULT=new Bte({include:[gE()],explicit:[mte(),Ete(),wte()]})});var Gte=_((kQt,q2)=>{"use strict";var Ip=bd(),Qte=pE(),h9e=Qee(),Tte=gE(),g9e=G2(),i0=Object.prototype.hasOwnProperty,yx=1,Rte=2,Fte=3,Ex=4,XU=1,d9e=2,Ste=3,m9e=/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84\x86-\x9F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/,y9e=/[\x85\u2028\u2029]/,E9e=/[,\[\]\{\}]/,Nte=/^(?:!|!!|![a-z\-]+!)$/i,Ote=/^(?:!|[^,\[\]\{\}])(?:%[0-9a-f]{2}|[0-9a-z\-#;\/\?:@&=\+\$,_\.!~\*'\(\)\[\]])*$/i;function Dte(t){return Object.prototype.toString.call(t)}function jf(t){return t===10||t===13}function Qd(t){return t===9||t===32}function rl(t){return t===9||t===32||t===10||t===13}function dE(t){return t===44||t===91||t===93||t===123||t===125}function I9e(t){var e;return 48<=t&&t<=57?t-48:(e=t|32,97<=e&&e<=102?e-97+10:-1)}function C9e(t){return t===120?2:t===117?4:t===85?8:0}function w9e(t){return 48<=t&&t<=57?t-48:-1}function bte(t){return t===48?"\0":t===97?"\x07":t===98?"\b":t===116||t===9?" ":t===110?` +`:t===118?"\v":t===102?"\f":t===114?"\r":t===101?"\x1B":t===32?" ":t===34?'"':t===47?"/":t===92?"\\":t===78?"\x85":t===95?"\xA0":t===76?"\u2028":t===80?"\u2029":""}function B9e(t){return t<=65535?String.fromCharCode(t):String.fromCharCode((t-65536>>10)+55296,(t-65536&1023)+56320)}var Lte=new Array(256),Mte=new Array(256);for(kd=0;kd<256;kd++)Lte[kd]=bte(kd)?1:0,Mte[kd]=bte(kd);var kd;function v9e(t,e){this.input=t,this.filename=e.filename||null,this.schema=e.schema||g9e,this.onWarning=e.onWarning||null,this.legacy=e.legacy||!1,this.json=e.json||!1,this.listener=e.listener||null,this.implicitTypes=this.schema.compiledImplicit,this.typeMap=this.schema.compiledTypeMap,this.length=t.length,this.position=0,this.line=0,this.lineStart=0,this.lineIndent=0,this.documents=[]}function Ute(t,e){return new Qte(e,new h9e(t.filename,t.input,t.position,t.line,t.position-t.lineStart))}function Rr(t,e){throw Ute(t,e)}function Ix(t,e){t.onWarning&&t.onWarning.call(null,Ute(t,e))}var Pte={YAML:function(e,r,s){var a,n,c;e.version!==null&&Rr(e,"duplication of %YAML directive"),s.length!==1&&Rr(e,"YAML directive accepts exactly one argument"),a=/^([0-9]+)\.([0-9]+)$/.exec(s[0]),a===null&&Rr(e,"ill-formed argument of the YAML directive"),n=parseInt(a[1],10),c=parseInt(a[2],10),n!==1&&Rr(e,"unacceptable YAML version of the document"),e.version=s[0],e.checkLineBreaks=c<2,c!==1&&c!==2&&Ix(e,"unsupported YAML version of the document")},TAG:function(e,r,s){var a,n;s.length!==2&&Rr(e,"TAG directive accepts exactly two arguments"),a=s[0],n=s[1],Nte.test(a)||Rr(e,"ill-formed tag handle (first argument) of the TAG directive"),i0.call(e.tagMap,a)&&Rr(e,'there is a previously declared suffix for "'+a+'" tag handle'),Ote.test(n)||Rr(e,"ill-formed tag prefix (second argument) of the TAG directive"),e.tagMap[a]=n}};function n0(t,e,r,s){var a,n,c,f;if(e1&&(t.result+=Ip.repeat(` +`,e-1))}function S9e(t,e,r){var s,a,n,c,f,p,h,E,C=t.kind,S=t.result,P;if(P=t.input.charCodeAt(t.position),rl(P)||dE(P)||P===35||P===38||P===42||P===33||P===124||P===62||P===39||P===34||P===37||P===64||P===96||(P===63||P===45)&&(a=t.input.charCodeAt(t.position+1),rl(a)||r&&dE(a)))return!1;for(t.kind="scalar",t.result="",n=c=t.position,f=!1;P!==0;){if(P===58){if(a=t.input.charCodeAt(t.position+1),rl(a)||r&&dE(a))break}else if(P===35){if(s=t.input.charCodeAt(t.position-1),rl(s))break}else{if(t.position===t.lineStart&&Cx(t)||r&&dE(P))break;if(jf(P))if(p=t.line,h=t.lineStart,E=t.lineIndent,as(t,!1,-1),t.lineIndent>=e){f=!0,P=t.input.charCodeAt(t.position);continue}else{t.position=c,t.line=p,t.lineStart=h,t.lineIndent=E;break}}f&&(n0(t,n,c,!1),$U(t,t.line-p),n=c=t.position,f=!1),Qd(P)||(c=t.position+1),P=t.input.charCodeAt(++t.position)}return n0(t,n,c,!1),t.result?!0:(t.kind=C,t.result=S,!1)}function D9e(t,e){var r,s,a;if(r=t.input.charCodeAt(t.position),r!==39)return!1;for(t.kind="scalar",t.result="",t.position++,s=a=t.position;(r=t.input.charCodeAt(t.position))!==0;)if(r===39)if(n0(t,s,t.position,!0),r=t.input.charCodeAt(++t.position),r===39)s=t.position,t.position++,a=t.position;else return!0;else jf(r)?(n0(t,s,a,!0),$U(t,as(t,!1,e)),s=a=t.position):t.position===t.lineStart&&Cx(t)?Rr(t,"unexpected end of the document within a single quoted scalar"):(t.position++,a=t.position);Rr(t,"unexpected end of the stream within a single quoted scalar")}function b9e(t,e){var r,s,a,n,c,f;if(f=t.input.charCodeAt(t.position),f!==34)return!1;for(t.kind="scalar",t.result="",t.position++,r=s=t.position;(f=t.input.charCodeAt(t.position))!==0;){if(f===34)return n0(t,r,t.position,!0),t.position++,!0;if(f===92){if(n0(t,r,t.position,!0),f=t.input.charCodeAt(++t.position),jf(f))as(t,!1,e);else if(f<256&&Lte[f])t.result+=Mte[f],t.position++;else if((c=C9e(f))>0){for(a=c,n=0;a>0;a--)f=t.input.charCodeAt(++t.position),(c=I9e(f))>=0?n=(n<<4)+c:Rr(t,"expected hexadecimal character");t.result+=B9e(n),t.position++}else Rr(t,"unknown escape sequence");r=s=t.position}else jf(f)?(n0(t,r,s,!0),$U(t,as(t,!1,e)),r=s=t.position):t.position===t.lineStart&&Cx(t)?Rr(t,"unexpected end of the document within a double quoted scalar"):(t.position++,s=t.position)}Rr(t,"unexpected end of the stream within a double quoted scalar")}function P9e(t,e){var r=!0,s,a=t.tag,n,c=t.anchor,f,p,h,E,C,S={},P,I,R,N;if(N=t.input.charCodeAt(t.position),N===91)p=93,C=!1,n=[];else if(N===123)p=125,C=!0,n={};else return!1;for(t.anchor!==null&&(t.anchorMap[t.anchor]=n),N=t.input.charCodeAt(++t.position);N!==0;){if(as(t,!0,e),N=t.input.charCodeAt(t.position),N===p)return t.position++,t.tag=a,t.anchor=c,t.kind=C?"mapping":"sequence",t.result=n,!0;r||Rr(t,"missed comma between flow collection entries"),I=P=R=null,h=E=!1,N===63&&(f=t.input.charCodeAt(t.position+1),rl(f)&&(h=E=!0,t.position++,as(t,!0,e))),s=t.line,yE(t,e,yx,!1,!0),I=t.tag,P=t.result,as(t,!0,e),N=t.input.charCodeAt(t.position),(E||t.line===s)&&N===58&&(h=!0,N=t.input.charCodeAt(++t.position),as(t,!0,e),yE(t,e,yx,!1,!0),R=t.result),C?mE(t,n,S,I,P,R):h?n.push(mE(t,null,S,I,P,R)):n.push(P),as(t,!0,e),N=t.input.charCodeAt(t.position),N===44?(r=!0,N=t.input.charCodeAt(++t.position)):r=!1}Rr(t,"unexpected end of the stream within a flow collection")}function x9e(t,e){var r,s,a=XU,n=!1,c=!1,f=e,p=0,h=!1,E,C;if(C=t.input.charCodeAt(t.position),C===124)s=!1;else if(C===62)s=!0;else return!1;for(t.kind="scalar",t.result="";C!==0;)if(C=t.input.charCodeAt(++t.position),C===43||C===45)XU===a?a=C===43?Ste:d9e:Rr(t,"repeat of a chomping mode identifier");else if((E=w9e(C))>=0)E===0?Rr(t,"bad explicit indentation width of a block scalar; it cannot be less than one"):c?Rr(t,"repeat of an indentation width identifier"):(f=e+E-1,c=!0);else break;if(Qd(C)){do C=t.input.charCodeAt(++t.position);while(Qd(C));if(C===35)do C=t.input.charCodeAt(++t.position);while(!jf(C)&&C!==0)}for(;C!==0;){for(ZU(t),t.lineIndent=0,C=t.input.charCodeAt(t.position);(!c||t.lineIndentf&&(f=t.lineIndent),jf(C)){p++;continue}if(t.lineIndente)&&p!==0)Rr(t,"bad indentation of a sequence entry");else if(t.lineIndente)&&(yE(t,e,Ex,!0,a)&&(I?S=t.result:P=t.result),I||(mE(t,h,E,C,S,P,n,c),C=S=P=null),as(t,!0,-1),N=t.input.charCodeAt(t.position)),t.lineIndent>e&&N!==0)Rr(t,"bad indentation of a mapping entry");else if(t.lineIndente?p=1:t.lineIndent===e?p=0:t.lineIndente?p=1:t.lineIndent===e?p=0:t.lineIndent tag; it should be "scalar", not "'+t.kind+'"'),C=0,S=t.implicitTypes.length;C tag; it should be "'+P.kind+'", not "'+t.kind+'"'),P.resolve(t.result)?(t.result=P.construct(t.result),t.anchor!==null&&(t.anchorMap[t.anchor]=t.result)):Rr(t,"cannot resolve a node with !<"+t.tag+"> explicit tag")):Rr(t,"unknown tag !<"+t.tag+">");return t.listener!==null&&t.listener("close",t),t.tag!==null||t.anchor!==null||E}function F9e(t){var e=t.position,r,s,a,n=!1,c;for(t.version=null,t.checkLineBreaks=t.legacy,t.tagMap={},t.anchorMap={};(c=t.input.charCodeAt(t.position))!==0&&(as(t,!0,-1),c=t.input.charCodeAt(t.position),!(t.lineIndent>0||c!==37));){for(n=!0,c=t.input.charCodeAt(++t.position),r=t.position;c!==0&&!rl(c);)c=t.input.charCodeAt(++t.position);for(s=t.input.slice(r,t.position),a=[],s.length<1&&Rr(t,"directive name must not be less than one character in length");c!==0;){for(;Qd(c);)c=t.input.charCodeAt(++t.position);if(c===35){do c=t.input.charCodeAt(++t.position);while(c!==0&&!jf(c));break}if(jf(c))break;for(r=t.position;c!==0&&!rl(c);)c=t.input.charCodeAt(++t.position);a.push(t.input.slice(r,t.position))}c!==0&&ZU(t),i0.call(Pte,s)?Pte[s](t,s,a):Ix(t,'unknown document directive "'+s+'"')}if(as(t,!0,-1),t.lineIndent===0&&t.input.charCodeAt(t.position)===45&&t.input.charCodeAt(t.position+1)===45&&t.input.charCodeAt(t.position+2)===45?(t.position+=3,as(t,!0,-1)):n&&Rr(t,"directives end mark is expected"),yE(t,t.lineIndent-1,Ex,!1,!0),as(t,!0,-1),t.checkLineBreaks&&y9e.test(t.input.slice(e,t.position))&&Ix(t,"non-ASCII line breaks are interpreted as content"),t.documents.push(t.result),t.position===t.lineStart&&Cx(t)){t.input.charCodeAt(t.position)===46&&(t.position+=3,as(t,!0,-1));return}if(t.position"u"&&(r=e,e=null);var s=_te(t,r);if(typeof e!="function")return s;for(var a=0,n=s.length;a"u"&&(r=e,e=null),Hte(t,e,Ip.extend({schema:Tte},r))}function O9e(t,e){return jte(t,Ip.extend({schema:Tte},e))}q2.exports.loadAll=Hte;q2.exports.load=jte;q2.exports.safeLoadAll=N9e;q2.exports.safeLoad=O9e});var Are=_((QQt,n_)=>{"use strict";var Y2=bd(),V2=pE(),L9e=G2(),M9e=gE(),Xte=Object.prototype.toString,Zte=Object.prototype.hasOwnProperty,U9e=9,W2=10,_9e=13,H9e=32,j9e=33,G9e=34,$te=35,q9e=37,W9e=38,Y9e=39,V9e=42,ere=44,J9e=45,tre=58,K9e=61,z9e=62,X9e=63,Z9e=64,rre=91,nre=93,$9e=96,ire=123,eWe=124,sre=125,_o={};_o[0]="\\0";_o[7]="\\a";_o[8]="\\b";_o[9]="\\t";_o[10]="\\n";_o[11]="\\v";_o[12]="\\f";_o[13]="\\r";_o[27]="\\e";_o[34]='\\"';_o[92]="\\\\";_o[133]="\\N";_o[160]="\\_";_o[8232]="\\L";_o[8233]="\\P";var tWe=["y","Y","yes","Yes","YES","on","On","ON","n","N","no","No","NO","off","Off","OFF"];function rWe(t,e){var r,s,a,n,c,f,p;if(e===null)return{};for(r={},s=Object.keys(e),a=0,n=s.length;a0?t.charCodeAt(n-1):null,S=S&&Yte(c,f)}else{for(n=0;ns&&t[C+1]!==" ",C=n);else if(!EE(c))return wx;f=n>0?t.charCodeAt(n-1):null,S=S&&Yte(c,f)}h=h||E&&n-C-1>s&&t[C+1]!==" "}return!p&&!h?S&&!a(t)?are:lre:r>9&&ore(t)?wx:h?ure:cre}function lWe(t,e,r,s){t.dump=function(){if(e.length===0)return"''";if(!t.noCompatMode&&tWe.indexOf(e)!==-1)return"'"+e+"'";var a=t.indent*Math.max(1,r),n=t.lineWidth===-1?-1:Math.max(Math.min(t.lineWidth,40),t.lineWidth-a),c=s||t.flowLevel>-1&&r>=t.flowLevel;function f(p){return iWe(t,p)}switch(aWe(e,c,t.indent,n,f)){case are:return e;case lre:return"'"+e.replace(/'/g,"''")+"'";case cre:return"|"+Vte(e,t.indent)+Jte(Wte(e,a));case ure:return">"+Vte(e,t.indent)+Jte(Wte(cWe(e,n),a));case wx:return'"'+uWe(e,n)+'"';default:throw new V2("impossible error: invalid scalar style")}}()}function Vte(t,e){var r=ore(t)?String(e):"",s=t[t.length-1]===` +`,a=s&&(t[t.length-2]===` +`||t===` +`),n=a?"+":s?"":"-";return r+n+` +`}function Jte(t){return t[t.length-1]===` +`?t.slice(0,-1):t}function cWe(t,e){for(var r=/(\n+)([^\n]*)/g,s=function(){var h=t.indexOf(` +`);return h=h!==-1?h:t.length,r.lastIndex=h,Kte(t.slice(0,h),e)}(),a=t[0]===` +`||t[0]===" ",n,c;c=r.exec(t);){var f=c[1],p=c[2];n=p[0]===" ",s+=f+(!a&&!n&&p!==""?` +`:"")+Kte(p,e),a=n}return s}function Kte(t,e){if(t===""||t[0]===" ")return t;for(var r=/ [^ ]/g,s,a=0,n,c=0,f=0,p="";s=r.exec(t);)f=s.index,f-a>e&&(n=c>a?c:f,p+=` +`+t.slice(a,n),a=n+1),c=f;return p+=` +`,t.length-a>e&&c>a?p+=t.slice(a,c)+` +`+t.slice(c+1):p+=t.slice(a),p.slice(1)}function uWe(t){for(var e="",r,s,a,n=0;n=55296&&r<=56319&&(s=t.charCodeAt(n+1),s>=56320&&s<=57343)){e+=qte((r-55296)*1024+s-56320+65536),n++;continue}a=_o[r],e+=!a&&EE(r)?t[n]:a||qte(r)}return e}function fWe(t,e,r){var s="",a=t.tag,n,c;for(n=0,c=r.length;n1024&&(E+="? "),E+=t.dump+(t.condenseFlow?'"':"")+":"+(t.condenseFlow?"":" "),Td(t,e,h,!1,!1)&&(E+=t.dump,s+=E));t.tag=a,t.dump="{"+s+"}"}function hWe(t,e,r,s){var a="",n=t.tag,c=Object.keys(r),f,p,h,E,C,S;if(t.sortKeys===!0)c.sort();else if(typeof t.sortKeys=="function")c.sort(t.sortKeys);else if(t.sortKeys)throw new V2("sortKeys must be a boolean or a function");for(f=0,p=c.length;f1024,C&&(t.dump&&W2===t.dump.charCodeAt(0)?S+="?":S+="? "),S+=t.dump,C&&(S+=e_(t,e)),Td(t,e+1,E,!0,C)&&(t.dump&&W2===t.dump.charCodeAt(0)?S+=":":S+=": ",S+=t.dump,a+=S));t.tag=n,t.dump=a||"{}"}function zte(t,e,r){var s,a,n,c,f,p;for(a=r?t.explicitTypes:t.implicitTypes,n=0,c=a.length;n tag resolver accepts not "'+p+'" style');t.dump=s}return!0}return!1}function Td(t,e,r,s,a,n){t.tag=null,t.dump=r,zte(t,r,!1)||zte(t,r,!0);var c=Xte.call(t.dump);s&&(s=t.flowLevel<0||t.flowLevel>e);var f=c==="[object Object]"||c==="[object Array]",p,h;if(f&&(p=t.duplicates.indexOf(r),h=p!==-1),(t.tag!==null&&t.tag!=="?"||h||t.indent!==2&&e>0)&&(a=!1),h&&t.usedDuplicates[p])t.dump="*ref_"+p;else{if(f&&h&&!t.usedDuplicates[p]&&(t.usedDuplicates[p]=!0),c==="[object Object]")s&&Object.keys(t.dump).length!==0?(hWe(t,e,t.dump,a),h&&(t.dump="&ref_"+p+t.dump)):(pWe(t,e,t.dump),h&&(t.dump="&ref_"+p+" "+t.dump));else if(c==="[object Array]"){var E=t.noArrayIndent&&e>0?e-1:e;s&&t.dump.length!==0?(AWe(t,E,t.dump,a),h&&(t.dump="&ref_"+p+t.dump)):(fWe(t,E,t.dump),h&&(t.dump="&ref_"+p+" "+t.dump))}else if(c==="[object String]")t.tag!=="?"&&lWe(t,t.dump,e,n);else{if(t.skipInvalid)return!1;throw new V2("unacceptable kind of an object to dump "+c)}t.tag!==null&&t.tag!=="?"&&(t.dump="!<"+t.tag+"> "+t.dump)}return!0}function gWe(t,e){var r=[],s=[],a,n;for(t_(t,r,s),a=0,n=s.length;a{"use strict";var Bx=Gte(),pre=Are();function vx(t){return function(){throw new Error("Function "+t+" is deprecated and cannot be used.")}}Wi.exports.Type=Ss();Wi.exports.Schema=Pd();Wi.exports.FAILSAFE_SCHEMA=dx();Wi.exports.JSON_SCHEMA=JU();Wi.exports.CORE_SCHEMA=KU();Wi.exports.DEFAULT_SAFE_SCHEMA=gE();Wi.exports.DEFAULT_FULL_SCHEMA=G2();Wi.exports.load=Bx.load;Wi.exports.loadAll=Bx.loadAll;Wi.exports.safeLoad=Bx.safeLoad;Wi.exports.safeLoadAll=Bx.safeLoadAll;Wi.exports.dump=pre.dump;Wi.exports.safeDump=pre.safeDump;Wi.exports.YAMLException=pE();Wi.exports.MINIMAL_SCHEMA=dx();Wi.exports.SAFE_SCHEMA=gE();Wi.exports.DEFAULT_SCHEMA=G2();Wi.exports.scan=vx("scan");Wi.exports.parse=vx("parse");Wi.exports.compose=vx("compose");Wi.exports.addConstructor=vx("addConstructor")});var dre=_((RQt,gre)=>{"use strict";var mWe=hre();gre.exports=mWe});var yre=_((FQt,mre)=>{"use strict";function yWe(t,e){function r(){this.constructor=t}r.prototype=e.prototype,t.prototype=new r}function Rd(t,e,r,s){this.message=t,this.expected=e,this.found=r,this.location=s,this.name="SyntaxError",typeof Error.captureStackTrace=="function"&&Error.captureStackTrace(this,Rd)}yWe(Rd,Error);Rd.buildMessage=function(t,e){var r={literal:function(h){return'"'+a(h.text)+'"'},class:function(h){var E="",C;for(C=0;C0){for(C=1,S=1;C({[dt]:Oe})))},ue=function(te){return te},le=function(te){return te},me=Oa("correct indentation"),pe=" ",Be=dn(" ",!1),Ce=function(te){return te.length===lr*St},g=function(te){return te.length===(lr+1)*St},we=function(){return lr++,!0},ye=function(){return lr--,!0},Ae=function(){return la()},se=Oa("pseudostring"),Z=/^[^\r\n\t ?:,\][{}#&*!|>'"%@`\-]/,De=Kn(["\r",` +`," "," ","?",":",",","]","[","{","}","#","&","*","!","|",">","'",'"',"%","@","`","-"],!0,!1),Re=/^[^\r\n\t ,\][{}:#"']/,mt=Kn(["\r",` +`," "," ",",","]","[","{","}",":","#",'"',"'"],!0,!1),j=function(){return la().replace(/^ *| *$/g,"")},rt="--",Fe=dn("--",!1),Ne=/^[a-zA-Z\/0-9]/,Pe=Kn([["a","z"],["A","Z"],"/",["0","9"]],!1,!1),Ve=/^[^\r\n\t :,]/,ke=Kn(["\r",` +`," "," ",":",","],!0,!1),it="null",Ue=dn("null",!1),x=function(){return null},w="true",b=dn("true",!1),y=function(){return!0},F="false",z=dn("false",!1),X=function(){return!1},$=Oa("string"),oe='"',xe=dn('"',!1),Te=function(){return""},lt=function(te){return te},Ct=function(te){return te.join("")},qt=/^[^"\\\0-\x1F\x7F]/,ir=Kn(['"',"\\",["\0",""],"\x7F"],!0,!1),Pt='\\"',gn=dn('\\"',!1),Pr=function(){return'"'},Ir="\\\\",Or=dn("\\\\",!1),on=function(){return"\\"},ai="\\/",Io=dn("\\/",!1),rs=function(){return"/"},$s="\\b",Co=dn("\\b",!1),ji=function(){return"\b"},eo="\\f",wo=dn("\\f",!1),QA=function(){return"\f"},Af="\\n",dh=dn("\\n",!1),mh=function(){return` +`},to="\\r",jn=dn("\\r",!1),Ts=function(){return"\r"},ro="\\t",ou=dn("\\t",!1),au=function(){return" "},lu="\\u",TA=dn("\\u",!1),RA=function(te,Ee,Oe,dt){return String.fromCharCode(parseInt(`0x${te}${Ee}${Oe}${dt}`))},oa=/^[0-9a-fA-F]/,aa=Kn([["0","9"],["a","f"],["A","F"]],!1,!1),FA=Oa("blank space"),gr=/^[ \t]/,Bo=Kn([" "," "],!1,!1),Me=Oa("white space"),cu=/^[ \t\n\r]/,Cr=Kn([" "," ",` +`,"\r"],!1,!1),pf=`\r +`,NA=dn(`\r +`,!1),OA=` +`,uu=dn(` +`,!1),fu="\r",oc=dn("\r",!1),ve=0,Nt=0,ac=[{line:1,column:1}],Oi=0,no=[],Rt=0,xn;if("startRule"in e){if(!(e.startRule in s))throw new Error(`Can't start parsing from rule "`+e.startRule+'".');a=s[e.startRule]}function la(){return t.substring(Nt,ve)}function Gi(){return Ma(Nt,ve)}function Li(te,Ee){throw Ee=Ee!==void 0?Ee:Ma(Nt,ve),hf([Oa(te)],t.substring(Nt,ve),Ee)}function Na(te,Ee){throw Ee=Ee!==void 0?Ee:Ma(Nt,ve),Ua(te,Ee)}function dn(te,Ee){return{type:"literal",text:te,ignoreCase:Ee}}function Kn(te,Ee,Oe){return{type:"class",parts:te,inverted:Ee,ignoreCase:Oe}}function Au(){return{type:"any"}}function yh(){return{type:"end"}}function Oa(te){return{type:"other",description:te}}function La(te){var Ee=ac[te],Oe;if(Ee)return Ee;for(Oe=te-1;!ac[Oe];)Oe--;for(Ee=ac[Oe],Ee={line:Ee.line,column:Ee.column};OeOi&&(Oi=ve,no=[]),no.push(te))}function Ua(te,Ee){return new Rd(te,null,null,Ee)}function hf(te,Ee,Oe){return new Rd(Rd.buildMessage(te,Ee),te,Ee,Oe)}function lc(){var te;return te=LA(),te}function wn(){var te,Ee,Oe;for(te=ve,Ee=[],Oe=ca();Oe!==r;)Ee.push(Oe),Oe=ca();return Ee!==r&&(Nt=te,Ee=n(Ee)),te=Ee,te}function ca(){var te,Ee,Oe,dt,Et;return te=ve,Ee=Bl(),Ee!==r?(t.charCodeAt(ve)===45?(Oe=c,ve++):(Oe=r,Rt===0&&$e(f)),Oe!==r?(dt=Qn(),dt!==r?(Et=ua(),Et!==r?(Nt=te,Ee=p(Et),te=Ee):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r),te}function LA(){var te,Ee,Oe;for(te=ve,Ee=[],Oe=MA();Oe!==r;)Ee.push(Oe),Oe=MA();return Ee!==r&&(Nt=te,Ee=h(Ee)),te=Ee,te}function MA(){var te,Ee,Oe,dt,Et,bt,tr,An,li;if(te=ve,Ee=Qn(),Ee===r&&(Ee=null),Ee!==r){if(Oe=ve,t.charCodeAt(ve)===35?(dt=E,ve++):(dt=r,Rt===0&&$e(C)),dt!==r){if(Et=[],bt=ve,tr=ve,Rt++,An=st(),Rt--,An===r?tr=void 0:(ve=tr,tr=r),tr!==r?(t.length>ve?(An=t.charAt(ve),ve++):(An=r,Rt===0&&$e(S)),An!==r?(tr=[tr,An],bt=tr):(ve=bt,bt=r)):(ve=bt,bt=r),bt!==r)for(;bt!==r;)Et.push(bt),bt=ve,tr=ve,Rt++,An=st(),Rt--,An===r?tr=void 0:(ve=tr,tr=r),tr!==r?(t.length>ve?(An=t.charAt(ve),ve++):(An=r,Rt===0&&$e(S)),An!==r?(tr=[tr,An],bt=tr):(ve=bt,bt=r)):(ve=bt,bt=r);else Et=r;Et!==r?(dt=[dt,Et],Oe=dt):(ve=Oe,Oe=r)}else ve=Oe,Oe=r;if(Oe===r&&(Oe=null),Oe!==r){if(dt=[],Et=Ke(),Et!==r)for(;Et!==r;)dt.push(Et),Et=Ke();else dt=r;dt!==r?(Nt=te,Ee=P(),te=Ee):(ve=te,te=r)}else ve=te,te=r}else ve=te,te=r;if(te===r&&(te=ve,Ee=Bl(),Ee!==r?(Oe=Ha(),Oe!==r?(dt=Qn(),dt===r&&(dt=null),dt!==r?(t.charCodeAt(ve)===58?(Et=I,ve++):(Et=r,Rt===0&&$e(R)),Et!==r?(bt=Qn(),bt===r&&(bt=null),bt!==r?(tr=ua(),tr!==r?(Nt=te,Ee=N(Oe,tr),te=Ee):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r),te===r&&(te=ve,Ee=Bl(),Ee!==r?(Oe=ns(),Oe!==r?(dt=Qn(),dt===r&&(dt=null),dt!==r?(t.charCodeAt(ve)===58?(Et=I,ve++):(Et=r,Rt===0&&$e(R)),Et!==r?(bt=Qn(),bt===r&&(bt=null),bt!==r?(tr=ua(),tr!==r?(Nt=te,Ee=N(Oe,tr),te=Ee):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r),te===r))){if(te=ve,Ee=Bl(),Ee!==r)if(Oe=ns(),Oe!==r)if(dt=Qn(),dt!==r)if(Et=pu(),Et!==r){if(bt=[],tr=Ke(),tr!==r)for(;tr!==r;)bt.push(tr),tr=Ke();else bt=r;bt!==r?(Nt=te,Ee=N(Oe,Et),te=Ee):(ve=te,te=r)}else ve=te,te=r;else ve=te,te=r;else ve=te,te=r;else ve=te,te=r;if(te===r)if(te=ve,Ee=Bl(),Ee!==r)if(Oe=ns(),Oe!==r){if(dt=[],Et=ve,bt=Qn(),bt===r&&(bt=null),bt!==r?(t.charCodeAt(ve)===44?(tr=U,ve++):(tr=r,Rt===0&&$e(W)),tr!==r?(An=Qn(),An===r&&(An=null),An!==r?(li=ns(),li!==r?(Nt=Et,bt=ee(Oe,li),Et=bt):(ve=Et,Et=r)):(ve=Et,Et=r)):(ve=Et,Et=r)):(ve=Et,Et=r),Et!==r)for(;Et!==r;)dt.push(Et),Et=ve,bt=Qn(),bt===r&&(bt=null),bt!==r?(t.charCodeAt(ve)===44?(tr=U,ve++):(tr=r,Rt===0&&$e(W)),tr!==r?(An=Qn(),An===r&&(An=null),An!==r?(li=ns(),li!==r?(Nt=Et,bt=ee(Oe,li),Et=bt):(ve=Et,Et=r)):(ve=Et,Et=r)):(ve=Et,Et=r)):(ve=Et,Et=r);else dt=r;dt!==r?(Et=Qn(),Et===r&&(Et=null),Et!==r?(t.charCodeAt(ve)===58?(bt=I,ve++):(bt=r,Rt===0&&$e(R)),bt!==r?(tr=Qn(),tr===r&&(tr=null),tr!==r?(An=ua(),An!==r?(Nt=te,Ee=ie(Oe,dt,An),te=Ee):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)}else ve=te,te=r;else ve=te,te=r}return te}function ua(){var te,Ee,Oe,dt,Et,bt,tr;if(te=ve,Ee=ve,Rt++,Oe=ve,dt=st(),dt!==r?(Et=Mt(),Et!==r?(t.charCodeAt(ve)===45?(bt=c,ve++):(bt=r,Rt===0&&$e(f)),bt!==r?(tr=Qn(),tr!==r?(dt=[dt,Et,bt,tr],Oe=dt):(ve=Oe,Oe=r)):(ve=Oe,Oe=r)):(ve=Oe,Oe=r)):(ve=Oe,Oe=r),Rt--,Oe!==r?(ve=Ee,Ee=void 0):Ee=r,Ee!==r?(Oe=Ke(),Oe!==r?(dt=kn(),dt!==r?(Et=wn(),Et!==r?(bt=fa(),bt!==r?(Nt=te,Ee=ue(Et),te=Ee):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r),te===r&&(te=ve,Ee=st(),Ee!==r?(Oe=kn(),Oe!==r?(dt=LA(),dt!==r?(Et=fa(),Et!==r?(Nt=te,Ee=ue(dt),te=Ee):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r),te===r))if(te=ve,Ee=cc(),Ee!==r){if(Oe=[],dt=Ke(),dt!==r)for(;dt!==r;)Oe.push(dt),dt=Ke();else Oe=r;Oe!==r?(Nt=te,Ee=le(Ee),te=Ee):(ve=te,te=r)}else ve=te,te=r;return te}function Bl(){var te,Ee,Oe;for(Rt++,te=ve,Ee=[],t.charCodeAt(ve)===32?(Oe=pe,ve++):(Oe=r,Rt===0&&$e(Be));Oe!==r;)Ee.push(Oe),t.charCodeAt(ve)===32?(Oe=pe,ve++):(Oe=r,Rt===0&&$e(Be));return Ee!==r?(Nt=ve,Oe=Ce(Ee),Oe?Oe=void 0:Oe=r,Oe!==r?(Ee=[Ee,Oe],te=Ee):(ve=te,te=r)):(ve=te,te=r),Rt--,te===r&&(Ee=r,Rt===0&&$e(me)),te}function Mt(){var te,Ee,Oe;for(te=ve,Ee=[],t.charCodeAt(ve)===32?(Oe=pe,ve++):(Oe=r,Rt===0&&$e(Be));Oe!==r;)Ee.push(Oe),t.charCodeAt(ve)===32?(Oe=pe,ve++):(Oe=r,Rt===0&&$e(Be));return Ee!==r?(Nt=ve,Oe=g(Ee),Oe?Oe=void 0:Oe=r,Oe!==r?(Ee=[Ee,Oe],te=Ee):(ve=te,te=r)):(ve=te,te=r),te}function kn(){var te;return Nt=ve,te=we(),te?te=void 0:te=r,te}function fa(){var te;return Nt=ve,te=ye(),te?te=void 0:te=r,te}function Ha(){var te;return te=vl(),te===r&&(te=uc()),te}function ns(){var te,Ee,Oe;if(te=vl(),te===r){if(te=ve,Ee=[],Oe=ja(),Oe!==r)for(;Oe!==r;)Ee.push(Oe),Oe=ja();else Ee=r;Ee!==r&&(Nt=te,Ee=Ae()),te=Ee}return te}function cc(){var te;return te=Mi(),te===r&&(te=Is(),te===r&&(te=vl(),te===r&&(te=uc()))),te}function pu(){var te;return te=Mi(),te===r&&(te=vl(),te===r&&(te=ja())),te}function uc(){var te,Ee,Oe,dt,Et,bt;if(Rt++,te=ve,Z.test(t.charAt(ve))?(Ee=t.charAt(ve),ve++):(Ee=r,Rt===0&&$e(De)),Ee!==r){for(Oe=[],dt=ve,Et=Qn(),Et===r&&(Et=null),Et!==r?(Re.test(t.charAt(ve))?(bt=t.charAt(ve),ve++):(bt=r,Rt===0&&$e(mt)),bt!==r?(Et=[Et,bt],dt=Et):(ve=dt,dt=r)):(ve=dt,dt=r);dt!==r;)Oe.push(dt),dt=ve,Et=Qn(),Et===r&&(Et=null),Et!==r?(Re.test(t.charAt(ve))?(bt=t.charAt(ve),ve++):(bt=r,Rt===0&&$e(mt)),bt!==r?(Et=[Et,bt],dt=Et):(ve=dt,dt=r)):(ve=dt,dt=r);Oe!==r?(Nt=te,Ee=j(),te=Ee):(ve=te,te=r)}else ve=te,te=r;return Rt--,te===r&&(Ee=r,Rt===0&&$e(se)),te}function ja(){var te,Ee,Oe,dt,Et;if(te=ve,t.substr(ve,2)===rt?(Ee=rt,ve+=2):(Ee=r,Rt===0&&$e(Fe)),Ee===r&&(Ee=null),Ee!==r)if(Ne.test(t.charAt(ve))?(Oe=t.charAt(ve),ve++):(Oe=r,Rt===0&&$e(Pe)),Oe!==r){for(dt=[],Ve.test(t.charAt(ve))?(Et=t.charAt(ve),ve++):(Et=r,Rt===0&&$e(ke));Et!==r;)dt.push(Et),Ve.test(t.charAt(ve))?(Et=t.charAt(ve),ve++):(Et=r,Rt===0&&$e(ke));dt!==r?(Nt=te,Ee=j(),te=Ee):(ve=te,te=r)}else ve=te,te=r;else ve=te,te=r;return te}function Mi(){var te,Ee;return te=ve,t.substr(ve,4)===it?(Ee=it,ve+=4):(Ee=r,Rt===0&&$e(Ue)),Ee!==r&&(Nt=te,Ee=x()),te=Ee,te}function Is(){var te,Ee;return te=ve,t.substr(ve,4)===w?(Ee=w,ve+=4):(Ee=r,Rt===0&&$e(b)),Ee!==r&&(Nt=te,Ee=y()),te=Ee,te===r&&(te=ve,t.substr(ve,5)===F?(Ee=F,ve+=5):(Ee=r,Rt===0&&$e(z)),Ee!==r&&(Nt=te,Ee=X()),te=Ee),te}function vl(){var te,Ee,Oe,dt;return Rt++,te=ve,t.charCodeAt(ve)===34?(Ee=oe,ve++):(Ee=r,Rt===0&&$e(xe)),Ee!==r?(t.charCodeAt(ve)===34?(Oe=oe,ve++):(Oe=r,Rt===0&&$e(xe)),Oe!==r?(Nt=te,Ee=Te(),te=Ee):(ve=te,te=r)):(ve=te,te=r),te===r&&(te=ve,t.charCodeAt(ve)===34?(Ee=oe,ve++):(Ee=r,Rt===0&&$e(xe)),Ee!==r?(Oe=gf(),Oe!==r?(t.charCodeAt(ve)===34?(dt=oe,ve++):(dt=r,Rt===0&&$e(xe)),dt!==r?(Nt=te,Ee=lt(Oe),te=Ee):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)),Rt--,te===r&&(Ee=r,Rt===0&&$e($)),te}function gf(){var te,Ee,Oe;if(te=ve,Ee=[],Oe=fc(),Oe!==r)for(;Oe!==r;)Ee.push(Oe),Oe=fc();else Ee=r;return Ee!==r&&(Nt=te,Ee=Ct(Ee)),te=Ee,te}function fc(){var te,Ee,Oe,dt,Et,bt;return qt.test(t.charAt(ve))?(te=t.charAt(ve),ve++):(te=r,Rt===0&&$e(ir)),te===r&&(te=ve,t.substr(ve,2)===Pt?(Ee=Pt,ve+=2):(Ee=r,Rt===0&&$e(gn)),Ee!==r&&(Nt=te,Ee=Pr()),te=Ee,te===r&&(te=ve,t.substr(ve,2)===Ir?(Ee=Ir,ve+=2):(Ee=r,Rt===0&&$e(Or)),Ee!==r&&(Nt=te,Ee=on()),te=Ee,te===r&&(te=ve,t.substr(ve,2)===ai?(Ee=ai,ve+=2):(Ee=r,Rt===0&&$e(Io)),Ee!==r&&(Nt=te,Ee=rs()),te=Ee,te===r&&(te=ve,t.substr(ve,2)===$s?(Ee=$s,ve+=2):(Ee=r,Rt===0&&$e(Co)),Ee!==r&&(Nt=te,Ee=ji()),te=Ee,te===r&&(te=ve,t.substr(ve,2)===eo?(Ee=eo,ve+=2):(Ee=r,Rt===0&&$e(wo)),Ee!==r&&(Nt=te,Ee=QA()),te=Ee,te===r&&(te=ve,t.substr(ve,2)===Af?(Ee=Af,ve+=2):(Ee=r,Rt===0&&$e(dh)),Ee!==r&&(Nt=te,Ee=mh()),te=Ee,te===r&&(te=ve,t.substr(ve,2)===to?(Ee=to,ve+=2):(Ee=r,Rt===0&&$e(jn)),Ee!==r&&(Nt=te,Ee=Ts()),te=Ee,te===r&&(te=ve,t.substr(ve,2)===ro?(Ee=ro,ve+=2):(Ee=r,Rt===0&&$e(ou)),Ee!==r&&(Nt=te,Ee=au()),te=Ee,te===r&&(te=ve,t.substr(ve,2)===lu?(Ee=lu,ve+=2):(Ee=r,Rt===0&&$e(TA)),Ee!==r?(Oe=wi(),Oe!==r?(dt=wi(),dt!==r?(Et=wi(),Et!==r?(bt=wi(),bt!==r?(Nt=te,Ee=RA(Oe,dt,Et,bt),te=Ee):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)))))))))),te}function wi(){var te;return oa.test(t.charAt(ve))?(te=t.charAt(ve),ve++):(te=r,Rt===0&&$e(aa)),te}function Qn(){var te,Ee;if(Rt++,te=[],gr.test(t.charAt(ve))?(Ee=t.charAt(ve),ve++):(Ee=r,Rt===0&&$e(Bo)),Ee!==r)for(;Ee!==r;)te.push(Ee),gr.test(t.charAt(ve))?(Ee=t.charAt(ve),ve++):(Ee=r,Rt===0&&$e(Bo));else te=r;return Rt--,te===r&&(Ee=r,Rt===0&&$e(FA)),te}function Ac(){var te,Ee;if(Rt++,te=[],cu.test(t.charAt(ve))?(Ee=t.charAt(ve),ve++):(Ee=r,Rt===0&&$e(Cr)),Ee!==r)for(;Ee!==r;)te.push(Ee),cu.test(t.charAt(ve))?(Ee=t.charAt(ve),ve++):(Ee=r,Rt===0&&$e(Cr));else te=r;return Rt--,te===r&&(Ee=r,Rt===0&&$e(Me)),te}function Ke(){var te,Ee,Oe,dt,Et,bt;if(te=ve,Ee=st(),Ee!==r){for(Oe=[],dt=ve,Et=Qn(),Et===r&&(Et=null),Et!==r?(bt=st(),bt!==r?(Et=[Et,bt],dt=Et):(ve=dt,dt=r)):(ve=dt,dt=r);dt!==r;)Oe.push(dt),dt=ve,Et=Qn(),Et===r&&(Et=null),Et!==r?(bt=st(),bt!==r?(Et=[Et,bt],dt=Et):(ve=dt,dt=r)):(ve=dt,dt=r);Oe!==r?(Ee=[Ee,Oe],te=Ee):(ve=te,te=r)}else ve=te,te=r;return te}function st(){var te;return t.substr(ve,2)===pf?(te=pf,ve+=2):(te=r,Rt===0&&$e(NA)),te===r&&(t.charCodeAt(ve)===10?(te=OA,ve++):(te=r,Rt===0&&$e(uu)),te===r&&(t.charCodeAt(ve)===13?(te=fu,ve++):(te=r,Rt===0&&$e(oc)))),te}let St=2,lr=0;if(xn=a(),xn!==r&&ve===t.length)return xn;throw xn!==r&&ve"u"?!0:typeof t=="object"&&t!==null&&!Array.isArray(t)?Object.keys(t).every(e=>wre(t[e])):!1}function i_(t,e,r){if(t===null)return`null +`;if(typeof t=="number"||typeof t=="boolean")return`${t.toString()} +`;if(typeof t=="string")return`${Ire(t)} +`;if(Array.isArray(t)){if(t.length===0)return`[] +`;let s=" ".repeat(e);return` +${t.map(n=>`${s}- ${i_(n,e+1,!1)}`).join("")}`}if(typeof t=="object"&&t){let[s,a]=t instanceof Sx?[t.data,!1]:[t,!0],n=" ".repeat(e),c=Object.keys(s);a&&c.sort((p,h)=>{let E=Ere.indexOf(p),C=Ere.indexOf(h);return E===-1&&C===-1?ph?1:0:E!==-1&&C===-1?-1:E===-1&&C!==-1?1:E-C});let f=c.filter(p=>!wre(s[p])).map((p,h)=>{let E=s[p],C=Ire(p),S=i_(E,e+1,!0),P=h>0||r?n:"",I=C.length>1024?`? ${C} +${P}:`:`${C}:`,R=S.startsWith(` +`)?S:` ${S}`;return`${P}${I}${R}`}).join(e===0?` +`:"")||` +`;return r?` +${f}`:`${f}`}throw new Error(`Unsupported value type (${t})`)}function nl(t){try{let e=i_(t,0,!1);return e!==` +`?e:""}catch(e){throw e.location&&(e.message=e.message.replace(/(\.)?$/,` (line ${e.location.start.line}, column ${e.location.start.column})$1`)),e}}function CWe(t){return t.endsWith(` +`)||(t+=` +`),(0,Cre.parse)(t)}function BWe(t){if(wWe.test(t))return CWe(t);let e=(0,Dx.safeLoad)(t,{schema:Dx.FAILSAFE_SCHEMA,json:!0});if(e==null)return{};if(typeof e!="object")throw new Error(`Expected an indexed object, got a ${typeof e} instead. Does your file follow Yaml's rules?`);if(Array.isArray(e))throw new Error("Expected an indexed object, got an array instead. Does your file follow Yaml's rules?");return e}function ls(t){return BWe(t)}var Dx,Cre,IWe,Ere,Sx,wWe,Bre=Xe(()=>{Dx=ut(dre()),Cre=ut(yre()),IWe=/^(?![-?:,\][{}#&*!|>'"%@` \t\r\n]).([ \t]*(?![,\][{}:# \t\r\n]).)*$/,Ere=["__metadata","version","resolution","dependencies","peerDependencies","dependenciesMeta","peerDependenciesMeta","binaries"],Sx=class{constructor(e){this.data=e}};nl.PreserveOrdering=Sx;wWe=/^(#.*(\r?\n))*?#\s+yarn\s+lockfile\s+v1\r?\n/i});var J2={};Vt(J2,{parseResolution:()=>px,parseShell:()=>ux,parseSyml:()=>ls,stringifyArgument:()=>qU,stringifyArgumentSegment:()=>WU,stringifyArithmeticExpression:()=>Ax,stringifyCommand:()=>GU,stringifyCommandChain:()=>AE,stringifyCommandChainThen:()=>jU,stringifyCommandLine:()=>fx,stringifyCommandLineThen:()=>HU,stringifyEnvSegment:()=>cx,stringifyRedirectArgument:()=>H2,stringifyResolution:()=>hx,stringifyShell:()=>fE,stringifyShellLine:()=>fE,stringifySyml:()=>nl,stringifyValueArgument:()=>vd});var wc=Xe(()=>{wee();Dee();Bre()});var Sre=_((UQt,s_)=>{"use strict";var vWe=t=>{let e=!1,r=!1,s=!1;for(let a=0;a{if(!(typeof t=="string"||Array.isArray(t)))throw new TypeError("Expected the input to be `string | string[]`");e=Object.assign({pascalCase:!1},e);let r=a=>e.pascalCase?a.charAt(0).toUpperCase()+a.slice(1):a;return Array.isArray(t)?t=t.map(a=>a.trim()).filter(a=>a.length).join("-"):t=t.trim(),t.length===0?"":t.length===1?e.pascalCase?t.toUpperCase():t.toLowerCase():(t!==t.toLowerCase()&&(t=vWe(t)),t=t.replace(/^[_.\- ]+/,"").toLowerCase().replace(/[_.\- ]+(\w|$)/g,(a,n)=>n.toUpperCase()).replace(/\d+(\w|$)/g,a=>a.toUpperCase()),r(t))};s_.exports=vre;s_.exports.default=vre});var Dre=_((_Qt,SWe)=>{SWe.exports=[{name:"Agola CI",constant:"AGOLA",env:"AGOLA_GIT_REF",pr:"AGOLA_PULL_REQUEST_ID"},{name:"Appcircle",constant:"APPCIRCLE",env:"AC_APPCIRCLE"},{name:"AppVeyor",constant:"APPVEYOR",env:"APPVEYOR",pr:"APPVEYOR_PULL_REQUEST_NUMBER"},{name:"AWS CodeBuild",constant:"CODEBUILD",env:"CODEBUILD_BUILD_ARN"},{name:"Azure Pipelines",constant:"AZURE_PIPELINES",env:"TF_BUILD",pr:{BUILD_REASON:"PullRequest"}},{name:"Bamboo",constant:"BAMBOO",env:"bamboo_planKey"},{name:"Bitbucket Pipelines",constant:"BITBUCKET",env:"BITBUCKET_COMMIT",pr:"BITBUCKET_PR_ID"},{name:"Bitrise",constant:"BITRISE",env:"BITRISE_IO",pr:"BITRISE_PULL_REQUEST"},{name:"Buddy",constant:"BUDDY",env:"BUDDY_WORKSPACE_ID",pr:"BUDDY_EXECUTION_PULL_REQUEST_ID"},{name:"Buildkite",constant:"BUILDKITE",env:"BUILDKITE",pr:{env:"BUILDKITE_PULL_REQUEST",ne:"false"}},{name:"CircleCI",constant:"CIRCLE",env:"CIRCLECI",pr:"CIRCLE_PULL_REQUEST"},{name:"Cirrus CI",constant:"CIRRUS",env:"CIRRUS_CI",pr:"CIRRUS_PR"},{name:"Codefresh",constant:"CODEFRESH",env:"CF_BUILD_ID",pr:{any:["CF_PULL_REQUEST_NUMBER","CF_PULL_REQUEST_ID"]}},{name:"Codemagic",constant:"CODEMAGIC",env:"CM_BUILD_ID",pr:"CM_PULL_REQUEST"},{name:"Codeship",constant:"CODESHIP",env:{CI_NAME:"codeship"}},{name:"Drone",constant:"DRONE",env:"DRONE",pr:{DRONE_BUILD_EVENT:"pull_request"}},{name:"dsari",constant:"DSARI",env:"DSARI"},{name:"Earthly",constant:"EARTHLY",env:"EARTHLY_CI"},{name:"Expo Application Services",constant:"EAS",env:"EAS_BUILD"},{name:"Gerrit",constant:"GERRIT",env:"GERRIT_PROJECT"},{name:"Gitea Actions",constant:"GITEA_ACTIONS",env:"GITEA_ACTIONS"},{name:"GitHub Actions",constant:"GITHUB_ACTIONS",env:"GITHUB_ACTIONS",pr:{GITHUB_EVENT_NAME:"pull_request"}},{name:"GitLab CI",constant:"GITLAB",env:"GITLAB_CI",pr:"CI_MERGE_REQUEST_ID"},{name:"GoCD",constant:"GOCD",env:"GO_PIPELINE_LABEL"},{name:"Google Cloud Build",constant:"GOOGLE_CLOUD_BUILD",env:"BUILDER_OUTPUT"},{name:"Harness CI",constant:"HARNESS",env:"HARNESS_BUILD_ID"},{name:"Heroku",constant:"HEROKU",env:{env:"NODE",includes:"/app/.heroku/node/bin/node"}},{name:"Hudson",constant:"HUDSON",env:"HUDSON_URL"},{name:"Jenkins",constant:"JENKINS",env:["JENKINS_URL","BUILD_ID"],pr:{any:["ghprbPullId","CHANGE_ID"]}},{name:"LayerCI",constant:"LAYERCI",env:"LAYERCI",pr:"LAYERCI_PULL_REQUEST"},{name:"Magnum CI",constant:"MAGNUM",env:"MAGNUM"},{name:"Netlify CI",constant:"NETLIFY",env:"NETLIFY",pr:{env:"PULL_REQUEST",ne:"false"}},{name:"Nevercode",constant:"NEVERCODE",env:"NEVERCODE",pr:{env:"NEVERCODE_PULL_REQUEST",ne:"false"}},{name:"Prow",constant:"PROW",env:"PROW_JOB_ID"},{name:"ReleaseHub",constant:"RELEASEHUB",env:"RELEASE_BUILD_ID"},{name:"Render",constant:"RENDER",env:"RENDER",pr:{IS_PULL_REQUEST:"true"}},{name:"Sail CI",constant:"SAIL",env:"SAILCI",pr:"SAIL_PULL_REQUEST_NUMBER"},{name:"Screwdriver",constant:"SCREWDRIVER",env:"SCREWDRIVER",pr:{env:"SD_PULL_REQUEST",ne:"false"}},{name:"Semaphore",constant:"SEMAPHORE",env:"SEMAPHORE",pr:"PULL_REQUEST_NUMBER"},{name:"Sourcehut",constant:"SOURCEHUT",env:{CI_NAME:"sourcehut"}},{name:"Strider CD",constant:"STRIDER",env:"STRIDER"},{name:"TaskCluster",constant:"TASKCLUSTER",env:["TASK_ID","RUN_ID"]},{name:"TeamCity",constant:"TEAMCITY",env:"TEAMCITY_VERSION"},{name:"Travis CI",constant:"TRAVIS",env:"TRAVIS",pr:{env:"TRAVIS_PULL_REQUEST",ne:"false"}},{name:"Vela",constant:"VELA",env:"VELA",pr:{VELA_PULL_REQUEST:"1"}},{name:"Vercel",constant:"VERCEL",env:{any:["NOW_BUILDER","VERCEL"]},pr:"VERCEL_GIT_PULL_REQUEST_ID"},{name:"Visual Studio App Center",constant:"APPCENTER",env:"APPCENTER_BUILD_ID"},{name:"Woodpecker",constant:"WOODPECKER",env:{CI:"woodpecker"},pr:{CI_BUILD_EVENT:"pull_request"}},{name:"Xcode Cloud",constant:"XCODE_CLOUD",env:"CI_XCODE_PROJECT",pr:"CI_PULL_REQUEST_NUMBER"},{name:"Xcode Server",constant:"XCODE_SERVER",env:"XCS"}]});var Fd=_(Ml=>{"use strict";var Pre=Dre(),Ds=process.env;Object.defineProperty(Ml,"_vendors",{value:Pre.map(function(t){return t.constant})});Ml.name=null;Ml.isPR=null;Pre.forEach(function(t){let r=(Array.isArray(t.env)?t.env:[t.env]).every(function(s){return bre(s)});if(Ml[t.constant]=r,!!r)switch(Ml.name=t.name,typeof t.pr){case"string":Ml.isPR=!!Ds[t.pr];break;case"object":"env"in t.pr?Ml.isPR=t.pr.env in Ds&&Ds[t.pr.env]!==t.pr.ne:"any"in t.pr?Ml.isPR=t.pr.any.some(function(s){return!!Ds[s]}):Ml.isPR=bre(t.pr);break;default:Ml.isPR=null}});Ml.isCI=!!(Ds.CI!=="false"&&(Ds.BUILD_ID||Ds.BUILD_NUMBER||Ds.CI||Ds.CI_APP_ID||Ds.CI_BUILD_ID||Ds.CI_BUILD_NUMBER||Ds.CI_NAME||Ds.CONTINUOUS_INTEGRATION||Ds.RUN_ID||Ml.name));function bre(t){return typeof t=="string"?!!Ds[t]:"env"in t?Ds[t.env]&&Ds[t.env].includes(t.includes):"any"in t?t.any.some(function(e){return!!Ds[e]}):Object.keys(t).every(function(e){return Ds[e]===t[e]})}});var ei,En,Nd,o_,bx,xre,a_,l_,Px=Xe(()=>{(function(t){t.StartOfInput="\0",t.EndOfInput="",t.EndOfPartialInput=""})(ei||(ei={}));(function(t){t[t.InitialNode=0]="InitialNode",t[t.SuccessNode=1]="SuccessNode",t[t.ErrorNode=2]="ErrorNode",t[t.CustomNode=3]="CustomNode"})(En||(En={}));Nd=-1,o_=/^(-h|--help)(?:=([0-9]+))?$/,bx=/^(--[a-z]+(?:-[a-z]+)*|-[a-zA-Z]+)$/,xre=/^-[a-zA-Z]{2,}$/,a_=/^([^=]+)=([\s\S]*)$/,l_=process.env.DEBUG_CLI==="1"});var nt,IE,xx,c_,kx=Xe(()=>{Px();nt=class extends Error{constructor(e){super(e),this.clipanion={type:"usage"},this.name="UsageError"}},IE=class extends Error{constructor(e,r){if(super(),this.input=e,this.candidates=r,this.clipanion={type:"none"},this.name="UnknownSyntaxError",this.candidates.length===0)this.message="Command not found, but we're not sure what's the alternative.";else if(this.candidates.every(s=>s.reason!==null&&s.reason===r[0].reason)){let[{reason:s}]=this.candidates;this.message=`${s} + +${this.candidates.map(({usage:a})=>`$ ${a}`).join(` +`)}`}else if(this.candidates.length===1){let[{usage:s}]=this.candidates;this.message=`Command not found; did you mean: + +$ ${s} +${c_(e)}`}else this.message=`Command not found; did you mean one of: + +${this.candidates.map(({usage:s},a)=>`${`${a}.`.padStart(4)} ${s}`).join(` +`)} + +${c_(e)}`}},xx=class extends Error{constructor(e,r){super(),this.input=e,this.usages=r,this.clipanion={type:"none"},this.name="AmbiguousSyntaxError",this.message=`Cannot find which to pick amongst the following alternatives: + +${this.usages.map((s,a)=>`${`${a}.`.padStart(4)} ${s}`).join(` +`)} + +${c_(e)}`}},c_=t=>`While running ${t.filter(e=>e!==ei.EndOfInput&&e!==ei.EndOfPartialInput).map(e=>{let r=JSON.stringify(e);return e.match(/\s/)||e.length===0||r!==`"${e}"`?r:e}).join(" ")}`});function DWe(t){let e=t.split(` +`),r=e.filter(a=>a.match(/\S/)),s=r.length>0?r.reduce((a,n)=>Math.min(a,n.length-n.trimStart().length),Number.MAX_VALUE):0;return e.map(a=>a.slice(s).trimRight()).join(` +`)}function Ho(t,{format:e,paragraphs:r}){return t=t.replace(/\r\n?/g,` +`),t=DWe(t),t=t.replace(/^\n+|\n+$/g,""),t=t.replace(/^(\s*)-([^\n]*?)\n+/gm,`$1-$2 + +`),t=t.replace(/\n(\n)?\n*/g,(s,a)=>a||" "),r&&(t=t.split(/\n/).map(s=>{let a=s.match(/^\s*[*-][\t ]+(.*)/);if(!a)return s.match(/(.{1,80})(?: |$)/g).join(` +`);let n=s.length-s.trimStart().length;return a[1].match(new RegExp(`(.{1,${78-n}})(?: |$)`,"g")).map((c,f)=>" ".repeat(n)+(f===0?"- ":" ")+c).join(` +`)}).join(` + +`)),t=t.replace(/(`+)((?:.|[\n])*?)\1/g,(s,a,n)=>e.code(a+n+a)),t=t.replace(/(\*\*)((?:.|[\n])*?)\1/g,(s,a,n)=>e.bold(a+n+a)),t?`${t} +`:""}var u_,kre,Qre,f_=Xe(()=>{u_=Array(80).fill("\u2501");for(let t=0;t<=24;++t)u_[u_.length-t]=`\x1B[38;5;${232+t}m\u2501`;kre={header:t=>`\x1B[1m\u2501\u2501\u2501 ${t}${t.length<75?` ${u_.slice(t.length+5).join("")}`:":"}\x1B[0m`,bold:t=>`\x1B[1m${t}\x1B[22m`,error:t=>`\x1B[31m\x1B[1m${t}\x1B[22m\x1B[39m`,code:t=>`\x1B[36m${t}\x1B[39m`},Qre={header:t=>t,bold:t=>t,error:t=>t,code:t=>t}});function ya(t){return{...t,[K2]:!0}}function Gf(t,e){return typeof t>"u"?[t,e]:typeof t=="object"&&t!==null&&!Array.isArray(t)?[void 0,t]:[t,e]}function Qx(t,{mergeName:e=!1}={}){let r=t.match(/^([^:]+): (.*)$/m);if(!r)return"validation failed";let[,s,a]=r;return e&&(a=a[0].toLowerCase()+a.slice(1)),a=s!=="."||!e?`${s.replace(/^\.(\[|$)/,"$1")}: ${a}`:`: ${a}`,a}function z2(t,e){return e.length===1?new nt(`${t}${Qx(e[0],{mergeName:!0})}`):new nt(`${t}: +${e.map(r=>` +- ${Qx(r)}`).join("")}`)}function Od(t,e,r){if(typeof r>"u")return e;let s=[],a=[],n=f=>{let p=e;return e=f,n.bind(null,p)};if(!r(e,{errors:s,coercions:a,coercion:n}))throw z2(`Invalid value for ${t}`,s);for(let[,f]of a)f();return e}var K2,Cp=Xe(()=>{kx();K2=Symbol("clipanion/isOption")});var Ea={};Vt(Ea,{KeyRelationship:()=>qf,TypeAssertionError:()=>o0,applyCascade:()=>$2,as:()=>WWe,assert:()=>jWe,assertWithErrors:()=>GWe,cascade:()=>Nx,fn:()=>YWe,hasAtLeastOneKey:()=>y_,hasExactLength:()=>Ore,hasForbiddenKeys:()=>fYe,hasKeyRelationship:()=>tB,hasMaxLength:()=>JWe,hasMinLength:()=>VWe,hasMutuallyExclusiveKeys:()=>AYe,hasRequiredKeys:()=>uYe,hasUniqueItems:()=>KWe,isArray:()=>Tx,isAtLeast:()=>d_,isAtMost:()=>ZWe,isBase64:()=>oYe,isBoolean:()=>FWe,isDate:()=>OWe,isDict:()=>UWe,isEnum:()=>fo,isHexColor:()=>sYe,isISO8601:()=>iYe,isInExclusiveRange:()=>eYe,isInInclusiveRange:()=>$We,isInstanceOf:()=>HWe,isInteger:()=>m_,isJSON:()=>aYe,isLiteral:()=>Rre,isLowerCase:()=>tYe,isMap:()=>MWe,isNegative:()=>zWe,isNullable:()=>cYe,isNumber:()=>h_,isObject:()=>Fre,isOneOf:()=>g_,isOptional:()=>lYe,isPartial:()=>_We,isPayload:()=>NWe,isPositive:()=>XWe,isRecord:()=>Fx,isSet:()=>LWe,isString:()=>wE,isTuple:()=>Rx,isUUID4:()=>nYe,isUnknown:()=>p_,isUpperCase:()=>rYe,makeTrait:()=>Nre,makeValidator:()=>Wr,matchesRegExp:()=>Z2,softAssert:()=>qWe});function ti(t){return t===null?"null":t===void 0?"undefined":t===""?"an empty string":typeof t=="symbol"?`<${t.toString()}>`:Array.isArray(t)?"an array":JSON.stringify(t)}function CE(t,e){if(t.length===0)return"nothing";if(t.length===1)return ti(t[0]);let r=t.slice(0,-1),s=t[t.length-1],a=t.length>2?`, ${e} `:` ${e} `;return`${r.map(n=>ti(n)).join(", ")}${a}${ti(s)}`}function s0(t,e){var r,s,a;return typeof e=="number"?`${(r=t?.p)!==null&&r!==void 0?r:"."}[${e}]`:bWe.test(e)?`${(s=t?.p)!==null&&s!==void 0?s:""}.${e}`:`${(a=t?.p)!==null&&a!==void 0?a:"."}[${JSON.stringify(e)}]`}function A_(t,e,r){return t===1?e:r}function mr({errors:t,p:e}={},r){return t?.push(`${e??"."}: ${r}`),!1}function TWe(t,e){return r=>{t[e]=r}}function Wf(t,e){return r=>{let s=t[e];return t[e]=r,Wf(t,e).bind(null,s)}}function X2(t,e,r){let s=()=>(t(r()),a),a=()=>(t(e),s);return s}function p_(){return Wr({test:(t,e)=>!0})}function Rre(t){return Wr({test:(e,r)=>e!==t?mr(r,`Expected ${ti(t)} (got ${ti(e)})`):!0})}function wE(){return Wr({test:(t,e)=>typeof t!="string"?mr(e,`Expected a string (got ${ti(t)})`):!0})}function fo(t){let e=Array.isArray(t)?t:Object.values(t),r=e.every(a=>typeof a=="string"||typeof a=="number"),s=new Set(e);return s.size===1?Rre([...s][0]):Wr({test:(a,n)=>s.has(a)?!0:r?mr(n,`Expected one of ${CE(e,"or")} (got ${ti(a)})`):mr(n,`Expected a valid enumeration value (got ${ti(a)})`)})}function FWe(){return Wr({test:(t,e)=>{var r;if(typeof t!="boolean"){if(typeof e?.coercions<"u"){if(typeof e?.coercion>"u")return mr(e,"Unbound coercion result");let s=RWe.get(t);if(typeof s<"u")return e.coercions.push([(r=e.p)!==null&&r!==void 0?r:".",e.coercion.bind(null,s)]),!0}return mr(e,`Expected a boolean (got ${ti(t)})`)}return!0}})}function h_(){return Wr({test:(t,e)=>{var r;if(typeof t!="number"){if(typeof e?.coercions<"u"){if(typeof e?.coercion>"u")return mr(e,"Unbound coercion result");let s;if(typeof t=="string"){let a;try{a=JSON.parse(t)}catch{}if(typeof a=="number")if(JSON.stringify(a)===t)s=a;else return mr(e,`Received a number that can't be safely represented by the runtime (${t})`)}if(typeof s<"u")return e.coercions.push([(r=e.p)!==null&&r!==void 0?r:".",e.coercion.bind(null,s)]),!0}return mr(e,`Expected a number (got ${ti(t)})`)}return!0}})}function NWe(t){return Wr({test:(e,r)=>{var s;if(typeof r?.coercions>"u")return mr(r,"The isPayload predicate can only be used with coercion enabled");if(typeof r.coercion>"u")return mr(r,"Unbound coercion result");if(typeof e!="string")return mr(r,`Expected a string (got ${ti(e)})`);let a;try{a=JSON.parse(e)}catch{return mr(r,`Expected a JSON string (got ${ti(e)})`)}let n={value:a};return t(a,Object.assign(Object.assign({},r),{coercion:Wf(n,"value")}))?(r.coercions.push([(s=r.p)!==null&&s!==void 0?s:".",r.coercion.bind(null,n.value)]),!0):!1}})}function OWe(){return Wr({test:(t,e)=>{var r;if(!(t instanceof Date)){if(typeof e?.coercions<"u"){if(typeof e?.coercion>"u")return mr(e,"Unbound coercion result");let s;if(typeof t=="string"&&Tre.test(t))s=new Date(t);else{let a;if(typeof t=="string"){let n;try{n=JSON.parse(t)}catch{}typeof n=="number"&&(a=n)}else typeof t=="number"&&(a=t);if(typeof a<"u")if(Number.isSafeInteger(a)||!Number.isSafeInteger(a*1e3))s=new Date(a*1e3);else return mr(e,`Received a timestamp that can't be safely represented by the runtime (${t})`)}if(typeof s<"u")return e.coercions.push([(r=e.p)!==null&&r!==void 0?r:".",e.coercion.bind(null,s)]),!0}return mr(e,`Expected a date (got ${ti(t)})`)}return!0}})}function Tx(t,{delimiter:e}={}){return Wr({test:(r,s)=>{var a;let n=r;if(typeof r=="string"&&typeof e<"u"&&typeof s?.coercions<"u"){if(typeof s?.coercion>"u")return mr(s,"Unbound coercion result");r=r.split(e)}if(!Array.isArray(r))return mr(s,`Expected an array (got ${ti(r)})`);let c=!0;for(let f=0,p=r.length;f{var n,c;if(Object.getPrototypeOf(s).toString()==="[object Set]")if(typeof a?.coercions<"u"){if(typeof a?.coercion>"u")return mr(a,"Unbound coercion result");let f=[...s],p=[...s];if(!r(p,Object.assign(Object.assign({},a),{coercion:void 0})))return!1;let h=()=>p.some((E,C)=>E!==f[C])?new Set(p):s;return a.coercions.push([(n=a.p)!==null&&n!==void 0?n:".",X2(a.coercion,s,h)]),!0}else{let f=!0;for(let p of s)if(f=t(p,Object.assign({},a))&&f,!f&&a?.errors==null)break;return f}if(typeof a?.coercions<"u"){if(typeof a?.coercion>"u")return mr(a,"Unbound coercion result");let f={value:s};return r(s,Object.assign(Object.assign({},a),{coercion:Wf(f,"value")}))?(a.coercions.push([(c=a.p)!==null&&c!==void 0?c:".",X2(a.coercion,s,()=>new Set(f.value))]),!0):!1}return mr(a,`Expected a set (got ${ti(s)})`)}})}function MWe(t,e){let r=Tx(Rx([t,e])),s=Fx(e,{keys:t});return Wr({test:(a,n)=>{var c,f,p;if(Object.getPrototypeOf(a).toString()==="[object Map]")if(typeof n?.coercions<"u"){if(typeof n?.coercion>"u")return mr(n,"Unbound coercion result");let h=[...a],E=[...a];if(!r(E,Object.assign(Object.assign({},n),{coercion:void 0})))return!1;let C=()=>E.some((S,P)=>S[0]!==h[P][0]||S[1]!==h[P][1])?new Map(E):a;return n.coercions.push([(c=n.p)!==null&&c!==void 0?c:".",X2(n.coercion,a,C)]),!0}else{let h=!0;for(let[E,C]of a)if(h=t(E,Object.assign({},n))&&h,!h&&n?.errors==null||(h=e(C,Object.assign(Object.assign({},n),{p:s0(n,E)}))&&h,!h&&n?.errors==null))break;return h}if(typeof n?.coercions<"u"){if(typeof n?.coercion>"u")return mr(n,"Unbound coercion result");let h={value:a};return Array.isArray(a)?r(a,Object.assign(Object.assign({},n),{coercion:void 0}))?(n.coercions.push([(f=n.p)!==null&&f!==void 0?f:".",X2(n.coercion,a,()=>new Map(h.value))]),!0):!1:s(a,Object.assign(Object.assign({},n),{coercion:Wf(h,"value")}))?(n.coercions.push([(p=n.p)!==null&&p!==void 0?p:".",X2(n.coercion,a,()=>new Map(Object.entries(h.value)))]),!0):!1}return mr(n,`Expected a map (got ${ti(a)})`)}})}function Rx(t,{delimiter:e}={}){let r=Ore(t.length);return Wr({test:(s,a)=>{var n;if(typeof s=="string"&&typeof e<"u"&&typeof a?.coercions<"u"){if(typeof a?.coercion>"u")return mr(a,"Unbound coercion result");s=s.split(e),a.coercions.push([(n=a.p)!==null&&n!==void 0?n:".",a.coercion.bind(null,s)])}if(!Array.isArray(s))return mr(a,`Expected a tuple (got ${ti(s)})`);let c=r(s,Object.assign({},a));for(let f=0,p=s.length;f{var n;if(Array.isArray(s)&&typeof a?.coercions<"u")return typeof a?.coercion>"u"?mr(a,"Unbound coercion result"):r(s,Object.assign(Object.assign({},a),{coercion:void 0}))?(s=Object.fromEntries(s),a.coercions.push([(n=a.p)!==null&&n!==void 0?n:".",a.coercion.bind(null,s)]),!0):!1;if(typeof s!="object"||s===null)return mr(a,`Expected an object (got ${ti(s)})`);let c=Object.keys(s),f=!0;for(let p=0,h=c.length;p{if(typeof a!="object"||a===null)return mr(n,`Expected an object (got ${ti(a)})`);let c=new Set([...r,...Object.keys(a)]),f={},p=!0;for(let h of c){if(h==="constructor"||h==="__proto__")p=mr(Object.assign(Object.assign({},n),{p:s0(n,h)}),"Unsafe property name");else{let E=Object.prototype.hasOwnProperty.call(t,h)?t[h]:void 0,C=Object.prototype.hasOwnProperty.call(a,h)?a[h]:void 0;typeof E<"u"?p=E(C,Object.assign(Object.assign({},n),{p:s0(n,h),coercion:Wf(a,h)}))&&p:e===null?p=mr(Object.assign(Object.assign({},n),{p:s0(n,h)}),`Extraneous property (got ${ti(C)})`):Object.defineProperty(f,h,{enumerable:!0,get:()=>C,set:TWe(a,h)})}if(!p&&n?.errors==null)break}return e!==null&&(p||n?.errors!=null)&&(p=e(f,n)&&p),p}});return Object.assign(s,{properties:t})}function _We(t){return Fre(t,{extra:Fx(p_())})}function Nre(t){return()=>t}function Wr({test:t}){return Nre(t)()}function jWe(t,e){if(!e(t))throw new o0}function GWe(t,e){let r=[];if(!e(t,{errors:r}))throw new o0({errors:r})}function qWe(t,e){}function WWe(t,e,{coerce:r=!1,errors:s,throw:a}={}){let n=s?[]:void 0;if(!r){if(e(t,{errors:n}))return a?t:{value:t,errors:void 0};if(a)throw new o0({errors:n});return{value:void 0,errors:n??!0}}let c={value:t},f=Wf(c,"value"),p=[];if(!e(t,{errors:n,coercion:f,coercions:p})){if(a)throw new o0({errors:n});return{value:void 0,errors:n??!0}}for(let[,h]of p)h();return a?c.value:{value:c.value,errors:void 0}}function YWe(t,e){let r=Rx(t);return(...s)=>{if(!r(s))throw new o0;return e(...s)}}function VWe(t){return Wr({test:(e,r)=>e.length>=t?!0:mr(r,`Expected to have a length of at least ${t} elements (got ${e.length})`)})}function JWe(t){return Wr({test:(e,r)=>e.length<=t?!0:mr(r,`Expected to have a length of at most ${t} elements (got ${e.length})`)})}function Ore(t){return Wr({test:(e,r)=>e.length!==t?mr(r,`Expected to have a length of exactly ${t} elements (got ${e.length})`):!0})}function KWe({map:t}={}){return Wr({test:(e,r)=>{let s=new Set,a=new Set;for(let n=0,c=e.length;nt<=0?!0:mr(e,`Expected to be negative (got ${t})`)})}function XWe(){return Wr({test:(t,e)=>t>=0?!0:mr(e,`Expected to be positive (got ${t})`)})}function d_(t){return Wr({test:(e,r)=>e>=t?!0:mr(r,`Expected to be at least ${t} (got ${e})`)})}function ZWe(t){return Wr({test:(e,r)=>e<=t?!0:mr(r,`Expected to be at most ${t} (got ${e})`)})}function $We(t,e){return Wr({test:(r,s)=>r>=t&&r<=e?!0:mr(s,`Expected to be in the [${t}; ${e}] range (got ${r})`)})}function eYe(t,e){return Wr({test:(r,s)=>r>=t&&re!==Math.round(e)?mr(r,`Expected to be an integer (got ${e})`):!t&&!Number.isSafeInteger(e)?mr(r,`Expected to be a safe integer (got ${e})`):!0})}function Z2(t){return Wr({test:(e,r)=>t.test(e)?!0:mr(r,`Expected to match the pattern ${t.toString()} (got ${ti(e)})`)})}function tYe(){return Wr({test:(t,e)=>t!==t.toLowerCase()?mr(e,`Expected to be all-lowercase (got ${t})`):!0})}function rYe(){return Wr({test:(t,e)=>t!==t.toUpperCase()?mr(e,`Expected to be all-uppercase (got ${t})`):!0})}function nYe(){return Wr({test:(t,e)=>QWe.test(t)?!0:mr(e,`Expected to be a valid UUID v4 (got ${ti(t)})`)})}function iYe(){return Wr({test:(t,e)=>Tre.test(t)?!0:mr(e,`Expected to be a valid ISO 8601 date string (got ${ti(t)})`)})}function sYe({alpha:t=!1}){return Wr({test:(e,r)=>(t?PWe.test(e):xWe.test(e))?!0:mr(r,`Expected to be a valid hexadecimal color string (got ${ti(e)})`)})}function oYe(){return Wr({test:(t,e)=>kWe.test(t)?!0:mr(e,`Expected to be a valid base 64 string (got ${ti(t)})`)})}function aYe(t=p_()){return Wr({test:(e,r)=>{let s;try{s=JSON.parse(e)}catch{return mr(r,`Expected to be a valid JSON string (got ${ti(e)})`)}return t(s,r)}})}function Nx(t,...e){let r=Array.isArray(e[0])?e[0]:e;return Wr({test:(s,a)=>{var n,c;let f={value:s},p=typeof a?.coercions<"u"?Wf(f,"value"):void 0,h=typeof a?.coercions<"u"?[]:void 0;if(!t(s,Object.assign(Object.assign({},a),{coercion:p,coercions:h})))return!1;let E=[];if(typeof h<"u")for(let[,C]of h)E.push(C());try{if(typeof a?.coercions<"u"){if(f.value!==s){if(typeof a?.coercion>"u")return mr(a,"Unbound coercion result");a.coercions.push([(n=a.p)!==null&&n!==void 0?n:".",a.coercion.bind(null,f.value)])}(c=a?.coercions)===null||c===void 0||c.push(...h)}return r.every(C=>C(f.value,a))}finally{for(let C of E)C()}}})}function $2(t,...e){let r=Array.isArray(e[0])?e[0]:e;return Nx(t,r)}function lYe(t){return Wr({test:(e,r)=>typeof e>"u"?!0:t(e,r)})}function cYe(t){return Wr({test:(e,r)=>e===null?!0:t(e,r)})}function uYe(t,e){var r;let s=new Set(t),a=eB[(r=e?.missingIf)!==null&&r!==void 0?r:"missing"];return Wr({test:(n,c)=>{let f=new Set(Object.keys(n)),p=[];for(let h of s)a(f,h,n)||p.push(h);return p.length>0?mr(c,`Missing required ${A_(p.length,"property","properties")} ${CE(p,"and")}`):!0}})}function y_(t,e){var r;let s=new Set(t),a=eB[(r=e?.missingIf)!==null&&r!==void 0?r:"missing"];return Wr({test:(n,c)=>Object.keys(n).some(h=>a(s,h,n))?!0:mr(c,`Missing at least one property from ${CE(Array.from(s),"or")}`)})}function fYe(t,e){var r;let s=new Set(t),a=eB[(r=e?.missingIf)!==null&&r!==void 0?r:"missing"];return Wr({test:(n,c)=>{let f=new Set(Object.keys(n)),p=[];for(let h of s)a(f,h,n)&&p.push(h);return p.length>0?mr(c,`Forbidden ${A_(p.length,"property","properties")} ${CE(p,"and")}`):!0}})}function AYe(t,e){var r;let s=new Set(t),a=eB[(r=e?.missingIf)!==null&&r!==void 0?r:"missing"];return Wr({test:(n,c)=>{let f=new Set(Object.keys(n)),p=[];for(let h of s)a(f,h,n)&&p.push(h);return p.length>1?mr(c,`Mutually exclusive properties ${CE(p,"and")}`):!0}})}function tB(t,e,r,s){var a,n;let c=new Set((a=s?.ignore)!==null&&a!==void 0?a:[]),f=eB[(n=s?.missingIf)!==null&&n!==void 0?n:"missing"],p=new Set(r),h=pYe[e],E=e===qf.Forbids?"or":"and";return Wr({test:(C,S)=>{let P=new Set(Object.keys(C));if(!f(P,t,C)||c.has(C[t]))return!0;let I=[];for(let R of p)(f(P,R,C)&&!c.has(C[R]))!==h.expect&&I.push(R);return I.length>=1?mr(S,`Property "${t}" ${h.message} ${A_(I.length,"property","properties")} ${CE(I,E)}`):!0}})}var bWe,PWe,xWe,kWe,QWe,Tre,RWe,HWe,g_,o0,eB,qf,pYe,Ul=Xe(()=>{bWe=/^[a-zA-Z_][a-zA-Z0-9_]*$/;PWe=/^#[0-9a-f]{6}$/i,xWe=/^#[0-9a-f]{6}([0-9a-f]{2})?$/i,kWe=/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/,QWe=/^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}$/i,Tre=/^(?:[1-9]\d{3}(-?)(?:(?:0[1-9]|1[0-2])\1(?:0[1-9]|1\d|2[0-8])|(?:0[13-9]|1[0-2])\1(?:29|30)|(?:0[13578]|1[02])(?:\1)31|00[1-9]|0[1-9]\d|[12]\d{2}|3(?:[0-5]\d|6[0-5]))|(?:[1-9]\d(?:0[48]|[2468][048]|[13579][26])|(?:[2468][048]|[13579][26])00)(?:(-?)02(?:\2)29|-?366))T(?:[01]\d|2[0-3])(:?)[0-5]\d(?:\3[0-5]\d)?(?:Z|[+-][01]\d(?:\3[0-5]\d)?)$/;RWe=new Map([["true",!0],["True",!0],["1",!0],[1,!0],["false",!1],["False",!1],["0",!1],[0,!1]]);HWe=t=>Wr({test:(e,r)=>e instanceof t?!0:mr(r,`Expected an instance of ${t.name} (got ${ti(e)})`)}),g_=(t,{exclusive:e=!1}={})=>Wr({test:(r,s)=>{var a,n,c;let f=[],p=typeof s?.errors<"u"?[]:void 0;for(let h=0,E=t.length;h1?mr(s,`Expected to match exactly a single predicate (matched ${f.join(", ")})`):(c=s?.errors)===null||c===void 0||c.push(...p),!1}});o0=class extends Error{constructor({errors:e}={}){let r="Type mismatch";if(e&&e.length>0){r+=` +`;for(let s of e)r+=` +- ${s}`}super(r)}};eB={missing:(t,e)=>t.has(e),undefined:(t,e,r)=>t.has(e)&&typeof r[e]<"u",nil:(t,e,r)=>t.has(e)&&r[e]!=null,falsy:(t,e,r)=>t.has(e)&&!!r[e]};(function(t){t.Forbids="Forbids",t.Requires="Requires"})(qf||(qf={}));pYe={[qf.Forbids]:{expect:!1,message:"forbids using"},[qf.Requires]:{expect:!0,message:"requires using"}}});var ot,a0=Xe(()=>{Cp();ot=class{constructor(){this.help=!1}static Usage(e){return e}async catch(e){throw e}async validateAndExecute(){let r=this.constructor.schema;if(Array.isArray(r)){let{isDict:a,isUnknown:n,applyCascade:c}=await Promise.resolve().then(()=>(Ul(),Ea)),f=c(a(n()),r),p=[],h=[];if(!f(this,{errors:p,coercions:h}))throw z2("Invalid option schema",p);for(let[,C]of h)C()}else if(r!=null)throw new Error("Invalid command schema");let s=await this.execute();return typeof s<"u"?s:0}};ot.isOption=K2;ot.Default=[]});function il(t){l_&&console.log(t)}function Mre(){let t={nodes:[]};for(let e=0;e{if(e.has(s))return;e.add(s);let a=t.nodes[s];for(let c of Object.values(a.statics))for(let{to:f}of c)r(f);for(let[,{to:c}]of a.dynamics)r(c);for(let{to:c}of a.shortcuts)r(c);let n=new Set(a.shortcuts.map(({to:c})=>c));for(;a.shortcuts.length>0;){let{to:c}=a.shortcuts.shift(),f=t.nodes[c];for(let[p,h]of Object.entries(f.statics)){let E=Object.prototype.hasOwnProperty.call(a.statics,p)?a.statics[p]:a.statics[p]=[];for(let C of h)E.some(({to:S})=>C.to===S)||E.push(C)}for(let[p,h]of f.dynamics)a.dynamics.some(([E,{to:C}])=>p===E&&h.to===C)||a.dynamics.push([p,h]);for(let p of f.shortcuts)n.has(p.to)||(a.shortcuts.push(p),n.add(p.to))}};r(En.InitialNode)}function dYe(t,{prefix:e=""}={}){if(l_){il(`${e}Nodes are:`);for(let r=0;rE!==En.ErrorNode).map(({state:E})=>({usage:E.candidateUsage,reason:null})));if(h.every(({node:E})=>E===En.ErrorNode))throw new IE(e,h.map(({state:E})=>({usage:E.candidateUsage,reason:E.errorMessage})));s=EYe(h)}if(s.length>0){il(" Results:");for(let n of s)il(` - ${n.node} -> ${JSON.stringify(n.state)}`)}else il(" No results");return s}function yYe(t,e,{endToken:r=ei.EndOfInput}={}){let s=mYe(t,[...e,r]);return IYe(e,s.map(({state:a})=>a))}function EYe(t){let e=0;for(let{state:r}of t)r.path.length>e&&(e=r.path.length);return t.filter(({state:r})=>r.path.length===e)}function IYe(t,e){let r=e.filter(S=>S.selectedIndex!==null),s=r.filter(S=>!S.partial);if(s.length>0&&(r=s),r.length===0)throw new Error;let a=r.filter(S=>S.selectedIndex===Nd||S.requiredOptions.every(P=>P.some(I=>S.options.find(R=>R.name===I))));if(a.length===0)throw new IE(t,r.map(S=>({usage:S.candidateUsage,reason:null})));let n=0;for(let S of a)S.path.length>n&&(n=S.path.length);let c=a.filter(S=>S.path.length===n),f=S=>S.positionals.filter(({extra:P})=>!P).length+S.options.length,p=c.map(S=>({state:S,positionalCount:f(S)})),h=0;for(let{positionalCount:S}of p)S>h&&(h=S);let E=p.filter(({positionalCount:S})=>S===h).map(({state:S})=>S),C=CYe(E);if(C.length>1)throw new xx(t,C.map(S=>S.candidateUsage));return C[0]}function CYe(t){let e=[],r=[];for(let s of t)s.selectedIndex===Nd?r.push(s):e.push(s);return r.length>0&&e.push({...Lre,path:Ure(...r.map(s=>s.path)),options:r.reduce((s,a)=>s.concat(a.options),[])}),e}function Ure(t,e,...r){return e===void 0?Array.from(t):Ure(t.filter((s,a)=>s===e[a]),...r)}function _l(){return{dynamics:[],shortcuts:[],statics:{}}}function _re(t){return t===En.SuccessNode||t===En.ErrorNode}function E_(t,e=0){return{to:_re(t.to)?t.to:t.to>=En.CustomNode?t.to+e-En.CustomNode+1:t.to+e,reducer:t.reducer}}function wYe(t,e=0){let r=_l();for(let[s,a]of t.dynamics)r.dynamics.push([s,E_(a,e)]);for(let s of t.shortcuts)r.shortcuts.push(E_(s,e));for(let[s,a]of Object.entries(t.statics))r.statics[s]=a.map(n=>E_(n,e));return r}function Hs(t,e,r,s,a){t.nodes[e].dynamics.push([r,{to:s,reducer:a}])}function BE(t,e,r,s){t.nodes[e].shortcuts.push({to:r,reducer:s})}function Ia(t,e,r,s,a){(Object.prototype.hasOwnProperty.call(t.nodes[e].statics,r)?t.nodes[e].statics[r]:t.nodes[e].statics[r]=[]).push({to:s,reducer:a})}function Ox(t,e,r,s,a){if(Array.isArray(e)){let[n,...c]=e;return t[n](r,s,a,...c)}else return t[e](r,s,a)}var Lre,BYe,I_,Hl,C_,Lx,Mx=Xe(()=>{Px();kx();Lre={candidateUsage:null,requiredOptions:[],errorMessage:null,ignoreOptions:!1,path:[],positionals:[],options:[],remainder:null,selectedIndex:Nd,partial:!1,tokens:[]};BYe={always:()=>!0,isOptionLike:(t,e)=>!t.ignoreOptions&&e!=="-"&&e.startsWith("-"),isNotOptionLike:(t,e)=>t.ignoreOptions||e==="-"||!e.startsWith("-"),isOption:(t,e,r,s)=>!t.ignoreOptions&&e===s,isBatchOption:(t,e,r,s)=>!t.ignoreOptions&&xre.test(e)&&[...e.slice(1)].every(a=>s.has(`-${a}`)),isBoundOption:(t,e,r,s,a)=>{let n=e.match(a_);return!t.ignoreOptions&&!!n&&bx.test(n[1])&&s.has(n[1])&&a.filter(c=>c.nameSet.includes(n[1])).every(c=>c.allowBinding)},isNegatedOption:(t,e,r,s)=>!t.ignoreOptions&&e===`--no-${s.slice(2)}`,isHelp:(t,e)=>!t.ignoreOptions&&o_.test(e),isUnsupportedOption:(t,e,r,s)=>!t.ignoreOptions&&e.startsWith("-")&&bx.test(e)&&!s.has(e),isInvalidOption:(t,e)=>!t.ignoreOptions&&e.startsWith("-")&&!bx.test(e)},I_={setCandidateState:(t,e,r,s)=>({...t,...s}),setSelectedIndex:(t,e,r,s)=>({...t,selectedIndex:s}),setPartialIndex:(t,e,r,s)=>({...t,selectedIndex:s,partial:!0}),pushBatch:(t,e,r,s)=>{let a=t.options.slice(),n=t.tokens.slice();for(let c=1;c{let[,s,a]=e.match(a_),n=t.options.concat({name:s,value:a}),c=t.tokens.concat([{segmentIndex:r,type:"option",slice:[0,s.length],option:s},{segmentIndex:r,type:"assign",slice:[s.length,s.length+1]},{segmentIndex:r,type:"value",slice:[s.length+1,s.length+a.length+1]}]);return{...t,options:n,tokens:c}},pushPath:(t,e,r)=>{let s=t.path.concat(e),a=t.tokens.concat({segmentIndex:r,type:"path"});return{...t,path:s,tokens:a}},pushPositional:(t,e,r)=>{let s=t.positionals.concat({value:e,extra:!1}),a=t.tokens.concat({segmentIndex:r,type:"positional"});return{...t,positionals:s,tokens:a}},pushExtra:(t,e,r)=>{let s=t.positionals.concat({value:e,extra:!0}),a=t.tokens.concat({segmentIndex:r,type:"positional"});return{...t,positionals:s,tokens:a}},pushExtraNoLimits:(t,e,r)=>{let s=t.positionals.concat({value:e,extra:Hl}),a=t.tokens.concat({segmentIndex:r,type:"positional"});return{...t,positionals:s,tokens:a}},pushTrue:(t,e,r,s)=>{let a=t.options.concat({name:s,value:!0}),n=t.tokens.concat({segmentIndex:r,type:"option",option:s});return{...t,options:a,tokens:n}},pushFalse:(t,e,r,s)=>{let a=t.options.concat({name:s,value:!1}),n=t.tokens.concat({segmentIndex:r,type:"option",option:s});return{...t,options:a,tokens:n}},pushUndefined:(t,e,r,s)=>{let a=t.options.concat({name:e,value:void 0}),n=t.tokens.concat({segmentIndex:r,type:"option",option:e});return{...t,options:a,tokens:n}},pushStringValue:(t,e,r)=>{var s;let a=t.options[t.options.length-1],n=t.options.slice(),c=t.tokens.concat({segmentIndex:r,type:"value"});return a.value=((s=a.value)!==null&&s!==void 0?s:[]).concat([e]),{...t,options:n,tokens:c}},setStringValue:(t,e,r)=>{let s=t.options[t.options.length-1],a=t.options.slice(),n=t.tokens.concat({segmentIndex:r,type:"value"});return s.value=e,{...t,options:a,tokens:n}},inhibateOptions:t=>({...t,ignoreOptions:!0}),useHelp:(t,e,r,s)=>{let[,,a]=e.match(o_);return typeof a<"u"?{...t,options:[{name:"-c",value:String(s)},{name:"-i",value:a}]}:{...t,options:[{name:"-c",value:String(s)}]}},setError:(t,e,r,s)=>e===ei.EndOfInput||e===ei.EndOfPartialInput?{...t,errorMessage:`${s}.`}:{...t,errorMessage:`${s} ("${e}").`},setOptionArityError:(t,e)=>{let r=t.options[t.options.length-1];return{...t,errorMessage:`Not enough arguments to option ${r.name}.`}}},Hl=Symbol(),C_=class{constructor(e,r){this.allOptionNames=new Map,this.arity={leading:[],trailing:[],extra:[],proxy:!1},this.options=[],this.paths=[],this.cliIndex=e,this.cliOpts=r}addPath(e){this.paths.push(e)}setArity({leading:e=this.arity.leading,trailing:r=this.arity.trailing,extra:s=this.arity.extra,proxy:a=this.arity.proxy}){Object.assign(this.arity,{leading:e,trailing:r,extra:s,proxy:a})}addPositional({name:e="arg",required:r=!0}={}){if(!r&&this.arity.extra===Hl)throw new Error("Optional parameters cannot be declared when using .rest() or .proxy()");if(!r&&this.arity.trailing.length>0)throw new Error("Optional parameters cannot be declared after the required trailing positional arguments");!r&&this.arity.extra!==Hl?this.arity.extra.push(e):this.arity.extra!==Hl&&this.arity.extra.length===0?this.arity.leading.push(e):this.arity.trailing.push(e)}addRest({name:e="arg",required:r=0}={}){if(this.arity.extra===Hl)throw new Error("Infinite lists cannot be declared multiple times in the same command");if(this.arity.trailing.length>0)throw new Error("Infinite lists cannot be declared after the required trailing positional arguments");for(let s=0;s1)throw new Error("The arity cannot be higher than 1 when the option only supports the --arg=value syntax");if(!Number.isInteger(s))throw new Error(`The arity must be an integer, got ${s}`);if(s<0)throw new Error(`The arity must be positive, got ${s}`);let f=e.reduce((p,h)=>h.length>p.length?h:p,"");for(let p of e)this.allOptionNames.set(p,f);this.options.push({preferredName:f,nameSet:e,description:r,arity:s,hidden:a,required:n,allowBinding:c})}setContext(e){this.context=e}usage({detailed:e=!0,inlineOptions:r=!0}={}){let s=[this.cliOpts.binaryName],a=[];if(this.paths.length>0&&s.push(...this.paths[0]),e){for(let{preferredName:c,nameSet:f,arity:p,hidden:h,description:E,required:C}of this.options){if(h)continue;let S=[];for(let I=0;I`:`[${P}]`)}s.push(...this.arity.leading.map(c=>`<${c}>`)),this.arity.extra===Hl?s.push("..."):s.push(...this.arity.extra.map(c=>`[${c}]`)),s.push(...this.arity.trailing.map(c=>`<${c}>`))}return{usage:s.join(" "),options:a}}compile(){if(typeof this.context>"u")throw new Error("Assertion failed: No context attached");let e=Mre(),r=En.InitialNode,s=this.usage().usage,a=this.options.filter(f=>f.required).map(f=>f.nameSet);r=Ou(e,_l()),Ia(e,En.InitialNode,ei.StartOfInput,r,["setCandidateState",{candidateUsage:s,requiredOptions:a}]);let n=this.arity.proxy?"always":"isNotOptionLike",c=this.paths.length>0?this.paths:[[]];for(let f of c){let p=r;if(f.length>0){let S=Ou(e,_l());BE(e,p,S),this.registerOptions(e,S),p=S}for(let S=0;S0||!this.arity.proxy){let S=Ou(e,_l());Hs(e,p,"isHelp",S,["useHelp",this.cliIndex]),Hs(e,S,"always",S,"pushExtra"),Ia(e,S,ei.EndOfInput,En.SuccessNode,["setSelectedIndex",Nd]),this.registerOptions(e,p)}this.arity.leading.length>0&&(Ia(e,p,ei.EndOfInput,En.ErrorNode,["setError","Not enough positional arguments"]),Ia(e,p,ei.EndOfPartialInput,En.SuccessNode,["setPartialIndex",this.cliIndex]));let h=p;for(let S=0;S0||S+1!==this.arity.leading.length)&&(Ia(e,P,ei.EndOfInput,En.ErrorNode,["setError","Not enough positional arguments"]),Ia(e,P,ei.EndOfPartialInput,En.SuccessNode,["setPartialIndex",this.cliIndex])),Hs(e,h,"isNotOptionLike",P,"pushPositional"),h=P}let E=h;if(this.arity.extra===Hl||this.arity.extra.length>0){let S=Ou(e,_l());if(BE(e,h,S),this.arity.extra===Hl){let P=Ou(e,_l());this.arity.proxy||this.registerOptions(e,P),Hs(e,h,n,P,"pushExtraNoLimits"),Hs(e,P,n,P,"pushExtraNoLimits"),BE(e,P,S)}else for(let P=0;P0)&&this.registerOptions(e,I),Hs(e,E,n,I,"pushExtra"),BE(e,I,S),E=I}E=S}this.arity.trailing.length>0&&(Ia(e,E,ei.EndOfInput,En.ErrorNode,["setError","Not enough positional arguments"]),Ia(e,E,ei.EndOfPartialInput,En.SuccessNode,["setPartialIndex",this.cliIndex]));let C=E;for(let S=0;S=0&&e{let c=n?ei.EndOfPartialInput:ei.EndOfInput;return yYe(s,a,{endToken:c})}}}}});function jre(){return Ux.default&&"getColorDepth"in Ux.default.WriteStream.prototype?Ux.default.WriteStream.prototype.getColorDepth():process.env.FORCE_COLOR==="0"?1:process.env.FORCE_COLOR==="1"||typeof process.stdout<"u"&&process.stdout.isTTY?8:1}function Gre(t){let e=Hre;if(typeof e>"u"){if(t.stdout===process.stdout&&t.stderr===process.stderr)return null;let{AsyncLocalStorage:r}=Ie("async_hooks");e=Hre=new r;let s=process.stdout._write;process.stdout._write=function(n,c,f){let p=e.getStore();return typeof p>"u"?s.call(this,n,c,f):p.stdout.write(n,c,f)};let a=process.stderr._write;process.stderr._write=function(n,c,f){let p=e.getStore();return typeof p>"u"?a.call(this,n,c,f):p.stderr.write(n,c,f)}}return r=>e.run(t,r)}var Ux,Hre,qre=Xe(()=>{Ux=ut(Ie("tty"),1)});var _x,Wre=Xe(()=>{a0();_x=class t extends ot{constructor(e){super(),this.contexts=e,this.commands=[]}static from(e,r){let s=new t(r);s.path=e.path;for(let a of e.options)switch(a.name){case"-c":s.commands.push(Number(a.value));break;case"-i":s.index=Number(a.value);break}return s}async execute(){let e=this.commands;if(typeof this.index<"u"&&this.index>=0&&this.index1){this.context.stdout.write(`Multiple commands match your selection: +`),this.context.stdout.write(` +`);let r=0;for(let s of this.commands)this.context.stdout.write(this.cli.usage(this.contexts[s].commandClass,{prefix:`${r++}. `.padStart(5)}));this.context.stdout.write(` +`),this.context.stdout.write(`Run again with -h= to see the longer details of any of those commands. +`)}}}});async function Jre(...t){let{resolvedOptions:e,resolvedCommandClasses:r,resolvedArgv:s,resolvedContext:a}=zre(t);return Ca.from(r,e).runExit(s,a)}async function Kre(...t){let{resolvedOptions:e,resolvedCommandClasses:r,resolvedArgv:s,resolvedContext:a}=zre(t);return Ca.from(r,e).run(s,a)}function zre(t){let e,r,s,a;switch(typeof process<"u"&&typeof process.argv<"u"&&(s=process.argv.slice(2)),t.length){case 1:r=t[0];break;case 2:t[0]&&t[0].prototype instanceof ot||Array.isArray(t[0])?(r=t[0],Array.isArray(t[1])?s=t[1]:a=t[1]):(e=t[0],r=t[1]);break;case 3:Array.isArray(t[2])?(e=t[0],r=t[1],s=t[2]):t[0]&&t[0].prototype instanceof ot||Array.isArray(t[0])?(r=t[0],s=t[1],a=t[2]):(e=t[0],r=t[1],a=t[2]);break;default:e=t[0],r=t[1],s=t[2],a=t[3];break}if(typeof s>"u")throw new Error("The argv parameter must be provided when running Clipanion outside of a Node context");return{resolvedOptions:e,resolvedCommandClasses:r,resolvedArgv:s,resolvedContext:a}}function Vre(t){return t()}var Yre,Ca,Xre=Xe(()=>{Px();Mx();f_();qre();a0();Wre();Yre=Symbol("clipanion/errorCommand");Ca=class t{constructor({binaryLabel:e,binaryName:r="...",binaryVersion:s,enableCapture:a=!1,enableColors:n}={}){this.registrations=new Map,this.builder=new Lx({binaryName:r}),this.binaryLabel=e,this.binaryName=r,this.binaryVersion=s,this.enableCapture=a,this.enableColors=n}static from(e,r={}){let s=new t(r),a=Array.isArray(e)?e:[e];for(let n of a)s.register(n);return s}register(e){var r;let s=new Map,a=new e;for(let p in a){let h=a[p];typeof h=="object"&&h!==null&&h[ot.isOption]&&s.set(p,h)}let n=this.builder.command(),c=n.cliIndex,f=(r=e.paths)!==null&&r!==void 0?r:a.paths;if(typeof f<"u")for(let p of f)n.addPath(p);this.registrations.set(e,{specs:s,builder:n,index:c});for(let[p,{definition:h}]of s.entries())h(n,p);n.setContext({commandClass:e})}process(e,r){let{input:s,context:a,partial:n}=typeof e=="object"&&Array.isArray(e)?{input:e,context:r}:e,{contexts:c,process:f}=this.builder.compile(),p=f(s,{partial:n}),h={...t.defaultContext,...a};switch(p.selectedIndex){case Nd:{let E=_x.from(p,c);return E.context=h,E.tokens=p.tokens,E}default:{let{commandClass:E}=c[p.selectedIndex],C=this.registrations.get(E);if(typeof C>"u")throw new Error("Assertion failed: Expected the command class to have been registered.");let S=new E;S.context=h,S.tokens=p.tokens,S.path=p.path;try{for(let[P,{transformer:I}]of C.specs.entries())S[P]=I(C.builder,P,p,h);return S}catch(P){throw P[Yre]=S,P}}break}}async run(e,r){var s,a;let n,c={...t.defaultContext,...r},f=(s=this.enableColors)!==null&&s!==void 0?s:c.colorDepth>1;if(!Array.isArray(e))n=e;else try{n=this.process(e,c)}catch(E){return c.stdout.write(this.error(E,{colored:f})),1}if(n.help)return c.stdout.write(this.usage(n,{colored:f,detailed:!0})),0;n.context=c,n.cli={binaryLabel:this.binaryLabel,binaryName:this.binaryName,binaryVersion:this.binaryVersion,enableCapture:this.enableCapture,enableColors:this.enableColors,definitions:()=>this.definitions(),definition:E=>this.definition(E),error:(E,C)=>this.error(E,C),format:E=>this.format(E),process:(E,C)=>this.process(E,{...c,...C}),run:(E,C)=>this.run(E,{...c,...C}),usage:(E,C)=>this.usage(E,C)};let p=this.enableCapture&&(a=Gre(c))!==null&&a!==void 0?a:Vre,h;try{h=await p(()=>n.validateAndExecute().catch(E=>n.catch(E).then(()=>0)))}catch(E){return c.stdout.write(this.error(E,{colored:f,command:n})),1}return h}async runExit(e,r){process.exitCode=await this.run(e,r)}definition(e,{colored:r=!1}={}){if(!e.usage)return null;let{usage:s}=this.getUsageByRegistration(e,{detailed:!1}),{usage:a,options:n}=this.getUsageByRegistration(e,{detailed:!0,inlineOptions:!1}),c=typeof e.usage.category<"u"?Ho(e.usage.category,{format:this.format(r),paragraphs:!1}):void 0,f=typeof e.usage.description<"u"?Ho(e.usage.description,{format:this.format(r),paragraphs:!1}):void 0,p=typeof e.usage.details<"u"?Ho(e.usage.details,{format:this.format(r),paragraphs:!0}):void 0,h=typeof e.usage.examples<"u"?e.usage.examples.map(([E,C])=>[Ho(E,{format:this.format(r),paragraphs:!1}),C.replace(/\$0/g,this.binaryName)]):void 0;return{path:s,usage:a,category:c,description:f,details:p,examples:h,options:n}}definitions({colored:e=!1}={}){let r=[];for(let s of this.registrations.keys()){let a=this.definition(s,{colored:e});a&&r.push(a)}return r}usage(e=null,{colored:r,detailed:s=!1,prefix:a="$ "}={}){var n;if(e===null){for(let p of this.registrations.keys()){let h=p.paths,E=typeof p.usage<"u";if(!h||h.length===0||h.length===1&&h[0].length===0||((n=h?.some(P=>P.length===0))!==null&&n!==void 0?n:!1))if(e){e=null;break}else e=p;else if(E){e=null;continue}}e&&(s=!0)}let c=e!==null&&e instanceof ot?e.constructor:e,f="";if(c)if(s){let{description:p="",details:h="",examples:E=[]}=c.usage||{};p!==""&&(f+=Ho(p,{format:this.format(r),paragraphs:!1}).replace(/^./,P=>P.toUpperCase()),f+=` +`),(h!==""||E.length>0)&&(f+=`${this.format(r).header("Usage")} +`,f+=` +`);let{usage:C,options:S}=this.getUsageByRegistration(c,{inlineOptions:!1});if(f+=`${this.format(r).bold(a)}${C} +`,S.length>0){f+=` +`,f+=`${this.format(r).header("Options")} +`;let P=S.reduce((I,R)=>Math.max(I,R.definition.length),0);f+=` +`;for(let{definition:I,description:R}of S)f+=` ${this.format(r).bold(I.padEnd(P))} ${Ho(R,{format:this.format(r),paragraphs:!1})}`}if(h!==""&&(f+=` +`,f+=`${this.format(r).header("Details")} +`,f+=` +`,f+=Ho(h,{format:this.format(r),paragraphs:!0})),E.length>0){f+=` +`,f+=`${this.format(r).header("Examples")} +`;for(let[P,I]of E)f+=` +`,f+=Ho(P,{format:this.format(r),paragraphs:!1}),f+=`${I.replace(/^/m,` ${this.format(r).bold(a)}`).replace(/\$0/g,this.binaryName)} +`}}else{let{usage:p}=this.getUsageByRegistration(c);f+=`${this.format(r).bold(a)}${p} +`}else{let p=new Map;for(let[S,{index:P}]of this.registrations.entries()){if(typeof S.usage>"u")continue;let I=typeof S.usage.category<"u"?Ho(S.usage.category,{format:this.format(r),paragraphs:!1}):null,R=p.get(I);typeof R>"u"&&p.set(I,R=[]);let{usage:N}=this.getUsageByIndex(P);R.push({commandClass:S,usage:N})}let h=Array.from(p.keys()).sort((S,P)=>S===null?-1:P===null?1:S.localeCompare(P,"en",{usage:"sort",caseFirst:"upper"})),E=typeof this.binaryLabel<"u",C=typeof this.binaryVersion<"u";E||C?(E&&C?f+=`${this.format(r).header(`${this.binaryLabel} - ${this.binaryVersion}`)} + +`:E?f+=`${this.format(r).header(`${this.binaryLabel}`)} +`:f+=`${this.format(r).header(`${this.binaryVersion}`)} +`,f+=` ${this.format(r).bold(a)}${this.binaryName} +`):f+=`${this.format(r).bold(a)}${this.binaryName} +`;for(let S of h){let P=p.get(S).slice().sort((R,N)=>R.usage.localeCompare(N.usage,"en",{usage:"sort",caseFirst:"upper"})),I=S!==null?S.trim():"General commands";f+=` +`,f+=`${this.format(r).header(`${I}`)} +`;for(let{commandClass:R,usage:N}of P){let U=R.usage.description||"undocumented";f+=` +`,f+=` ${this.format(r).bold(N)} +`,f+=` ${Ho(U,{format:this.format(r),paragraphs:!1})}`}}f+=` +`,f+=Ho("You can also print more details about any of these commands by calling them with the `-h,--help` flag right after the command name.",{format:this.format(r),paragraphs:!0})}return f}error(e,r){var s,{colored:a,command:n=(s=e[Yre])!==null&&s!==void 0?s:null}=r===void 0?{}:r;(!e||typeof e!="object"||!("stack"in e))&&(e=new Error(`Execution failed with a non-error rejection (rejected value: ${JSON.stringify(e)})`));let c="",f=e.name.replace(/([a-z])([A-Z])/g,"$1 $2");f==="Error"&&(f="Internal Error"),c+=`${this.format(a).error(f)}: ${e.message} +`;let p=e.clipanion;return typeof p<"u"?p.type==="usage"&&(c+=` +`,c+=this.usage(n)):e.stack&&(c+=`${e.stack.replace(/^.*\n/,"")} +`),c}format(e){var r;return((r=e??this.enableColors)!==null&&r!==void 0?r:t.defaultContext.colorDepth>1)?kre:Qre}getUsageByRegistration(e,r){let s=this.registrations.get(e);if(typeof s>"u")throw new Error("Assertion failed: Unregistered command");return this.getUsageByIndex(s.index,r)}getUsageByIndex(e,r){return this.builder.getBuilderByIndex(e).usage(r)}};Ca.defaultContext={env:process.env,stdin:process.stdin,stdout:process.stdout,stderr:process.stderr,colorDepth:jre()}});var rB,Zre=Xe(()=>{a0();rB=class extends ot{async execute(){this.context.stdout.write(`${JSON.stringify(this.cli.definitions(),null,2)} +`)}};rB.paths=[["--clipanion=definitions"]]});var nB,$re=Xe(()=>{a0();nB=class extends ot{async execute(){this.context.stdout.write(this.cli.usage())}};nB.paths=[["-h"],["--help"]]});function Hx(t={}){return ya({definition(e,r){var s;e.addProxy({name:(s=t.name)!==null&&s!==void 0?s:r,required:t.required})},transformer(e,r,s){return s.positionals.map(({value:a})=>a)}})}var w_=Xe(()=>{Cp()});var iB,ene=Xe(()=>{a0();w_();iB=class extends ot{constructor(){super(...arguments),this.args=Hx()}async execute(){this.context.stdout.write(`${JSON.stringify(this.cli.process(this.args).tokens,null,2)} +`)}};iB.paths=[["--clipanion=tokens"]]});var sB,tne=Xe(()=>{a0();sB=class extends ot{async execute(){var e;this.context.stdout.write(`${(e=this.cli.binaryVersion)!==null&&e!==void 0?e:""} +`)}};sB.paths=[["-v"],["--version"]]});var B_={};Vt(B_,{DefinitionsCommand:()=>rB,HelpCommand:()=>nB,TokensCommand:()=>iB,VersionCommand:()=>sB});var rne=Xe(()=>{Zre();$re();ene();tne()});function nne(t,e,r){let[s,a]=Gf(e,r??{}),{arity:n=1}=a,c=t.split(","),f=new Set(c);return ya({definition(p){p.addOption({names:c,arity:n,hidden:a?.hidden,description:a?.description,required:a.required})},transformer(p,h,E){let C,S=typeof s<"u"?[...s]:void 0;for(let{name:P,value:I}of E.options)f.has(P)&&(C=P,S=S??[],S.push(I));return typeof S<"u"?Od(C??h,S,a.validator):S}})}var ine=Xe(()=>{Cp()});function sne(t,e,r){let[s,a]=Gf(e,r??{}),n=t.split(","),c=new Set(n);return ya({definition(f){f.addOption({names:n,allowBinding:!1,arity:0,hidden:a.hidden,description:a.description,required:a.required})},transformer(f,p,h){let E=s;for(let{name:C,value:S}of h.options)c.has(C)&&(E=S);return E}})}var one=Xe(()=>{Cp()});function ane(t,e,r){let[s,a]=Gf(e,r??{}),n=t.split(","),c=new Set(n);return ya({definition(f){f.addOption({names:n,allowBinding:!1,arity:0,hidden:a.hidden,description:a.description,required:a.required})},transformer(f,p,h){let E=s;for(let{name:C,value:S}of h.options)c.has(C)&&(E??(E=0),S?E+=1:E=0);return E}})}var lne=Xe(()=>{Cp()});function cne(t={}){return ya({definition(e,r){var s;e.addRest({name:(s=t.name)!==null&&s!==void 0?s:r,required:t.required})},transformer(e,r,s){let a=c=>{let f=s.positionals[c];return f.extra===Hl||f.extra===!1&&cc)}})}var une=Xe(()=>{Mx();Cp()});function vYe(t,e,r){let[s,a]=Gf(e,r??{}),{arity:n=1}=a,c=t.split(","),f=new Set(c);return ya({definition(p){p.addOption({names:c,arity:a.tolerateBoolean?0:n,hidden:a.hidden,description:a.description,required:a.required})},transformer(p,h,E,C){let S,P=s;typeof a.env<"u"&&C.env[a.env]&&(S=a.env,P=C.env[a.env]);for(let{name:I,value:R}of E.options)f.has(I)&&(S=I,P=R);return typeof P=="string"?Od(S??h,P,a.validator):P}})}function SYe(t={}){let{required:e=!0}=t;return ya({definition(r,s){var a;r.addPositional({name:(a=t.name)!==null&&a!==void 0?a:s,required:t.required})},transformer(r,s,a){var n;for(let c=0;c{Mx();Cp()});var ge={};Vt(ge,{Array:()=>nne,Boolean:()=>sne,Counter:()=>ane,Proxy:()=>Hx,Rest:()=>cne,String:()=>fne,applyValidator:()=>Od,cleanValidationError:()=>Qx,formatError:()=>z2,isOptionSymbol:()=>K2,makeCommandOption:()=>ya,rerouteArguments:()=>Gf});var pne=Xe(()=>{Cp();w_();ine();one();lne();une();Ane()});var oB={};Vt(oB,{Builtins:()=>B_,Cli:()=>Ca,Command:()=>ot,Option:()=>ge,UsageError:()=>nt,formatMarkdownish:()=>Ho,run:()=>Kre,runExit:()=>Jre});var Yt=Xe(()=>{kx();f_();a0();Xre();rne();pne()});var hne=_((VTt,DYe)=>{DYe.exports={name:"dotenv",version:"16.3.1",description:"Loads environment variables from .env file",main:"lib/main.js",types:"lib/main.d.ts",exports:{".":{types:"./lib/main.d.ts",require:"./lib/main.js",default:"./lib/main.js"},"./config":"./config.js","./config.js":"./config.js","./lib/env-options":"./lib/env-options.js","./lib/env-options.js":"./lib/env-options.js","./lib/cli-options":"./lib/cli-options.js","./lib/cli-options.js":"./lib/cli-options.js","./package.json":"./package.json"},scripts:{"dts-check":"tsc --project tests/types/tsconfig.json",lint:"standard","lint-readme":"standard-markdown",pretest:"npm run lint && npm run dts-check",test:"tap tests/*.js --100 -Rspec",prerelease:"npm test",release:"standard-version"},repository:{type:"git",url:"git://github.com/motdotla/dotenv.git"},funding:"https://github.com/motdotla/dotenv?sponsor=1",keywords:["dotenv","env",".env","environment","variables","config","settings"],readmeFilename:"README.md",license:"BSD-2-Clause",devDependencies:{"@definitelytyped/dtslint":"^0.0.133","@types/node":"^18.11.3",decache:"^4.6.1",sinon:"^14.0.1",standard:"^17.0.0","standard-markdown":"^7.1.0","standard-version":"^9.5.0",tap:"^16.3.0",tar:"^6.1.11",typescript:"^4.8.4"},engines:{node:">=12"},browser:{fs:!1}}});var yne=_((JTt,wp)=>{var gne=Ie("fs"),S_=Ie("path"),bYe=Ie("os"),PYe=Ie("crypto"),xYe=hne(),D_=xYe.version,kYe=/(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg;function QYe(t){let e={},r=t.toString();r=r.replace(/\r\n?/mg,` +`);let s;for(;(s=kYe.exec(r))!=null;){let a=s[1],n=s[2]||"";n=n.trim();let c=n[0];n=n.replace(/^(['"`])([\s\S]*)\1$/mg,"$2"),c==='"'&&(n=n.replace(/\\n/g,` +`),n=n.replace(/\\r/g,"\r")),e[a]=n}return e}function TYe(t){let e=mne(t),r=js.configDotenv({path:e});if(!r.parsed)throw new Error(`MISSING_DATA: Cannot parse ${e} for an unknown reason`);let s=dne(t).split(","),a=s.length,n;for(let c=0;c=a)throw f}return js.parse(n)}function RYe(t){console.log(`[dotenv@${D_}][INFO] ${t}`)}function FYe(t){console.log(`[dotenv@${D_}][WARN] ${t}`)}function v_(t){console.log(`[dotenv@${D_}][DEBUG] ${t}`)}function dne(t){return t&&t.DOTENV_KEY&&t.DOTENV_KEY.length>0?t.DOTENV_KEY:process.env.DOTENV_KEY&&process.env.DOTENV_KEY.length>0?process.env.DOTENV_KEY:""}function NYe(t,e){let r;try{r=new URL(e)}catch(f){throw f.code==="ERR_INVALID_URL"?new Error("INVALID_DOTENV_KEY: Wrong format. Must be in valid uri format like dotenv://:key_1234@dotenv.org/vault/.env.vault?environment=development"):f}let s=r.password;if(!s)throw new Error("INVALID_DOTENV_KEY: Missing key part");let a=r.searchParams.get("environment");if(!a)throw new Error("INVALID_DOTENV_KEY: Missing environment part");let n=`DOTENV_VAULT_${a.toUpperCase()}`,c=t.parsed[n];if(!c)throw new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${n} in your .env.vault file.`);return{ciphertext:c,key:s}}function mne(t){let e=S_.resolve(process.cwd(),".env");return t&&t.path&&t.path.length>0&&(e=t.path),e.endsWith(".vault")?e:`${e}.vault`}function OYe(t){return t[0]==="~"?S_.join(bYe.homedir(),t.slice(1)):t}function LYe(t){RYe("Loading env from encrypted .env.vault");let e=js._parseVault(t),r=process.env;return t&&t.processEnv!=null&&(r=t.processEnv),js.populate(r,e,t),{parsed:e}}function MYe(t){let e=S_.resolve(process.cwd(),".env"),r="utf8",s=!!(t&&t.debug);t&&(t.path!=null&&(e=OYe(t.path)),t.encoding!=null&&(r=t.encoding));try{let a=js.parse(gne.readFileSync(e,{encoding:r})),n=process.env;return t&&t.processEnv!=null&&(n=t.processEnv),js.populate(n,a,t),{parsed:a}}catch(a){return s&&v_(`Failed to load ${e} ${a.message}`),{error:a}}}function UYe(t){let e=mne(t);return dne(t).length===0?js.configDotenv(t):gne.existsSync(e)?js._configVault(t):(FYe(`You set DOTENV_KEY but you are missing a .env.vault file at ${e}. Did you forget to build it?`),js.configDotenv(t))}function _Ye(t,e){let r=Buffer.from(e.slice(-64),"hex"),s=Buffer.from(t,"base64"),a=s.slice(0,12),n=s.slice(-16);s=s.slice(12,-16);try{let c=PYe.createDecipheriv("aes-256-gcm",r,a);return c.setAuthTag(n),`${c.update(s)}${c.final()}`}catch(c){let f=c instanceof RangeError,p=c.message==="Invalid key length",h=c.message==="Unsupported state or unable to authenticate data";if(f||p){let E="INVALID_DOTENV_KEY: It must be 64 characters long (or more)";throw new Error(E)}else if(h){let E="DECRYPTION_FAILED: Please check your DOTENV_KEY";throw new Error(E)}else throw console.error("Error: ",c.code),console.error("Error: ",c.message),c}}function HYe(t,e,r={}){let s=!!(r&&r.debug),a=!!(r&&r.override);if(typeof e!="object")throw new Error("OBJECT_REQUIRED: Please check the processEnv argument being passed to populate");for(let n of Object.keys(e))Object.prototype.hasOwnProperty.call(t,n)?(a===!0&&(t[n]=e[n]),s&&v_(a===!0?`"${n}" is already defined and WAS overwritten`:`"${n}" is already defined and was NOT overwritten`)):t[n]=e[n]}var js={configDotenv:MYe,_configVault:LYe,_parseVault:TYe,config:UYe,decrypt:_Ye,parse:QYe,populate:HYe};wp.exports.configDotenv=js.configDotenv;wp.exports._configVault=js._configVault;wp.exports._parseVault=js._parseVault;wp.exports.config=js.config;wp.exports.decrypt=js.decrypt;wp.exports.parse=js.parse;wp.exports.populate=js.populate;wp.exports=js});var Ine=_((KTt,Ene)=>{"use strict";Ene.exports=(t,...e)=>new Promise(r=>{r(t(...e))})});var Ld=_((zTt,b_)=>{"use strict";var jYe=Ine(),Cne=t=>{if(t<1)throw new TypeError("Expected `concurrency` to be a number from 1 and up");let e=[],r=0,s=()=>{r--,e.length>0&&e.shift()()},a=(f,p,...h)=>{r++;let E=jYe(f,...h);p(E),E.then(s,s)},n=(f,p,...h)=>{rnew Promise(h=>n(f,h,...p));return Object.defineProperties(c,{activeCount:{get:()=>r},pendingCount:{get:()=>e.length}}),c};b_.exports=Cne;b_.exports.default=Cne});function Yf(t){return`YN${t.toString(10).padStart(4,"0")}`}function jx(t){let e=Number(t.slice(2));if(typeof Br[e]>"u")throw new Error(`Unknown message name: "${t}"`);return e}var Br,Gx=Xe(()=>{Br=(Me=>(Me[Me.UNNAMED=0]="UNNAMED",Me[Me.EXCEPTION=1]="EXCEPTION",Me[Me.MISSING_PEER_DEPENDENCY=2]="MISSING_PEER_DEPENDENCY",Me[Me.CYCLIC_DEPENDENCIES=3]="CYCLIC_DEPENDENCIES",Me[Me.DISABLED_BUILD_SCRIPTS=4]="DISABLED_BUILD_SCRIPTS",Me[Me.BUILD_DISABLED=5]="BUILD_DISABLED",Me[Me.SOFT_LINK_BUILD=6]="SOFT_LINK_BUILD",Me[Me.MUST_BUILD=7]="MUST_BUILD",Me[Me.MUST_REBUILD=8]="MUST_REBUILD",Me[Me.BUILD_FAILED=9]="BUILD_FAILED",Me[Me.RESOLVER_NOT_FOUND=10]="RESOLVER_NOT_FOUND",Me[Me.FETCHER_NOT_FOUND=11]="FETCHER_NOT_FOUND",Me[Me.LINKER_NOT_FOUND=12]="LINKER_NOT_FOUND",Me[Me.FETCH_NOT_CACHED=13]="FETCH_NOT_CACHED",Me[Me.YARN_IMPORT_FAILED=14]="YARN_IMPORT_FAILED",Me[Me.REMOTE_INVALID=15]="REMOTE_INVALID",Me[Me.REMOTE_NOT_FOUND=16]="REMOTE_NOT_FOUND",Me[Me.RESOLUTION_PACK=17]="RESOLUTION_PACK",Me[Me.CACHE_CHECKSUM_MISMATCH=18]="CACHE_CHECKSUM_MISMATCH",Me[Me.UNUSED_CACHE_ENTRY=19]="UNUSED_CACHE_ENTRY",Me[Me.MISSING_LOCKFILE_ENTRY=20]="MISSING_LOCKFILE_ENTRY",Me[Me.WORKSPACE_NOT_FOUND=21]="WORKSPACE_NOT_FOUND",Me[Me.TOO_MANY_MATCHING_WORKSPACES=22]="TOO_MANY_MATCHING_WORKSPACES",Me[Me.CONSTRAINTS_MISSING_DEPENDENCY=23]="CONSTRAINTS_MISSING_DEPENDENCY",Me[Me.CONSTRAINTS_INCOMPATIBLE_DEPENDENCY=24]="CONSTRAINTS_INCOMPATIBLE_DEPENDENCY",Me[Me.CONSTRAINTS_EXTRANEOUS_DEPENDENCY=25]="CONSTRAINTS_EXTRANEOUS_DEPENDENCY",Me[Me.CONSTRAINTS_INVALID_DEPENDENCY=26]="CONSTRAINTS_INVALID_DEPENDENCY",Me[Me.CANT_SUGGEST_RESOLUTIONS=27]="CANT_SUGGEST_RESOLUTIONS",Me[Me.FROZEN_LOCKFILE_EXCEPTION=28]="FROZEN_LOCKFILE_EXCEPTION",Me[Me.CROSS_DRIVE_VIRTUAL_LOCAL=29]="CROSS_DRIVE_VIRTUAL_LOCAL",Me[Me.FETCH_FAILED=30]="FETCH_FAILED",Me[Me.DANGEROUS_NODE_MODULES=31]="DANGEROUS_NODE_MODULES",Me[Me.NODE_GYP_INJECTED=32]="NODE_GYP_INJECTED",Me[Me.AUTHENTICATION_NOT_FOUND=33]="AUTHENTICATION_NOT_FOUND",Me[Me.INVALID_CONFIGURATION_KEY=34]="INVALID_CONFIGURATION_KEY",Me[Me.NETWORK_ERROR=35]="NETWORK_ERROR",Me[Me.LIFECYCLE_SCRIPT=36]="LIFECYCLE_SCRIPT",Me[Me.CONSTRAINTS_MISSING_FIELD=37]="CONSTRAINTS_MISSING_FIELD",Me[Me.CONSTRAINTS_INCOMPATIBLE_FIELD=38]="CONSTRAINTS_INCOMPATIBLE_FIELD",Me[Me.CONSTRAINTS_EXTRANEOUS_FIELD=39]="CONSTRAINTS_EXTRANEOUS_FIELD",Me[Me.CONSTRAINTS_INVALID_FIELD=40]="CONSTRAINTS_INVALID_FIELD",Me[Me.AUTHENTICATION_INVALID=41]="AUTHENTICATION_INVALID",Me[Me.PROLOG_UNKNOWN_ERROR=42]="PROLOG_UNKNOWN_ERROR",Me[Me.PROLOG_SYNTAX_ERROR=43]="PROLOG_SYNTAX_ERROR",Me[Me.PROLOG_EXISTENCE_ERROR=44]="PROLOG_EXISTENCE_ERROR",Me[Me.STACK_OVERFLOW_RESOLUTION=45]="STACK_OVERFLOW_RESOLUTION",Me[Me.AUTOMERGE_FAILED_TO_PARSE=46]="AUTOMERGE_FAILED_TO_PARSE",Me[Me.AUTOMERGE_IMMUTABLE=47]="AUTOMERGE_IMMUTABLE",Me[Me.AUTOMERGE_SUCCESS=48]="AUTOMERGE_SUCCESS",Me[Me.AUTOMERGE_REQUIRED=49]="AUTOMERGE_REQUIRED",Me[Me.DEPRECATED_CLI_SETTINGS=50]="DEPRECATED_CLI_SETTINGS",Me[Me.PLUGIN_NAME_NOT_FOUND=51]="PLUGIN_NAME_NOT_FOUND",Me[Me.INVALID_PLUGIN_REFERENCE=52]="INVALID_PLUGIN_REFERENCE",Me[Me.CONSTRAINTS_AMBIGUITY=53]="CONSTRAINTS_AMBIGUITY",Me[Me.CACHE_OUTSIDE_PROJECT=54]="CACHE_OUTSIDE_PROJECT",Me[Me.IMMUTABLE_INSTALL=55]="IMMUTABLE_INSTALL",Me[Me.IMMUTABLE_CACHE=56]="IMMUTABLE_CACHE",Me[Me.INVALID_MANIFEST=57]="INVALID_MANIFEST",Me[Me.PACKAGE_PREPARATION_FAILED=58]="PACKAGE_PREPARATION_FAILED",Me[Me.INVALID_RANGE_PEER_DEPENDENCY=59]="INVALID_RANGE_PEER_DEPENDENCY",Me[Me.INCOMPATIBLE_PEER_DEPENDENCY=60]="INCOMPATIBLE_PEER_DEPENDENCY",Me[Me.DEPRECATED_PACKAGE=61]="DEPRECATED_PACKAGE",Me[Me.INCOMPATIBLE_OS=62]="INCOMPATIBLE_OS",Me[Me.INCOMPATIBLE_CPU=63]="INCOMPATIBLE_CPU",Me[Me.FROZEN_ARTIFACT_EXCEPTION=64]="FROZEN_ARTIFACT_EXCEPTION",Me[Me.TELEMETRY_NOTICE=65]="TELEMETRY_NOTICE",Me[Me.PATCH_HUNK_FAILED=66]="PATCH_HUNK_FAILED",Me[Me.INVALID_CONFIGURATION_VALUE=67]="INVALID_CONFIGURATION_VALUE",Me[Me.UNUSED_PACKAGE_EXTENSION=68]="UNUSED_PACKAGE_EXTENSION",Me[Me.REDUNDANT_PACKAGE_EXTENSION=69]="REDUNDANT_PACKAGE_EXTENSION",Me[Me.AUTO_NM_SUCCESS=70]="AUTO_NM_SUCCESS",Me[Me.NM_CANT_INSTALL_EXTERNAL_SOFT_LINK=71]="NM_CANT_INSTALL_EXTERNAL_SOFT_LINK",Me[Me.NM_PRESERVE_SYMLINKS_REQUIRED=72]="NM_PRESERVE_SYMLINKS_REQUIRED",Me[Me.UPDATE_LOCKFILE_ONLY_SKIP_LINK=73]="UPDATE_LOCKFILE_ONLY_SKIP_LINK",Me[Me.NM_HARDLINKS_MODE_DOWNGRADED=74]="NM_HARDLINKS_MODE_DOWNGRADED",Me[Me.PROLOG_INSTANTIATION_ERROR=75]="PROLOG_INSTANTIATION_ERROR",Me[Me.INCOMPATIBLE_ARCHITECTURE=76]="INCOMPATIBLE_ARCHITECTURE",Me[Me.GHOST_ARCHITECTURE=77]="GHOST_ARCHITECTURE",Me[Me.RESOLUTION_MISMATCH=78]="RESOLUTION_MISMATCH",Me[Me.PROLOG_LIMIT_EXCEEDED=79]="PROLOG_LIMIT_EXCEEDED",Me[Me.NETWORK_DISABLED=80]="NETWORK_DISABLED",Me[Me.NETWORK_UNSAFE_HTTP=81]="NETWORK_UNSAFE_HTTP",Me[Me.RESOLUTION_FAILED=82]="RESOLUTION_FAILED",Me[Me.AUTOMERGE_GIT_ERROR=83]="AUTOMERGE_GIT_ERROR",Me[Me.CONSTRAINTS_CHECK_FAILED=84]="CONSTRAINTS_CHECK_FAILED",Me[Me.UPDATED_RESOLUTION_RECORD=85]="UPDATED_RESOLUTION_RECORD",Me[Me.EXPLAIN_PEER_DEPENDENCIES_CTA=86]="EXPLAIN_PEER_DEPENDENCIES_CTA",Me[Me.MIGRATION_SUCCESS=87]="MIGRATION_SUCCESS",Me[Me.VERSION_NOTICE=88]="VERSION_NOTICE",Me[Me.TIPS_NOTICE=89]="TIPS_NOTICE",Me[Me.OFFLINE_MODE_ENABLED=90]="OFFLINE_MODE_ENABLED",Me[Me.INVALID_PROVENANCE_ENVIRONMENT=91]="INVALID_PROVENANCE_ENVIRONMENT",Me))(Br||{})});var aB=_((ZTt,wne)=>{var GYe="2.0.0",qYe=Number.MAX_SAFE_INTEGER||9007199254740991,WYe=16,YYe=250,VYe=["major","premajor","minor","preminor","patch","prepatch","prerelease"];wne.exports={MAX_LENGTH:256,MAX_SAFE_COMPONENT_LENGTH:WYe,MAX_SAFE_BUILD_LENGTH:YYe,MAX_SAFE_INTEGER:qYe,RELEASE_TYPES:VYe,SEMVER_SPEC_VERSION:GYe,FLAG_INCLUDE_PRERELEASE:1,FLAG_LOOSE:2}});var lB=_(($Tt,Bne)=>{var JYe=typeof process=="object"&&process.env&&process.env.NODE_DEBUG&&/\bsemver\b/i.test(process.env.NODE_DEBUG)?(...t)=>console.error("SEMVER",...t):()=>{};Bne.exports=JYe});var vE=_((Bp,vne)=>{var{MAX_SAFE_COMPONENT_LENGTH:P_,MAX_SAFE_BUILD_LENGTH:KYe,MAX_LENGTH:zYe}=aB(),XYe=lB();Bp=vne.exports={};var ZYe=Bp.re=[],$Ye=Bp.safeRe=[],rr=Bp.src=[],nr=Bp.t={},eVe=0,x_="[a-zA-Z0-9-]",tVe=[["\\s",1],["\\d",zYe],[x_,KYe]],rVe=t=>{for(let[e,r]of tVe)t=t.split(`${e}*`).join(`${e}{0,${r}}`).split(`${e}+`).join(`${e}{1,${r}}`);return t},Jr=(t,e,r)=>{let s=rVe(e),a=eVe++;XYe(t,a,e),nr[t]=a,rr[a]=e,ZYe[a]=new RegExp(e,r?"g":void 0),$Ye[a]=new RegExp(s,r?"g":void 0)};Jr("NUMERICIDENTIFIER","0|[1-9]\\d*");Jr("NUMERICIDENTIFIERLOOSE","\\d+");Jr("NONNUMERICIDENTIFIER",`\\d*[a-zA-Z-]${x_}*`);Jr("MAINVERSION",`(${rr[nr.NUMERICIDENTIFIER]})\\.(${rr[nr.NUMERICIDENTIFIER]})\\.(${rr[nr.NUMERICIDENTIFIER]})`);Jr("MAINVERSIONLOOSE",`(${rr[nr.NUMERICIDENTIFIERLOOSE]})\\.(${rr[nr.NUMERICIDENTIFIERLOOSE]})\\.(${rr[nr.NUMERICIDENTIFIERLOOSE]})`);Jr("PRERELEASEIDENTIFIER",`(?:${rr[nr.NUMERICIDENTIFIER]}|${rr[nr.NONNUMERICIDENTIFIER]})`);Jr("PRERELEASEIDENTIFIERLOOSE",`(?:${rr[nr.NUMERICIDENTIFIERLOOSE]}|${rr[nr.NONNUMERICIDENTIFIER]})`);Jr("PRERELEASE",`(?:-(${rr[nr.PRERELEASEIDENTIFIER]}(?:\\.${rr[nr.PRERELEASEIDENTIFIER]})*))`);Jr("PRERELEASELOOSE",`(?:-?(${rr[nr.PRERELEASEIDENTIFIERLOOSE]}(?:\\.${rr[nr.PRERELEASEIDENTIFIERLOOSE]})*))`);Jr("BUILDIDENTIFIER",`${x_}+`);Jr("BUILD",`(?:\\+(${rr[nr.BUILDIDENTIFIER]}(?:\\.${rr[nr.BUILDIDENTIFIER]})*))`);Jr("FULLPLAIN",`v?${rr[nr.MAINVERSION]}${rr[nr.PRERELEASE]}?${rr[nr.BUILD]}?`);Jr("FULL",`^${rr[nr.FULLPLAIN]}$`);Jr("LOOSEPLAIN",`[v=\\s]*${rr[nr.MAINVERSIONLOOSE]}${rr[nr.PRERELEASELOOSE]}?${rr[nr.BUILD]}?`);Jr("LOOSE",`^${rr[nr.LOOSEPLAIN]}$`);Jr("GTLT","((?:<|>)?=?)");Jr("XRANGEIDENTIFIERLOOSE",`${rr[nr.NUMERICIDENTIFIERLOOSE]}|x|X|\\*`);Jr("XRANGEIDENTIFIER",`${rr[nr.NUMERICIDENTIFIER]}|x|X|\\*`);Jr("XRANGEPLAIN",`[v=\\s]*(${rr[nr.XRANGEIDENTIFIER]})(?:\\.(${rr[nr.XRANGEIDENTIFIER]})(?:\\.(${rr[nr.XRANGEIDENTIFIER]})(?:${rr[nr.PRERELEASE]})?${rr[nr.BUILD]}?)?)?`);Jr("XRANGEPLAINLOOSE",`[v=\\s]*(${rr[nr.XRANGEIDENTIFIERLOOSE]})(?:\\.(${rr[nr.XRANGEIDENTIFIERLOOSE]})(?:\\.(${rr[nr.XRANGEIDENTIFIERLOOSE]})(?:${rr[nr.PRERELEASELOOSE]})?${rr[nr.BUILD]}?)?)?`);Jr("XRANGE",`^${rr[nr.GTLT]}\\s*${rr[nr.XRANGEPLAIN]}$`);Jr("XRANGELOOSE",`^${rr[nr.GTLT]}\\s*${rr[nr.XRANGEPLAINLOOSE]}$`);Jr("COERCEPLAIN",`(^|[^\\d])(\\d{1,${P_}})(?:\\.(\\d{1,${P_}}))?(?:\\.(\\d{1,${P_}}))?`);Jr("COERCE",`${rr[nr.COERCEPLAIN]}(?:$|[^\\d])`);Jr("COERCEFULL",rr[nr.COERCEPLAIN]+`(?:${rr[nr.PRERELEASE]})?(?:${rr[nr.BUILD]})?(?:$|[^\\d])`);Jr("COERCERTL",rr[nr.COERCE],!0);Jr("COERCERTLFULL",rr[nr.COERCEFULL],!0);Jr("LONETILDE","(?:~>?)");Jr("TILDETRIM",`(\\s*)${rr[nr.LONETILDE]}\\s+`,!0);Bp.tildeTrimReplace="$1~";Jr("TILDE",`^${rr[nr.LONETILDE]}${rr[nr.XRANGEPLAIN]}$`);Jr("TILDELOOSE",`^${rr[nr.LONETILDE]}${rr[nr.XRANGEPLAINLOOSE]}$`);Jr("LONECARET","(?:\\^)");Jr("CARETTRIM",`(\\s*)${rr[nr.LONECARET]}\\s+`,!0);Bp.caretTrimReplace="$1^";Jr("CARET",`^${rr[nr.LONECARET]}${rr[nr.XRANGEPLAIN]}$`);Jr("CARETLOOSE",`^${rr[nr.LONECARET]}${rr[nr.XRANGEPLAINLOOSE]}$`);Jr("COMPARATORLOOSE",`^${rr[nr.GTLT]}\\s*(${rr[nr.LOOSEPLAIN]})$|^$`);Jr("COMPARATOR",`^${rr[nr.GTLT]}\\s*(${rr[nr.FULLPLAIN]})$|^$`);Jr("COMPARATORTRIM",`(\\s*)${rr[nr.GTLT]}\\s*(${rr[nr.LOOSEPLAIN]}|${rr[nr.XRANGEPLAIN]})`,!0);Bp.comparatorTrimReplace="$1$2$3";Jr("HYPHENRANGE",`^\\s*(${rr[nr.XRANGEPLAIN]})\\s+-\\s+(${rr[nr.XRANGEPLAIN]})\\s*$`);Jr("HYPHENRANGELOOSE",`^\\s*(${rr[nr.XRANGEPLAINLOOSE]})\\s+-\\s+(${rr[nr.XRANGEPLAINLOOSE]})\\s*$`);Jr("STAR","(<|>)?=?\\s*\\*");Jr("GTE0","^\\s*>=\\s*0\\.0\\.0\\s*$");Jr("GTE0PRE","^\\s*>=\\s*0\\.0\\.0-0\\s*$")});var qx=_((eRt,Sne)=>{var nVe=Object.freeze({loose:!0}),iVe=Object.freeze({}),sVe=t=>t?typeof t!="object"?nVe:t:iVe;Sne.exports=sVe});var k_=_((tRt,Pne)=>{var Dne=/^[0-9]+$/,bne=(t,e)=>{let r=Dne.test(t),s=Dne.test(e);return r&&s&&(t=+t,e=+e),t===e?0:r&&!s?-1:s&&!r?1:tbne(e,t);Pne.exports={compareIdentifiers:bne,rcompareIdentifiers:oVe}});var jo=_((rRt,Tne)=>{var Wx=lB(),{MAX_LENGTH:xne,MAX_SAFE_INTEGER:Yx}=aB(),{safeRe:kne,t:Qne}=vE(),aVe=qx(),{compareIdentifiers:SE}=k_(),Q_=class t{constructor(e,r){if(r=aVe(r),e instanceof t){if(e.loose===!!r.loose&&e.includePrerelease===!!r.includePrerelease)return e;e=e.version}else if(typeof e!="string")throw new TypeError(`Invalid version. Must be a string. Got type "${typeof e}".`);if(e.length>xne)throw new TypeError(`version is longer than ${xne} characters`);Wx("SemVer",e,r),this.options=r,this.loose=!!r.loose,this.includePrerelease=!!r.includePrerelease;let s=e.trim().match(r.loose?kne[Qne.LOOSE]:kne[Qne.FULL]);if(!s)throw new TypeError(`Invalid Version: ${e}`);if(this.raw=e,this.major=+s[1],this.minor=+s[2],this.patch=+s[3],this.major>Yx||this.major<0)throw new TypeError("Invalid major version");if(this.minor>Yx||this.minor<0)throw new TypeError("Invalid minor version");if(this.patch>Yx||this.patch<0)throw new TypeError("Invalid patch version");s[4]?this.prerelease=s[4].split(".").map(a=>{if(/^[0-9]+$/.test(a)){let n=+a;if(n>=0&&n=0;)typeof this.prerelease[n]=="number"&&(this.prerelease[n]++,n=-2);if(n===-1){if(r===this.prerelease.join(".")&&s===!1)throw new Error("invalid increment argument: identifier already exists");this.prerelease.push(a)}}if(r){let n=[r,a];s===!1&&(n=[r]),SE(this.prerelease[0],r)===0?isNaN(this.prerelease[1])&&(this.prerelease=n):this.prerelease=n}break}default:throw new Error(`invalid increment argument: ${e}`)}return this.raw=this.format(),this.build.length&&(this.raw+=`+${this.build.join(".")}`),this}};Tne.exports=Q_});var Md=_((nRt,Fne)=>{var Rne=jo(),lVe=(t,e,r=!1)=>{if(t instanceof Rne)return t;try{return new Rne(t,e)}catch(s){if(!r)return null;throw s}};Fne.exports=lVe});var One=_((iRt,Nne)=>{var cVe=Md(),uVe=(t,e)=>{let r=cVe(t,e);return r?r.version:null};Nne.exports=uVe});var Mne=_((sRt,Lne)=>{var fVe=Md(),AVe=(t,e)=>{let r=fVe(t.trim().replace(/^[=v]+/,""),e);return r?r.version:null};Lne.exports=AVe});var Hne=_((oRt,_ne)=>{var Une=jo(),pVe=(t,e,r,s,a)=>{typeof r=="string"&&(a=s,s=r,r=void 0);try{return new Une(t instanceof Une?t.version:t,r).inc(e,s,a).version}catch{return null}};_ne.exports=pVe});var qne=_((aRt,Gne)=>{var jne=Md(),hVe=(t,e)=>{let r=jne(t,null,!0),s=jne(e,null,!0),a=r.compare(s);if(a===0)return null;let n=a>0,c=n?r:s,f=n?s:r,p=!!c.prerelease.length;if(!!f.prerelease.length&&!p)return!f.patch&&!f.minor?"major":c.patch?"patch":c.minor?"minor":"major";let E=p?"pre":"";return r.major!==s.major?E+"major":r.minor!==s.minor?E+"minor":r.patch!==s.patch?E+"patch":"prerelease"};Gne.exports=hVe});var Yne=_((lRt,Wne)=>{var gVe=jo(),dVe=(t,e)=>new gVe(t,e).major;Wne.exports=dVe});var Jne=_((cRt,Vne)=>{var mVe=jo(),yVe=(t,e)=>new mVe(t,e).minor;Vne.exports=yVe});var zne=_((uRt,Kne)=>{var EVe=jo(),IVe=(t,e)=>new EVe(t,e).patch;Kne.exports=IVe});var Zne=_((fRt,Xne)=>{var CVe=Md(),wVe=(t,e)=>{let r=CVe(t,e);return r&&r.prerelease.length?r.prerelease:null};Xne.exports=wVe});var Bc=_((ARt,eie)=>{var $ne=jo(),BVe=(t,e,r)=>new $ne(t,r).compare(new $ne(e,r));eie.exports=BVe});var rie=_((pRt,tie)=>{var vVe=Bc(),SVe=(t,e,r)=>vVe(e,t,r);tie.exports=SVe});var iie=_((hRt,nie)=>{var DVe=Bc(),bVe=(t,e)=>DVe(t,e,!0);nie.exports=bVe});var Vx=_((gRt,oie)=>{var sie=jo(),PVe=(t,e,r)=>{let s=new sie(t,r),a=new sie(e,r);return s.compare(a)||s.compareBuild(a)};oie.exports=PVe});var lie=_((dRt,aie)=>{var xVe=Vx(),kVe=(t,e)=>t.sort((r,s)=>xVe(r,s,e));aie.exports=kVe});var uie=_((mRt,cie)=>{var QVe=Vx(),TVe=(t,e)=>t.sort((r,s)=>QVe(s,r,e));cie.exports=TVe});var cB=_((yRt,fie)=>{var RVe=Bc(),FVe=(t,e,r)=>RVe(t,e,r)>0;fie.exports=FVe});var Jx=_((ERt,Aie)=>{var NVe=Bc(),OVe=(t,e,r)=>NVe(t,e,r)<0;Aie.exports=OVe});var T_=_((IRt,pie)=>{var LVe=Bc(),MVe=(t,e,r)=>LVe(t,e,r)===0;pie.exports=MVe});var R_=_((CRt,hie)=>{var UVe=Bc(),_Ve=(t,e,r)=>UVe(t,e,r)!==0;hie.exports=_Ve});var Kx=_((wRt,gie)=>{var HVe=Bc(),jVe=(t,e,r)=>HVe(t,e,r)>=0;gie.exports=jVe});var zx=_((BRt,die)=>{var GVe=Bc(),qVe=(t,e,r)=>GVe(t,e,r)<=0;die.exports=qVe});var F_=_((vRt,mie)=>{var WVe=T_(),YVe=R_(),VVe=cB(),JVe=Kx(),KVe=Jx(),zVe=zx(),XVe=(t,e,r,s)=>{switch(e){case"===":return typeof t=="object"&&(t=t.version),typeof r=="object"&&(r=r.version),t===r;case"!==":return typeof t=="object"&&(t=t.version),typeof r=="object"&&(r=r.version),t!==r;case"":case"=":case"==":return WVe(t,r,s);case"!=":return YVe(t,r,s);case">":return VVe(t,r,s);case">=":return JVe(t,r,s);case"<":return KVe(t,r,s);case"<=":return zVe(t,r,s);default:throw new TypeError(`Invalid operator: ${e}`)}};mie.exports=XVe});var Eie=_((SRt,yie)=>{var ZVe=jo(),$Ve=Md(),{safeRe:Xx,t:Zx}=vE(),e7e=(t,e)=>{if(t instanceof ZVe)return t;if(typeof t=="number"&&(t=String(t)),typeof t!="string")return null;e=e||{};let r=null;if(!e.rtl)r=t.match(e.includePrerelease?Xx[Zx.COERCEFULL]:Xx[Zx.COERCE]);else{let p=e.includePrerelease?Xx[Zx.COERCERTLFULL]:Xx[Zx.COERCERTL],h;for(;(h=p.exec(t))&&(!r||r.index+r[0].length!==t.length);)(!r||h.index+h[0].length!==r.index+r[0].length)&&(r=h),p.lastIndex=h.index+h[1].length+h[2].length;p.lastIndex=-1}if(r===null)return null;let s=r[2],a=r[3]||"0",n=r[4]||"0",c=e.includePrerelease&&r[5]?`-${r[5]}`:"",f=e.includePrerelease&&r[6]?`+${r[6]}`:"";return $Ve(`${s}.${a}.${n}${c}${f}`,e)};yie.exports=e7e});var Cie=_((DRt,Iie)=>{"use strict";Iie.exports=function(t){t.prototype[Symbol.iterator]=function*(){for(let e=this.head;e;e=e.next)yield e.value}}});var $x=_((bRt,wie)=>{"use strict";wie.exports=Fn;Fn.Node=Ud;Fn.create=Fn;function Fn(t){var e=this;if(e instanceof Fn||(e=new Fn),e.tail=null,e.head=null,e.length=0,t&&typeof t.forEach=="function")t.forEach(function(a){e.push(a)});else if(arguments.length>0)for(var r=0,s=arguments.length;r1)r=e;else if(this.head)s=this.head.next,r=this.head.value;else throw new TypeError("Reduce of empty list with no initial value");for(var a=0;s!==null;a++)r=t(r,s.value,a),s=s.next;return r};Fn.prototype.reduceReverse=function(t,e){var r,s=this.tail;if(arguments.length>1)r=e;else if(this.tail)s=this.tail.prev,r=this.tail.value;else throw new TypeError("Reduce of empty list with no initial value");for(var a=this.length-1;s!==null;a--)r=t(r,s.value,a),s=s.prev;return r};Fn.prototype.toArray=function(){for(var t=new Array(this.length),e=0,r=this.head;r!==null;e++)t[e]=r.value,r=r.next;return t};Fn.prototype.toArrayReverse=function(){for(var t=new Array(this.length),e=0,r=this.tail;r!==null;e++)t[e]=r.value,r=r.prev;return t};Fn.prototype.slice=function(t,e){e=e||this.length,e<0&&(e+=this.length),t=t||0,t<0&&(t+=this.length);var r=new Fn;if(ethis.length&&(e=this.length);for(var s=0,a=this.head;a!==null&&sthis.length&&(e=this.length);for(var s=this.length,a=this.tail;a!==null&&s>e;s--)a=a.prev;for(;a!==null&&s>t;s--,a=a.prev)r.push(a.value);return r};Fn.prototype.splice=function(t,e,...r){t>this.length&&(t=this.length-1),t<0&&(t=this.length+t);for(var s=0,a=this.head;a!==null&&s{"use strict";var i7e=$x(),_d=Symbol("max"),Sp=Symbol("length"),DE=Symbol("lengthCalculator"),fB=Symbol("allowStale"),Hd=Symbol("maxAge"),vp=Symbol("dispose"),Bie=Symbol("noDisposeOnSet"),Gs=Symbol("lruList"),Lu=Symbol("cache"),Sie=Symbol("updateAgeOnGet"),N_=()=>1,L_=class{constructor(e){if(typeof e=="number"&&(e={max:e}),e||(e={}),e.max&&(typeof e.max!="number"||e.max<0))throw new TypeError("max must be a non-negative number");let r=this[_d]=e.max||1/0,s=e.length||N_;if(this[DE]=typeof s!="function"?N_:s,this[fB]=e.stale||!1,e.maxAge&&typeof e.maxAge!="number")throw new TypeError("maxAge must be a number");this[Hd]=e.maxAge||0,this[vp]=e.dispose,this[Bie]=e.noDisposeOnSet||!1,this[Sie]=e.updateAgeOnGet||!1,this.reset()}set max(e){if(typeof e!="number"||e<0)throw new TypeError("max must be a non-negative number");this[_d]=e||1/0,uB(this)}get max(){return this[_d]}set allowStale(e){this[fB]=!!e}get allowStale(){return this[fB]}set maxAge(e){if(typeof e!="number")throw new TypeError("maxAge must be a non-negative number");this[Hd]=e,uB(this)}get maxAge(){return this[Hd]}set lengthCalculator(e){typeof e!="function"&&(e=N_),e!==this[DE]&&(this[DE]=e,this[Sp]=0,this[Gs].forEach(r=>{r.length=this[DE](r.value,r.key),this[Sp]+=r.length})),uB(this)}get lengthCalculator(){return this[DE]}get length(){return this[Sp]}get itemCount(){return this[Gs].length}rforEach(e,r){r=r||this;for(let s=this[Gs].tail;s!==null;){let a=s.prev;vie(this,e,s,r),s=a}}forEach(e,r){r=r||this;for(let s=this[Gs].head;s!==null;){let a=s.next;vie(this,e,s,r),s=a}}keys(){return this[Gs].toArray().map(e=>e.key)}values(){return this[Gs].toArray().map(e=>e.value)}reset(){this[vp]&&this[Gs]&&this[Gs].length&&this[Gs].forEach(e=>this[vp](e.key,e.value)),this[Lu]=new Map,this[Gs]=new i7e,this[Sp]=0}dump(){return this[Gs].map(e=>ek(this,e)?!1:{k:e.key,v:e.value,e:e.now+(e.maxAge||0)}).toArray().filter(e=>e)}dumpLru(){return this[Gs]}set(e,r,s){if(s=s||this[Hd],s&&typeof s!="number")throw new TypeError("maxAge must be a number");let a=s?Date.now():0,n=this[DE](r,e);if(this[Lu].has(e)){if(n>this[_d])return bE(this,this[Lu].get(e)),!1;let p=this[Lu].get(e).value;return this[vp]&&(this[Bie]||this[vp](e,p.value)),p.now=a,p.maxAge=s,p.value=r,this[Sp]+=n-p.length,p.length=n,this.get(e),uB(this),!0}let c=new M_(e,r,n,a,s);return c.length>this[_d]?(this[vp]&&this[vp](e,r),!1):(this[Sp]+=c.length,this[Gs].unshift(c),this[Lu].set(e,this[Gs].head),uB(this),!0)}has(e){if(!this[Lu].has(e))return!1;let r=this[Lu].get(e).value;return!ek(this,r)}get(e){return O_(this,e,!0)}peek(e){return O_(this,e,!1)}pop(){let e=this[Gs].tail;return e?(bE(this,e),e.value):null}del(e){bE(this,this[Lu].get(e))}load(e){this.reset();let r=Date.now();for(let s=e.length-1;s>=0;s--){let a=e[s],n=a.e||0;if(n===0)this.set(a.k,a.v);else{let c=n-r;c>0&&this.set(a.k,a.v,c)}}}prune(){this[Lu].forEach((e,r)=>O_(this,r,!1))}},O_=(t,e,r)=>{let s=t[Lu].get(e);if(s){let a=s.value;if(ek(t,a)){if(bE(t,s),!t[fB])return}else r&&(t[Sie]&&(s.value.now=Date.now()),t[Gs].unshiftNode(s));return a.value}},ek=(t,e)=>{if(!e||!e.maxAge&&!t[Hd])return!1;let r=Date.now()-e.now;return e.maxAge?r>e.maxAge:t[Hd]&&r>t[Hd]},uB=t=>{if(t[Sp]>t[_d])for(let e=t[Gs].tail;t[Sp]>t[_d]&&e!==null;){let r=e.prev;bE(t,e),e=r}},bE=(t,e)=>{if(e){let r=e.value;t[vp]&&t[vp](r.key,r.value),t[Sp]-=r.length,t[Lu].delete(r.key),t[Gs].removeNode(e)}},M_=class{constructor(e,r,s,a,n){this.key=e,this.value=r,this.length=s,this.now=a,this.maxAge=n||0}},vie=(t,e,r,s)=>{let a=r.value;ek(t,a)&&(bE(t,r),t[fB]||(a=void 0)),a&&e.call(s,a.value,a.key,t)};Die.exports=L_});var vc=_((xRt,Qie)=>{var U_=class t{constructor(e,r){if(r=o7e(r),e instanceof t)return e.loose===!!r.loose&&e.includePrerelease===!!r.includePrerelease?e:new t(e.raw,r);if(e instanceof __)return this.raw=e.value,this.set=[[e]],this.format(),this;if(this.options=r,this.loose=!!r.loose,this.includePrerelease=!!r.includePrerelease,this.raw=e.trim().split(/\s+/).join(" "),this.set=this.raw.split("||").map(s=>this.parseRange(s.trim())).filter(s=>s.length),!this.set.length)throw new TypeError(`Invalid SemVer Range: ${this.raw}`);if(this.set.length>1){let s=this.set[0];if(this.set=this.set.filter(a=>!xie(a[0])),this.set.length===0)this.set=[s];else if(this.set.length>1){for(let a of this.set)if(a.length===1&&p7e(a[0])){this.set=[a];break}}}this.format()}format(){return this.range=this.set.map(e=>e.join(" ").trim()).join("||").trim(),this.range}toString(){return this.range}parseRange(e){let s=((this.options.includePrerelease&&f7e)|(this.options.loose&&A7e))+":"+e,a=Pie.get(s);if(a)return a;let n=this.options.loose,c=n?sl[wa.HYPHENRANGELOOSE]:sl[wa.HYPHENRANGE];e=e.replace(c,B7e(this.options.includePrerelease)),vi("hyphen replace",e),e=e.replace(sl[wa.COMPARATORTRIM],l7e),vi("comparator trim",e),e=e.replace(sl[wa.TILDETRIM],c7e),vi("tilde trim",e),e=e.replace(sl[wa.CARETTRIM],u7e),vi("caret trim",e);let f=e.split(" ").map(C=>h7e(C,this.options)).join(" ").split(/\s+/).map(C=>w7e(C,this.options));n&&(f=f.filter(C=>(vi("loose invalid filter",C,this.options),!!C.match(sl[wa.COMPARATORLOOSE])))),vi("range list",f);let p=new Map,h=f.map(C=>new __(C,this.options));for(let C of h){if(xie(C))return[C];p.set(C.value,C)}p.size>1&&p.has("")&&p.delete("");let E=[...p.values()];return Pie.set(s,E),E}intersects(e,r){if(!(e instanceof t))throw new TypeError("a Range is required");return this.set.some(s=>kie(s,r)&&e.set.some(a=>kie(a,r)&&s.every(n=>a.every(c=>n.intersects(c,r)))))}test(e){if(!e)return!1;if(typeof e=="string")try{e=new a7e(e,this.options)}catch{return!1}for(let r=0;rt.value==="<0.0.0-0",p7e=t=>t.value==="",kie=(t,e)=>{let r=!0,s=t.slice(),a=s.pop();for(;r&&s.length;)r=s.every(n=>a.intersects(n,e)),a=s.pop();return r},h7e=(t,e)=>(vi("comp",t,e),t=m7e(t,e),vi("caret",t),t=g7e(t,e),vi("tildes",t),t=E7e(t,e),vi("xrange",t),t=C7e(t,e),vi("stars",t),t),Ba=t=>!t||t.toLowerCase()==="x"||t==="*",g7e=(t,e)=>t.trim().split(/\s+/).map(r=>d7e(r,e)).join(" "),d7e=(t,e)=>{let r=e.loose?sl[wa.TILDELOOSE]:sl[wa.TILDE];return t.replace(r,(s,a,n,c,f)=>{vi("tilde",t,s,a,n,c,f);let p;return Ba(a)?p="":Ba(n)?p=`>=${a}.0.0 <${+a+1}.0.0-0`:Ba(c)?p=`>=${a}.${n}.0 <${a}.${+n+1}.0-0`:f?(vi("replaceTilde pr",f),p=`>=${a}.${n}.${c}-${f} <${a}.${+n+1}.0-0`):p=`>=${a}.${n}.${c} <${a}.${+n+1}.0-0`,vi("tilde return",p),p})},m7e=(t,e)=>t.trim().split(/\s+/).map(r=>y7e(r,e)).join(" "),y7e=(t,e)=>{vi("caret",t,e);let r=e.loose?sl[wa.CARETLOOSE]:sl[wa.CARET],s=e.includePrerelease?"-0":"";return t.replace(r,(a,n,c,f,p)=>{vi("caret",t,a,n,c,f,p);let h;return Ba(n)?h="":Ba(c)?h=`>=${n}.0.0${s} <${+n+1}.0.0-0`:Ba(f)?n==="0"?h=`>=${n}.${c}.0${s} <${n}.${+c+1}.0-0`:h=`>=${n}.${c}.0${s} <${+n+1}.0.0-0`:p?(vi("replaceCaret pr",p),n==="0"?c==="0"?h=`>=${n}.${c}.${f}-${p} <${n}.${c}.${+f+1}-0`:h=`>=${n}.${c}.${f}-${p} <${n}.${+c+1}.0-0`:h=`>=${n}.${c}.${f}-${p} <${+n+1}.0.0-0`):(vi("no pr"),n==="0"?c==="0"?h=`>=${n}.${c}.${f}${s} <${n}.${c}.${+f+1}-0`:h=`>=${n}.${c}.${f}${s} <${n}.${+c+1}.0-0`:h=`>=${n}.${c}.${f} <${+n+1}.0.0-0`),vi("caret return",h),h})},E7e=(t,e)=>(vi("replaceXRanges",t,e),t.split(/\s+/).map(r=>I7e(r,e)).join(" ")),I7e=(t,e)=>{t=t.trim();let r=e.loose?sl[wa.XRANGELOOSE]:sl[wa.XRANGE];return t.replace(r,(s,a,n,c,f,p)=>{vi("xRange",t,s,a,n,c,f,p);let h=Ba(n),E=h||Ba(c),C=E||Ba(f),S=C;return a==="="&&S&&(a=""),p=e.includePrerelease?"-0":"",h?a===">"||a==="<"?s="<0.0.0-0":s="*":a&&S?(E&&(c=0),f=0,a===">"?(a=">=",E?(n=+n+1,c=0,f=0):(c=+c+1,f=0)):a==="<="&&(a="<",E?n=+n+1:c=+c+1),a==="<"&&(p="-0"),s=`${a+n}.${c}.${f}${p}`):E?s=`>=${n}.0.0${p} <${+n+1}.0.0-0`:C&&(s=`>=${n}.${c}.0${p} <${n}.${+c+1}.0-0`),vi("xRange return",s),s})},C7e=(t,e)=>(vi("replaceStars",t,e),t.trim().replace(sl[wa.STAR],"")),w7e=(t,e)=>(vi("replaceGTE0",t,e),t.trim().replace(sl[e.includePrerelease?wa.GTE0PRE:wa.GTE0],"")),B7e=t=>(e,r,s,a,n,c,f,p,h,E,C,S,P)=>(Ba(s)?r="":Ba(a)?r=`>=${s}.0.0${t?"-0":""}`:Ba(n)?r=`>=${s}.${a}.0${t?"-0":""}`:c?r=`>=${r}`:r=`>=${r}${t?"-0":""}`,Ba(h)?p="":Ba(E)?p=`<${+h+1}.0.0-0`:Ba(C)?p=`<${h}.${+E+1}.0-0`:S?p=`<=${h}.${E}.${C}-${S}`:t?p=`<${h}.${E}.${+C+1}-0`:p=`<=${p}`,`${r} ${p}`.trim()),v7e=(t,e,r)=>{for(let s=0;s0){let a=t[s].semver;if(a.major===e.major&&a.minor===e.minor&&a.patch===e.patch)return!0}return!1}return!0}});var AB=_((kRt,Lie)=>{var pB=Symbol("SemVer ANY"),G_=class t{static get ANY(){return pB}constructor(e,r){if(r=Tie(r),e instanceof t){if(e.loose===!!r.loose)return e;e=e.value}e=e.trim().split(/\s+/).join(" "),j_("comparator",e,r),this.options=r,this.loose=!!r.loose,this.parse(e),this.semver===pB?this.value="":this.value=this.operator+this.semver.version,j_("comp",this)}parse(e){let r=this.options.loose?Rie[Fie.COMPARATORLOOSE]:Rie[Fie.COMPARATOR],s=e.match(r);if(!s)throw new TypeError(`Invalid comparator: ${e}`);this.operator=s[1]!==void 0?s[1]:"",this.operator==="="&&(this.operator=""),s[2]?this.semver=new Nie(s[2],this.options.loose):this.semver=pB}toString(){return this.value}test(e){if(j_("Comparator.test",e,this.options.loose),this.semver===pB||e===pB)return!0;if(typeof e=="string")try{e=new Nie(e,this.options)}catch{return!1}return H_(e,this.operator,this.semver,this.options)}intersects(e,r){if(!(e instanceof t))throw new TypeError("a Comparator is required");return this.operator===""?this.value===""?!0:new Oie(e.value,r).test(this.value):e.operator===""?e.value===""?!0:new Oie(this.value,r).test(e.semver):(r=Tie(r),r.includePrerelease&&(this.value==="<0.0.0-0"||e.value==="<0.0.0-0")||!r.includePrerelease&&(this.value.startsWith("<0.0.0")||e.value.startsWith("<0.0.0"))?!1:!!(this.operator.startsWith(">")&&e.operator.startsWith(">")||this.operator.startsWith("<")&&e.operator.startsWith("<")||this.semver.version===e.semver.version&&this.operator.includes("=")&&e.operator.includes("=")||H_(this.semver,"<",e.semver,r)&&this.operator.startsWith(">")&&e.operator.startsWith("<")||H_(this.semver,">",e.semver,r)&&this.operator.startsWith("<")&&e.operator.startsWith(">")))}};Lie.exports=G_;var Tie=qx(),{safeRe:Rie,t:Fie}=vE(),H_=F_(),j_=lB(),Nie=jo(),Oie=vc()});var hB=_((QRt,Mie)=>{var S7e=vc(),D7e=(t,e,r)=>{try{e=new S7e(e,r)}catch{return!1}return e.test(t)};Mie.exports=D7e});var _ie=_((TRt,Uie)=>{var b7e=vc(),P7e=(t,e)=>new b7e(t,e).set.map(r=>r.map(s=>s.value).join(" ").trim().split(" "));Uie.exports=P7e});var jie=_((RRt,Hie)=>{var x7e=jo(),k7e=vc(),Q7e=(t,e,r)=>{let s=null,a=null,n=null;try{n=new k7e(e,r)}catch{return null}return t.forEach(c=>{n.test(c)&&(!s||a.compare(c)===-1)&&(s=c,a=new x7e(s,r))}),s};Hie.exports=Q7e});var qie=_((FRt,Gie)=>{var T7e=jo(),R7e=vc(),F7e=(t,e,r)=>{let s=null,a=null,n=null;try{n=new R7e(e,r)}catch{return null}return t.forEach(c=>{n.test(c)&&(!s||a.compare(c)===1)&&(s=c,a=new T7e(s,r))}),s};Gie.exports=F7e});var Vie=_((NRt,Yie)=>{var q_=jo(),N7e=vc(),Wie=cB(),O7e=(t,e)=>{t=new N7e(t,e);let r=new q_("0.0.0");if(t.test(r)||(r=new q_("0.0.0-0"),t.test(r)))return r;r=null;for(let s=0;s{let f=new q_(c.semver.version);switch(c.operator){case">":f.prerelease.length===0?f.patch++:f.prerelease.push(0),f.raw=f.format();case"":case">=":(!n||Wie(f,n))&&(n=f);break;case"<":case"<=":break;default:throw new Error(`Unexpected operation: ${c.operator}`)}}),n&&(!r||Wie(r,n))&&(r=n)}return r&&t.test(r)?r:null};Yie.exports=O7e});var Kie=_((ORt,Jie)=>{var L7e=vc(),M7e=(t,e)=>{try{return new L7e(t,e).range||"*"}catch{return null}};Jie.exports=M7e});var tk=_((LRt,$ie)=>{var U7e=jo(),Zie=AB(),{ANY:_7e}=Zie,H7e=vc(),j7e=hB(),zie=cB(),Xie=Jx(),G7e=zx(),q7e=Kx(),W7e=(t,e,r,s)=>{t=new U7e(t,s),e=new H7e(e,s);let a,n,c,f,p;switch(r){case">":a=zie,n=G7e,c=Xie,f=">",p=">=";break;case"<":a=Xie,n=q7e,c=zie,f="<",p="<=";break;default:throw new TypeError('Must provide a hilo val of "<" or ">"')}if(j7e(t,e,s))return!1;for(let h=0;h{P.semver===_7e&&(P=new Zie(">=0.0.0")),C=C||P,S=S||P,a(P.semver,C.semver,s)?C=P:c(P.semver,S.semver,s)&&(S=P)}),C.operator===f||C.operator===p||(!S.operator||S.operator===f)&&n(t,S.semver))return!1;if(S.operator===p&&c(t,S.semver))return!1}return!0};$ie.exports=W7e});var tse=_((MRt,ese)=>{var Y7e=tk(),V7e=(t,e,r)=>Y7e(t,e,">",r);ese.exports=V7e});var nse=_((URt,rse)=>{var J7e=tk(),K7e=(t,e,r)=>J7e(t,e,"<",r);rse.exports=K7e});var ose=_((_Rt,sse)=>{var ise=vc(),z7e=(t,e,r)=>(t=new ise(t,r),e=new ise(e,r),t.intersects(e,r));sse.exports=z7e});var lse=_((HRt,ase)=>{var X7e=hB(),Z7e=Bc();ase.exports=(t,e,r)=>{let s=[],a=null,n=null,c=t.sort((E,C)=>Z7e(E,C,r));for(let E of c)X7e(E,e,r)?(n=E,a||(a=E)):(n&&s.push([a,n]),n=null,a=null);a&&s.push([a,null]);let f=[];for(let[E,C]of s)E===C?f.push(E):!C&&E===c[0]?f.push("*"):C?E===c[0]?f.push(`<=${C}`):f.push(`${E} - ${C}`):f.push(`>=${E}`);let p=f.join(" || "),h=typeof e.raw=="string"?e.raw:String(e);return p.length{var cse=vc(),Y_=AB(),{ANY:W_}=Y_,gB=hB(),V_=Bc(),$7e=(t,e,r={})=>{if(t===e)return!0;t=new cse(t,r),e=new cse(e,r);let s=!1;e:for(let a of t.set){for(let n of e.set){let c=tJe(a,n,r);if(s=s||c!==null,c)continue e}if(s)return!1}return!0},eJe=[new Y_(">=0.0.0-0")],use=[new Y_(">=0.0.0")],tJe=(t,e,r)=>{if(t===e)return!0;if(t.length===1&&t[0].semver===W_){if(e.length===1&&e[0].semver===W_)return!0;r.includePrerelease?t=eJe:t=use}if(e.length===1&&e[0].semver===W_){if(r.includePrerelease)return!0;e=use}let s=new Set,a,n;for(let P of t)P.operator===">"||P.operator===">="?a=fse(a,P,r):P.operator==="<"||P.operator==="<="?n=Ase(n,P,r):s.add(P.semver);if(s.size>1)return null;let c;if(a&&n){if(c=V_(a.semver,n.semver,r),c>0)return null;if(c===0&&(a.operator!==">="||n.operator!=="<="))return null}for(let P of s){if(a&&!gB(P,String(a),r)||n&&!gB(P,String(n),r))return null;for(let I of e)if(!gB(P,String(I),r))return!1;return!0}let f,p,h,E,C=n&&!r.includePrerelease&&n.semver.prerelease.length?n.semver:!1,S=a&&!r.includePrerelease&&a.semver.prerelease.length?a.semver:!1;C&&C.prerelease.length===1&&n.operator==="<"&&C.prerelease[0]===0&&(C=!1);for(let P of e){if(E=E||P.operator===">"||P.operator===">=",h=h||P.operator==="<"||P.operator==="<=",a){if(S&&P.semver.prerelease&&P.semver.prerelease.length&&P.semver.major===S.major&&P.semver.minor===S.minor&&P.semver.patch===S.patch&&(S=!1),P.operator===">"||P.operator===">="){if(f=fse(a,P,r),f===P&&f!==a)return!1}else if(a.operator===">="&&!gB(a.semver,String(P),r))return!1}if(n){if(C&&P.semver.prerelease&&P.semver.prerelease.length&&P.semver.major===C.major&&P.semver.minor===C.minor&&P.semver.patch===C.patch&&(C=!1),P.operator==="<"||P.operator==="<="){if(p=Ase(n,P,r),p===P&&p!==n)return!1}else if(n.operator==="<="&&!gB(n.semver,String(P),r))return!1}if(!P.operator&&(n||a)&&c!==0)return!1}return!(a&&h&&!n&&c!==0||n&&E&&!a&&c!==0||S||C)},fse=(t,e,r)=>{if(!t)return e;let s=V_(t.semver,e.semver,r);return s>0?t:s<0||e.operator===">"&&t.operator===">="?e:t},Ase=(t,e,r)=>{if(!t)return e;let s=V_(t.semver,e.semver,r);return s<0?t:s>0||e.operator==="<"&&t.operator==="<="?e:t};pse.exports=$7e});var Ai=_((GRt,mse)=>{var J_=vE(),gse=aB(),rJe=jo(),dse=k_(),nJe=Md(),iJe=One(),sJe=Mne(),oJe=Hne(),aJe=qne(),lJe=Yne(),cJe=Jne(),uJe=zne(),fJe=Zne(),AJe=Bc(),pJe=rie(),hJe=iie(),gJe=Vx(),dJe=lie(),mJe=uie(),yJe=cB(),EJe=Jx(),IJe=T_(),CJe=R_(),wJe=Kx(),BJe=zx(),vJe=F_(),SJe=Eie(),DJe=AB(),bJe=vc(),PJe=hB(),xJe=_ie(),kJe=jie(),QJe=qie(),TJe=Vie(),RJe=Kie(),FJe=tk(),NJe=tse(),OJe=nse(),LJe=ose(),MJe=lse(),UJe=hse();mse.exports={parse:nJe,valid:iJe,clean:sJe,inc:oJe,diff:aJe,major:lJe,minor:cJe,patch:uJe,prerelease:fJe,compare:AJe,rcompare:pJe,compareLoose:hJe,compareBuild:gJe,sort:dJe,rsort:mJe,gt:yJe,lt:EJe,eq:IJe,neq:CJe,gte:wJe,lte:BJe,cmp:vJe,coerce:SJe,Comparator:DJe,Range:bJe,satisfies:PJe,toComparators:xJe,maxSatisfying:kJe,minSatisfying:QJe,minVersion:TJe,validRange:RJe,outside:FJe,gtr:NJe,ltr:OJe,intersects:LJe,simplifyRange:MJe,subset:UJe,SemVer:rJe,re:J_.re,src:J_.src,tokens:J_.t,SEMVER_SPEC_VERSION:gse.SEMVER_SPEC_VERSION,RELEASE_TYPES:gse.RELEASE_TYPES,compareIdentifiers:dse.compareIdentifiers,rcompareIdentifiers:dse.rcompareIdentifiers}});var Ese=_((qRt,yse)=>{"use strict";function _Je(t,e){function r(){this.constructor=t}r.prototype=e.prototype,t.prototype=new r}function jd(t,e,r,s){this.message=t,this.expected=e,this.found=r,this.location=s,this.name="SyntaxError",typeof Error.captureStackTrace=="function"&&Error.captureStackTrace(this,jd)}_Je(jd,Error);jd.buildMessage=function(t,e){var r={literal:function(h){return'"'+a(h.text)+'"'},class:function(h){var E="",C;for(C=0;C0){for(C=1,S=1;C{switch(Te[1]){case"|":return xe|Te[3];case"&":return xe&Te[3];case"^":return xe^Te[3]}},$)},S="!",P=Fe("!",!1),I=function($){return!$},R="(",N=Fe("(",!1),U=")",W=Fe(")",!1),ee=function($){return $},ie=/^[^ \t\n\r()!|&\^]/,ue=Ne([" "," ",` +`,"\r","(",")","!","|","&","^"],!0,!1),le=function($){return e.queryPattern.test($)},me=function($){return e.checkFn($)},pe=ke("whitespace"),Be=/^[ \t\n\r]/,Ce=Ne([" "," ",` +`,"\r"],!1,!1),g=0,we=0,ye=[{line:1,column:1}],Ae=0,se=[],Z=0,De;if("startRule"in e){if(!(e.startRule in s))throw new Error(`Can't start parsing from rule "`+e.startRule+'".');a=s[e.startRule]}function Re(){return t.substring(we,g)}function mt(){return Ue(we,g)}function j($,oe){throw oe=oe!==void 0?oe:Ue(we,g),b([ke($)],t.substring(we,g),oe)}function rt($,oe){throw oe=oe!==void 0?oe:Ue(we,g),w($,oe)}function Fe($,oe){return{type:"literal",text:$,ignoreCase:oe}}function Ne($,oe,xe){return{type:"class",parts:$,inverted:oe,ignoreCase:xe}}function Pe(){return{type:"any"}}function Ve(){return{type:"end"}}function ke($){return{type:"other",description:$}}function it($){var oe=ye[$],xe;if(oe)return oe;for(xe=$-1;!ye[xe];)xe--;for(oe=ye[xe],oe={line:oe.line,column:oe.column};xe<$;)t.charCodeAt(xe)===10?(oe.line++,oe.column=1):oe.column++,xe++;return ye[$]=oe,oe}function Ue($,oe){var xe=it($),Te=it(oe);return{start:{offset:$,line:xe.line,column:xe.column},end:{offset:oe,line:Te.line,column:Te.column}}}function x($){gAe&&(Ae=g,se=[]),se.push($))}function w($,oe){return new jd($,null,null,oe)}function b($,oe,xe){return new jd(jd.buildMessage($,oe),$,oe,xe)}function y(){var $,oe,xe,Te,lt,Ct,qt,ir;if($=g,oe=F(),oe!==r){for(xe=[],Te=g,lt=X(),lt!==r?(t.charCodeAt(g)===124?(Ct=n,g++):(Ct=r,Z===0&&x(c)),Ct===r&&(t.charCodeAt(g)===38?(Ct=f,g++):(Ct=r,Z===0&&x(p)),Ct===r&&(t.charCodeAt(g)===94?(Ct=h,g++):(Ct=r,Z===0&&x(E)))),Ct!==r?(qt=X(),qt!==r?(ir=F(),ir!==r?(lt=[lt,Ct,qt,ir],Te=lt):(g=Te,Te=r)):(g=Te,Te=r)):(g=Te,Te=r)):(g=Te,Te=r);Te!==r;)xe.push(Te),Te=g,lt=X(),lt!==r?(t.charCodeAt(g)===124?(Ct=n,g++):(Ct=r,Z===0&&x(c)),Ct===r&&(t.charCodeAt(g)===38?(Ct=f,g++):(Ct=r,Z===0&&x(p)),Ct===r&&(t.charCodeAt(g)===94?(Ct=h,g++):(Ct=r,Z===0&&x(E)))),Ct!==r?(qt=X(),qt!==r?(ir=F(),ir!==r?(lt=[lt,Ct,qt,ir],Te=lt):(g=Te,Te=r)):(g=Te,Te=r)):(g=Te,Te=r)):(g=Te,Te=r);xe!==r?(we=$,oe=C(oe,xe),$=oe):(g=$,$=r)}else g=$,$=r;return $}function F(){var $,oe,xe,Te,lt,Ct;return $=g,t.charCodeAt(g)===33?(oe=S,g++):(oe=r,Z===0&&x(P)),oe!==r?(xe=F(),xe!==r?(we=$,oe=I(xe),$=oe):(g=$,$=r)):(g=$,$=r),$===r&&($=g,t.charCodeAt(g)===40?(oe=R,g++):(oe=r,Z===0&&x(N)),oe!==r?(xe=X(),xe!==r?(Te=y(),Te!==r?(lt=X(),lt!==r?(t.charCodeAt(g)===41?(Ct=U,g++):(Ct=r,Z===0&&x(W)),Ct!==r?(we=$,oe=ee(Te),$=oe):(g=$,$=r)):(g=$,$=r)):(g=$,$=r)):(g=$,$=r)):(g=$,$=r),$===r&&($=z())),$}function z(){var $,oe,xe,Te,lt;if($=g,oe=X(),oe!==r){if(xe=g,Te=[],ie.test(t.charAt(g))?(lt=t.charAt(g),g++):(lt=r,Z===0&&x(ue)),lt!==r)for(;lt!==r;)Te.push(lt),ie.test(t.charAt(g))?(lt=t.charAt(g),g++):(lt=r,Z===0&&x(ue));else Te=r;Te!==r?xe=t.substring(xe,g):xe=Te,xe!==r?(we=g,Te=le(xe),Te?Te=void 0:Te=r,Te!==r?(we=$,oe=me(xe),$=oe):(g=$,$=r)):(g=$,$=r)}else g=$,$=r;return $}function X(){var $,oe;for(Z++,$=[],Be.test(t.charAt(g))?(oe=t.charAt(g),g++):(oe=r,Z===0&&x(Ce));oe!==r;)$.push(oe),Be.test(t.charAt(g))?(oe=t.charAt(g),g++):(oe=r,Z===0&&x(Ce));return Z--,$===r&&(oe=r,Z===0&&x(pe)),$}if(De=a(),De!==r&&g===t.length)return De;throw De!==r&&g{var{parse:jJe}=Ese();rk.makeParser=(t=/[a-z]+/)=>(e,r)=>jJe(e,{queryPattern:t,checkFn:r});rk.parse=rk.makeParser()});var wse=_((YRt,Cse)=>{"use strict";Cse.exports={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]}});var K_=_((VRt,vse)=>{var dB=wse(),Bse={};for(let t of Object.keys(dB))Bse[dB[t]]=t;var hr={rgb:{channels:3,labels:"rgb"},hsl:{channels:3,labels:"hsl"},hsv:{channels:3,labels:"hsv"},hwb:{channels:3,labels:"hwb"},cmyk:{channels:4,labels:"cmyk"},xyz:{channels:3,labels:"xyz"},lab:{channels:3,labels:"lab"},lch:{channels:3,labels:"lch"},hex:{channels:1,labels:["hex"]},keyword:{channels:1,labels:["keyword"]},ansi16:{channels:1,labels:["ansi16"]},ansi256:{channels:1,labels:["ansi256"]},hcg:{channels:3,labels:["h","c","g"]},apple:{channels:3,labels:["r16","g16","b16"]},gray:{channels:1,labels:["gray"]}};vse.exports=hr;for(let t of Object.keys(hr)){if(!("channels"in hr[t]))throw new Error("missing channels property: "+t);if(!("labels"in hr[t]))throw new Error("missing channel labels property: "+t);if(hr[t].labels.length!==hr[t].channels)throw new Error("channel and label counts mismatch: "+t);let{channels:e,labels:r}=hr[t];delete hr[t].channels,delete hr[t].labels,Object.defineProperty(hr[t],"channels",{value:e}),Object.defineProperty(hr[t],"labels",{value:r})}hr.rgb.hsl=function(t){let e=t[0]/255,r=t[1]/255,s=t[2]/255,a=Math.min(e,r,s),n=Math.max(e,r,s),c=n-a,f,p;n===a?f=0:e===n?f=(r-s)/c:r===n?f=2+(s-e)/c:s===n&&(f=4+(e-r)/c),f=Math.min(f*60,360),f<0&&(f+=360);let h=(a+n)/2;return n===a?p=0:h<=.5?p=c/(n+a):p=c/(2-n-a),[f,p*100,h*100]};hr.rgb.hsv=function(t){let e,r,s,a,n,c=t[0]/255,f=t[1]/255,p=t[2]/255,h=Math.max(c,f,p),E=h-Math.min(c,f,p),C=function(S){return(h-S)/6/E+1/2};return E===0?(a=0,n=0):(n=E/h,e=C(c),r=C(f),s=C(p),c===h?a=s-r:f===h?a=1/3+e-s:p===h&&(a=2/3+r-e),a<0?a+=1:a>1&&(a-=1)),[a*360,n*100,h*100]};hr.rgb.hwb=function(t){let e=t[0],r=t[1],s=t[2],a=hr.rgb.hsl(t)[0],n=1/255*Math.min(e,Math.min(r,s));return s=1-1/255*Math.max(e,Math.max(r,s)),[a,n*100,s*100]};hr.rgb.cmyk=function(t){let e=t[0]/255,r=t[1]/255,s=t[2]/255,a=Math.min(1-e,1-r,1-s),n=(1-e-a)/(1-a)||0,c=(1-r-a)/(1-a)||0,f=(1-s-a)/(1-a)||0;return[n*100,c*100,f*100,a*100]};function GJe(t,e){return(t[0]-e[0])**2+(t[1]-e[1])**2+(t[2]-e[2])**2}hr.rgb.keyword=function(t){let e=Bse[t];if(e)return e;let r=1/0,s;for(let a of Object.keys(dB)){let n=dB[a],c=GJe(t,n);c.04045?((e+.055)/1.055)**2.4:e/12.92,r=r>.04045?((r+.055)/1.055)**2.4:r/12.92,s=s>.04045?((s+.055)/1.055)**2.4:s/12.92;let a=e*.4124+r*.3576+s*.1805,n=e*.2126+r*.7152+s*.0722,c=e*.0193+r*.1192+s*.9505;return[a*100,n*100,c*100]};hr.rgb.lab=function(t){let e=hr.rgb.xyz(t),r=e[0],s=e[1],a=e[2];r/=95.047,s/=100,a/=108.883,r=r>.008856?r**(1/3):7.787*r+16/116,s=s>.008856?s**(1/3):7.787*s+16/116,a=a>.008856?a**(1/3):7.787*a+16/116;let n=116*s-16,c=500*(r-s),f=200*(s-a);return[n,c,f]};hr.hsl.rgb=function(t){let e=t[0]/360,r=t[1]/100,s=t[2]/100,a,n,c;if(r===0)return c=s*255,[c,c,c];s<.5?a=s*(1+r):a=s+r-s*r;let f=2*s-a,p=[0,0,0];for(let h=0;h<3;h++)n=e+1/3*-(h-1),n<0&&n++,n>1&&n--,6*n<1?c=f+(a-f)*6*n:2*n<1?c=a:3*n<2?c=f+(a-f)*(2/3-n)*6:c=f,p[h]=c*255;return p};hr.hsl.hsv=function(t){let e=t[0],r=t[1]/100,s=t[2]/100,a=r,n=Math.max(s,.01);s*=2,r*=s<=1?s:2-s,a*=n<=1?n:2-n;let c=(s+r)/2,f=s===0?2*a/(n+a):2*r/(s+r);return[e,f*100,c*100]};hr.hsv.rgb=function(t){let e=t[0]/60,r=t[1]/100,s=t[2]/100,a=Math.floor(e)%6,n=e-Math.floor(e),c=255*s*(1-r),f=255*s*(1-r*n),p=255*s*(1-r*(1-n));switch(s*=255,a){case 0:return[s,p,c];case 1:return[f,s,c];case 2:return[c,s,p];case 3:return[c,f,s];case 4:return[p,c,s];case 5:return[s,c,f]}};hr.hsv.hsl=function(t){let e=t[0],r=t[1]/100,s=t[2]/100,a=Math.max(s,.01),n,c;c=(2-r)*s;let f=(2-r)*a;return n=r*a,n/=f<=1?f:2-f,n=n||0,c/=2,[e,n*100,c*100]};hr.hwb.rgb=function(t){let e=t[0]/360,r=t[1]/100,s=t[2]/100,a=r+s,n;a>1&&(r/=a,s/=a);let c=Math.floor(6*e),f=1-s;n=6*e-c,c&1&&(n=1-n);let p=r+n*(f-r),h,E,C;switch(c){default:case 6:case 0:h=f,E=p,C=r;break;case 1:h=p,E=f,C=r;break;case 2:h=r,E=f,C=p;break;case 3:h=r,E=p,C=f;break;case 4:h=p,E=r,C=f;break;case 5:h=f,E=r,C=p;break}return[h*255,E*255,C*255]};hr.cmyk.rgb=function(t){let e=t[0]/100,r=t[1]/100,s=t[2]/100,a=t[3]/100,n=1-Math.min(1,e*(1-a)+a),c=1-Math.min(1,r*(1-a)+a),f=1-Math.min(1,s*(1-a)+a);return[n*255,c*255,f*255]};hr.xyz.rgb=function(t){let e=t[0]/100,r=t[1]/100,s=t[2]/100,a,n,c;return a=e*3.2406+r*-1.5372+s*-.4986,n=e*-.9689+r*1.8758+s*.0415,c=e*.0557+r*-.204+s*1.057,a=a>.0031308?1.055*a**(1/2.4)-.055:a*12.92,n=n>.0031308?1.055*n**(1/2.4)-.055:n*12.92,c=c>.0031308?1.055*c**(1/2.4)-.055:c*12.92,a=Math.min(Math.max(0,a),1),n=Math.min(Math.max(0,n),1),c=Math.min(Math.max(0,c),1),[a*255,n*255,c*255]};hr.xyz.lab=function(t){let e=t[0],r=t[1],s=t[2];e/=95.047,r/=100,s/=108.883,e=e>.008856?e**(1/3):7.787*e+16/116,r=r>.008856?r**(1/3):7.787*r+16/116,s=s>.008856?s**(1/3):7.787*s+16/116;let a=116*r-16,n=500*(e-r),c=200*(r-s);return[a,n,c]};hr.lab.xyz=function(t){let e=t[0],r=t[1],s=t[2],a,n,c;n=(e+16)/116,a=r/500+n,c=n-s/200;let f=n**3,p=a**3,h=c**3;return n=f>.008856?f:(n-16/116)/7.787,a=p>.008856?p:(a-16/116)/7.787,c=h>.008856?h:(c-16/116)/7.787,a*=95.047,n*=100,c*=108.883,[a,n,c]};hr.lab.lch=function(t){let e=t[0],r=t[1],s=t[2],a;a=Math.atan2(s,r)*360/2/Math.PI,a<0&&(a+=360);let c=Math.sqrt(r*r+s*s);return[e,c,a]};hr.lch.lab=function(t){let e=t[0],r=t[1],a=t[2]/360*2*Math.PI,n=r*Math.cos(a),c=r*Math.sin(a);return[e,n,c]};hr.rgb.ansi16=function(t,e=null){let[r,s,a]=t,n=e===null?hr.rgb.hsv(t)[2]:e;if(n=Math.round(n/50),n===0)return 30;let c=30+(Math.round(a/255)<<2|Math.round(s/255)<<1|Math.round(r/255));return n===2&&(c+=60),c};hr.hsv.ansi16=function(t){return hr.rgb.ansi16(hr.hsv.rgb(t),t[2])};hr.rgb.ansi256=function(t){let e=t[0],r=t[1],s=t[2];return e===r&&r===s?e<8?16:e>248?231:Math.round((e-8)/247*24)+232:16+36*Math.round(e/255*5)+6*Math.round(r/255*5)+Math.round(s/255*5)};hr.ansi16.rgb=function(t){let e=t%10;if(e===0||e===7)return t>50&&(e+=3.5),e=e/10.5*255,[e,e,e];let r=(~~(t>50)+1)*.5,s=(e&1)*r*255,a=(e>>1&1)*r*255,n=(e>>2&1)*r*255;return[s,a,n]};hr.ansi256.rgb=function(t){if(t>=232){let n=(t-232)*10+8;return[n,n,n]}t-=16;let e,r=Math.floor(t/36)/5*255,s=Math.floor((e=t%36)/6)/5*255,a=e%6/5*255;return[r,s,a]};hr.rgb.hex=function(t){let r=(((Math.round(t[0])&255)<<16)+((Math.round(t[1])&255)<<8)+(Math.round(t[2])&255)).toString(16).toUpperCase();return"000000".substring(r.length)+r};hr.hex.rgb=function(t){let e=t.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i);if(!e)return[0,0,0];let r=e[0];e[0].length===3&&(r=r.split("").map(f=>f+f).join(""));let s=parseInt(r,16),a=s>>16&255,n=s>>8&255,c=s&255;return[a,n,c]};hr.rgb.hcg=function(t){let e=t[0]/255,r=t[1]/255,s=t[2]/255,a=Math.max(Math.max(e,r),s),n=Math.min(Math.min(e,r),s),c=a-n,f,p;return c<1?f=n/(1-c):f=0,c<=0?p=0:a===e?p=(r-s)/c%6:a===r?p=2+(s-e)/c:p=4+(e-r)/c,p/=6,p%=1,[p*360,c*100,f*100]};hr.hsl.hcg=function(t){let e=t[1]/100,r=t[2]/100,s=r<.5?2*e*r:2*e*(1-r),a=0;return s<1&&(a=(r-.5*s)/(1-s)),[t[0],s*100,a*100]};hr.hsv.hcg=function(t){let e=t[1]/100,r=t[2]/100,s=e*r,a=0;return s<1&&(a=(r-s)/(1-s)),[t[0],s*100,a*100]};hr.hcg.rgb=function(t){let e=t[0]/360,r=t[1]/100,s=t[2]/100;if(r===0)return[s*255,s*255,s*255];let a=[0,0,0],n=e%1*6,c=n%1,f=1-c,p=0;switch(Math.floor(n)){case 0:a[0]=1,a[1]=c,a[2]=0;break;case 1:a[0]=f,a[1]=1,a[2]=0;break;case 2:a[0]=0,a[1]=1,a[2]=c;break;case 3:a[0]=0,a[1]=f,a[2]=1;break;case 4:a[0]=c,a[1]=0,a[2]=1;break;default:a[0]=1,a[1]=0,a[2]=f}return p=(1-r)*s,[(r*a[0]+p)*255,(r*a[1]+p)*255,(r*a[2]+p)*255]};hr.hcg.hsv=function(t){let e=t[1]/100,r=t[2]/100,s=e+r*(1-e),a=0;return s>0&&(a=e/s),[t[0],a*100,s*100]};hr.hcg.hsl=function(t){let e=t[1]/100,s=t[2]/100*(1-e)+.5*e,a=0;return s>0&&s<.5?a=e/(2*s):s>=.5&&s<1&&(a=e/(2*(1-s))),[t[0],a*100,s*100]};hr.hcg.hwb=function(t){let e=t[1]/100,r=t[2]/100,s=e+r*(1-e);return[t[0],(s-e)*100,(1-s)*100]};hr.hwb.hcg=function(t){let e=t[1]/100,s=1-t[2]/100,a=s-e,n=0;return a<1&&(n=(s-a)/(1-a)),[t[0],a*100,n*100]};hr.apple.rgb=function(t){return[t[0]/65535*255,t[1]/65535*255,t[2]/65535*255]};hr.rgb.apple=function(t){return[t[0]/255*65535,t[1]/255*65535,t[2]/255*65535]};hr.gray.rgb=function(t){return[t[0]/100*255,t[0]/100*255,t[0]/100*255]};hr.gray.hsl=function(t){return[0,0,t[0]]};hr.gray.hsv=hr.gray.hsl;hr.gray.hwb=function(t){return[0,100,t[0]]};hr.gray.cmyk=function(t){return[0,0,0,t[0]]};hr.gray.lab=function(t){return[t[0],0,0]};hr.gray.hex=function(t){let e=Math.round(t[0]/100*255)&255,s=((e<<16)+(e<<8)+e).toString(16).toUpperCase();return"000000".substring(s.length)+s};hr.rgb.gray=function(t){return[(t[0]+t[1]+t[2])/3/255*100]}});var Dse=_((JRt,Sse)=>{var nk=K_();function qJe(){let t={},e=Object.keys(nk);for(let r=e.length,s=0;s{var z_=K_(),JJe=Dse(),PE={},KJe=Object.keys(z_);function zJe(t){let e=function(...r){let s=r[0];return s==null?s:(s.length>1&&(r=s),t(r))};return"conversion"in t&&(e.conversion=t.conversion),e}function XJe(t){let e=function(...r){let s=r[0];if(s==null)return s;s.length>1&&(r=s);let a=t(r);if(typeof a=="object")for(let n=a.length,c=0;c{PE[t]={},Object.defineProperty(PE[t],"channels",{value:z_[t].channels}),Object.defineProperty(PE[t],"labels",{value:z_[t].labels});let e=JJe(t);Object.keys(e).forEach(s=>{let a=e[s];PE[t][s]=XJe(a),PE[t][s].raw=zJe(a)})});bse.exports=PE});var sk=_((zRt,Rse)=>{"use strict";var xse=(t,e)=>(...r)=>`\x1B[${t(...r)+e}m`,kse=(t,e)=>(...r)=>{let s=t(...r);return`\x1B[${38+e};5;${s}m`},Qse=(t,e)=>(...r)=>{let s=t(...r);return`\x1B[${38+e};2;${s[0]};${s[1]};${s[2]}m`},ik=t=>t,Tse=(t,e,r)=>[t,e,r],xE=(t,e,r)=>{Object.defineProperty(t,e,{get:()=>{let s=r();return Object.defineProperty(t,e,{value:s,enumerable:!0,configurable:!0}),s},enumerable:!0,configurable:!0})},X_,kE=(t,e,r,s)=>{X_===void 0&&(X_=Pse());let a=s?10:0,n={};for(let[c,f]of Object.entries(X_)){let p=c==="ansi16"?"ansi":c;c===e?n[p]=t(r,a):typeof f=="object"&&(n[p]=t(f[e],a))}return n};function ZJe(){let t=new Map,e={modifier:{reset:[0,0],bold:[1,22],dim:[2,22],italic:[3,23],underline:[4,24],inverse:[7,27],hidden:[8,28],strikethrough:[9,29]},color:{black:[30,39],red:[31,39],green:[32,39],yellow:[33,39],blue:[34,39],magenta:[35,39],cyan:[36,39],white:[37,39],blackBright:[90,39],redBright:[91,39],greenBright:[92,39],yellowBright:[93,39],blueBright:[94,39],magentaBright:[95,39],cyanBright:[96,39],whiteBright:[97,39]},bgColor:{bgBlack:[40,49],bgRed:[41,49],bgGreen:[42,49],bgYellow:[43,49],bgBlue:[44,49],bgMagenta:[45,49],bgCyan:[46,49],bgWhite:[47,49],bgBlackBright:[100,49],bgRedBright:[101,49],bgGreenBright:[102,49],bgYellowBright:[103,49],bgBlueBright:[104,49],bgMagentaBright:[105,49],bgCyanBright:[106,49],bgWhiteBright:[107,49]}};e.color.gray=e.color.blackBright,e.bgColor.bgGray=e.bgColor.bgBlackBright,e.color.grey=e.color.blackBright,e.bgColor.bgGrey=e.bgColor.bgBlackBright;for(let[r,s]of Object.entries(e)){for(let[a,n]of Object.entries(s))e[a]={open:`\x1B[${n[0]}m`,close:`\x1B[${n[1]}m`},s[a]=e[a],t.set(n[0],n[1]);Object.defineProperty(e,r,{value:s,enumerable:!1})}return Object.defineProperty(e,"codes",{value:t,enumerable:!1}),e.color.close="\x1B[39m",e.bgColor.close="\x1B[49m",xE(e.color,"ansi",()=>kE(xse,"ansi16",ik,!1)),xE(e.color,"ansi256",()=>kE(kse,"ansi256",ik,!1)),xE(e.color,"ansi16m",()=>kE(Qse,"rgb",Tse,!1)),xE(e.bgColor,"ansi",()=>kE(xse,"ansi16",ik,!0)),xE(e.bgColor,"ansi256",()=>kE(kse,"ansi256",ik,!0)),xE(e.bgColor,"ansi16m",()=>kE(Qse,"rgb",Tse,!0)),e}Object.defineProperty(Rse,"exports",{enumerable:!0,get:ZJe})});var Nse=_((XRt,Fse)=>{"use strict";Fse.exports=(t,e=process.argv)=>{let r=t.startsWith("-")?"":t.length===1?"-":"--",s=e.indexOf(r+t),a=e.indexOf("--");return s!==-1&&(a===-1||s{"use strict";var $Je=Ie("os"),Ose=Ie("tty"),Sc=Nse(),{env:bs}=process,l0;Sc("no-color")||Sc("no-colors")||Sc("color=false")||Sc("color=never")?l0=0:(Sc("color")||Sc("colors")||Sc("color=true")||Sc("color=always"))&&(l0=1);"FORCE_COLOR"in bs&&(bs.FORCE_COLOR==="true"?l0=1:bs.FORCE_COLOR==="false"?l0=0:l0=bs.FORCE_COLOR.length===0?1:Math.min(parseInt(bs.FORCE_COLOR,10),3));function Z_(t){return t===0?!1:{level:t,hasBasic:!0,has256:t>=2,has16m:t>=3}}function $_(t,e){if(l0===0)return 0;if(Sc("color=16m")||Sc("color=full")||Sc("color=truecolor"))return 3;if(Sc("color=256"))return 2;if(t&&!e&&l0===void 0)return 0;let r=l0||0;if(bs.TERM==="dumb")return r;if(process.platform==="win32"){let s=$Je.release().split(".");return Number(s[0])>=10&&Number(s[2])>=10586?Number(s[2])>=14931?3:2:1}if("CI"in bs)return["TRAVIS","CIRCLECI","APPVEYOR","GITLAB_CI"].some(s=>s in bs)||bs.CI_NAME==="codeship"?1:r;if("TEAMCITY_VERSION"in bs)return/^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(bs.TEAMCITY_VERSION)?1:0;if("GITHUB_ACTIONS"in bs)return 1;if(bs.COLORTERM==="truecolor")return 3;if("TERM_PROGRAM"in bs){let s=parseInt((bs.TERM_PROGRAM_VERSION||"").split(".")[0],10);switch(bs.TERM_PROGRAM){case"iTerm.app":return s>=3?3:2;case"Apple_Terminal":return 2}}return/-256(color)?$/i.test(bs.TERM)?2:/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(bs.TERM)||"COLORTERM"in bs?1:r}function eKe(t){let e=$_(t,t&&t.isTTY);return Z_(e)}Lse.exports={supportsColor:eKe,stdout:Z_($_(!0,Ose.isatty(1))),stderr:Z_($_(!0,Ose.isatty(2)))}});var _se=_(($Rt,Use)=>{"use strict";var tKe=(t,e,r)=>{let s=t.indexOf(e);if(s===-1)return t;let a=e.length,n=0,c="";do c+=t.substr(n,s-n)+e+r,n=s+a,s=t.indexOf(e,n);while(s!==-1);return c+=t.substr(n),c},rKe=(t,e,r,s)=>{let a=0,n="";do{let c=t[s-1]==="\r";n+=t.substr(a,(c?s-1:s)-a)+e+(c?`\r +`:` +`)+r,a=s+1,s=t.indexOf(` +`,a)}while(s!==-1);return n+=t.substr(a),n};Use.exports={stringReplaceAll:tKe,stringEncaseCRLFWithFirstIndex:rKe}});var Wse=_((eFt,qse)=>{"use strict";var nKe=/(?:\\(u(?:[a-f\d]{4}|\{[a-f\d]{1,6}\})|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi,Hse=/(?:^|\.)(\w+)(?:\(([^)]*)\))?/g,iKe=/^(['"])((?:\\.|(?!\1)[^\\])*)\1$/,sKe=/\\(u(?:[a-f\d]{4}|{[a-f\d]{1,6}})|x[a-f\d]{2}|.)|([^\\])/gi,oKe=new Map([["n",` +`],["r","\r"],["t"," "],["b","\b"],["f","\f"],["v","\v"],["0","\0"],["\\","\\"],["e","\x1B"],["a","\x07"]]);function Gse(t){let e=t[0]==="u",r=t[1]==="{";return e&&!r&&t.length===5||t[0]==="x"&&t.length===3?String.fromCharCode(parseInt(t.slice(1),16)):e&&r?String.fromCodePoint(parseInt(t.slice(2,-1),16)):oKe.get(t)||t}function aKe(t,e){let r=[],s=e.trim().split(/\s*,\s*/g),a;for(let n of s){let c=Number(n);if(!Number.isNaN(c))r.push(c);else if(a=n.match(iKe))r.push(a[2].replace(sKe,(f,p,h)=>p?Gse(p):h));else throw new Error(`Invalid Chalk template style argument: ${n} (in style '${t}')`)}return r}function lKe(t){Hse.lastIndex=0;let e=[],r;for(;(r=Hse.exec(t))!==null;){let s=r[1];if(r[2]){let a=aKe(s,r[2]);e.push([s].concat(a))}else e.push([s])}return e}function jse(t,e){let r={};for(let a of e)for(let n of a.styles)r[n[0]]=a.inverse?null:n.slice(1);let s=t;for(let[a,n]of Object.entries(r))if(Array.isArray(n)){if(!(a in s))throw new Error(`Unknown Chalk style: ${a}`);s=n.length>0?s[a](...n):s[a]}return s}qse.exports=(t,e)=>{let r=[],s=[],a=[];if(e.replace(nKe,(n,c,f,p,h,E)=>{if(c)a.push(Gse(c));else if(p){let C=a.join("");a=[],s.push(r.length===0?C:jse(t,r)(C)),r.push({inverse:f,styles:lKe(p)})}else if(h){if(r.length===0)throw new Error("Found extraneous } in Chalk template literal");s.push(jse(t,r)(a.join(""))),a=[],r.pop()}else a.push(E)}),s.push(a.join("")),r.length>0){let n=`Chalk template literal is missing ${r.length} closing bracket${r.length===1?"":"s"} (\`}\`)`;throw new Error(n)}return s.join("")}});var TE=_((tFt,Xse)=>{"use strict";var mB=sk(),{stdout:t4,stderr:r4}=Mse(),{stringReplaceAll:cKe,stringEncaseCRLFWithFirstIndex:uKe}=_se(),{isArray:ok}=Array,Vse=["ansi","ansi","ansi256","ansi16m"],QE=Object.create(null),fKe=(t,e={})=>{if(e.level&&!(Number.isInteger(e.level)&&e.level>=0&&e.level<=3))throw new Error("The `level` option should be an integer from 0 to 3");let r=t4?t4.level:0;t.level=e.level===void 0?r:e.level},n4=class{constructor(e){return Jse(e)}},Jse=t=>{let e={};return fKe(e,t),e.template=(...r)=>zse(e.template,...r),Object.setPrototypeOf(e,ak.prototype),Object.setPrototypeOf(e.template,e),e.template.constructor=()=>{throw new Error("`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.")},e.template.Instance=n4,e.template};function ak(t){return Jse(t)}for(let[t,e]of Object.entries(mB))QE[t]={get(){let r=lk(this,i4(e.open,e.close,this._styler),this._isEmpty);return Object.defineProperty(this,t,{value:r}),r}};QE.visible={get(){let t=lk(this,this._styler,!0);return Object.defineProperty(this,"visible",{value:t}),t}};var Kse=["rgb","hex","keyword","hsl","hsv","hwb","ansi","ansi256"];for(let t of Kse)QE[t]={get(){let{level:e}=this;return function(...r){let s=i4(mB.color[Vse[e]][t](...r),mB.color.close,this._styler);return lk(this,s,this._isEmpty)}}};for(let t of Kse){let e="bg"+t[0].toUpperCase()+t.slice(1);QE[e]={get(){let{level:r}=this;return function(...s){let a=i4(mB.bgColor[Vse[r]][t](...s),mB.bgColor.close,this._styler);return lk(this,a,this._isEmpty)}}}}var AKe=Object.defineProperties(()=>{},{...QE,level:{enumerable:!0,get(){return this._generator.level},set(t){this._generator.level=t}}}),i4=(t,e,r)=>{let s,a;return r===void 0?(s=t,a=e):(s=r.openAll+t,a=e+r.closeAll),{open:t,close:e,openAll:s,closeAll:a,parent:r}},lk=(t,e,r)=>{let s=(...a)=>ok(a[0])&&ok(a[0].raw)?Yse(s,zse(s,...a)):Yse(s,a.length===1?""+a[0]:a.join(" "));return Object.setPrototypeOf(s,AKe),s._generator=t,s._styler=e,s._isEmpty=r,s},Yse=(t,e)=>{if(t.level<=0||!e)return t._isEmpty?"":e;let r=t._styler;if(r===void 0)return e;let{openAll:s,closeAll:a}=r;if(e.indexOf("\x1B")!==-1)for(;r!==void 0;)e=cKe(e,r.close,r.open),r=r.parent;let n=e.indexOf(` +`);return n!==-1&&(e=uKe(e,a,s,n)),s+e+a},e4,zse=(t,...e)=>{let[r]=e;if(!ok(r)||!ok(r.raw))return e.join(" ");let s=e.slice(1),a=[r.raw[0]];for(let n=1;n{"use strict";Dc.isInteger=t=>typeof t=="number"?Number.isInteger(t):typeof t=="string"&&t.trim()!==""?Number.isInteger(Number(t)):!1;Dc.find=(t,e)=>t.nodes.find(r=>r.type===e);Dc.exceedsLimit=(t,e,r=1,s)=>s===!1||!Dc.isInteger(t)||!Dc.isInteger(e)?!1:(Number(e)-Number(t))/Number(r)>=s;Dc.escapeNode=(t,e=0,r)=>{let s=t.nodes[e];s&&(r&&s.type===r||s.type==="open"||s.type==="close")&&s.escaped!==!0&&(s.value="\\"+s.value,s.escaped=!0)};Dc.encloseBrace=t=>t.type!=="brace"||t.commas>>0+t.ranges>>0?!1:(t.invalid=!0,!0);Dc.isInvalidBrace=t=>t.type!=="brace"?!1:t.invalid===!0||t.dollar?!0:!(t.commas>>0+t.ranges>>0)||t.open!==!0||t.close!==!0?(t.invalid=!0,!0):!1;Dc.isOpenOrClose=t=>t.type==="open"||t.type==="close"?!0:t.open===!0||t.close===!0;Dc.reduce=t=>t.reduce((e,r)=>(r.type==="text"&&e.push(r.value),r.type==="range"&&(r.type="text"),e),[]);Dc.flatten=(...t)=>{let e=[],r=s=>{for(let a=0;a{"use strict";var Zse=uk();$se.exports=(t,e={})=>{let r=(s,a={})=>{let n=e.escapeInvalid&&Zse.isInvalidBrace(a),c=s.invalid===!0&&e.escapeInvalid===!0,f="";if(s.value)return(n||c)&&Zse.isOpenOrClose(s)?"\\"+s.value:s.value;if(s.value)return s.value;if(s.nodes)for(let p of s.nodes)f+=r(p);return f};return r(t)}});var toe=_((iFt,eoe)=>{"use strict";eoe.exports=function(t){return typeof t=="number"?t-t===0:typeof t=="string"&&t.trim()!==""?Number.isFinite?Number.isFinite(+t):isFinite(+t):!1}});var uoe=_((sFt,coe)=>{"use strict";var roe=toe(),Gd=(t,e,r)=>{if(roe(t)===!1)throw new TypeError("toRegexRange: expected the first argument to be a number");if(e===void 0||t===e)return String(t);if(roe(e)===!1)throw new TypeError("toRegexRange: expected the second argument to be a number.");let s={relaxZeros:!0,...r};typeof s.strictZeros=="boolean"&&(s.relaxZeros=s.strictZeros===!1);let a=String(s.relaxZeros),n=String(s.shorthand),c=String(s.capture),f=String(s.wrap),p=t+":"+e+"="+a+n+c+f;if(Gd.cache.hasOwnProperty(p))return Gd.cache[p].result;let h=Math.min(t,e),E=Math.max(t,e);if(Math.abs(h-E)===1){let R=t+"|"+e;return s.capture?`(${R})`:s.wrap===!1?R:`(?:${R})`}let C=loe(t)||loe(e),S={min:t,max:e,a:h,b:E},P=[],I=[];if(C&&(S.isPadded=C,S.maxLen=String(S.max).length),h<0){let R=E<0?Math.abs(E):1;I=noe(R,Math.abs(h),S,s),h=S.a=0}return E>=0&&(P=noe(h,E,S,s)),S.negatives=I,S.positives=P,S.result=pKe(I,P,s),s.capture===!0?S.result=`(${S.result})`:s.wrap!==!1&&P.length+I.length>1&&(S.result=`(?:${S.result})`),Gd.cache[p]=S,S.result};function pKe(t,e,r){let s=s4(t,e,"-",!1,r)||[],a=s4(e,t,"",!1,r)||[],n=s4(t,e,"-?",!0,r)||[];return s.concat(n).concat(a).join("|")}function hKe(t,e){let r=1,s=1,a=soe(t,r),n=new Set([e]);for(;t<=a&&a<=e;)n.add(a),r+=1,a=soe(t,r);for(a=ooe(e+1,s)-1;t1&&f.count.pop(),f.count.push(E.count[0]),f.string=f.pattern+aoe(f.count),c=h+1;continue}r.isPadded&&(C=EKe(h,r,s)),E.string=C+E.pattern+aoe(E.count),n.push(E),c=h+1,f=E}return n}function s4(t,e,r,s,a){let n=[];for(let c of t){let{string:f}=c;!s&&!ioe(e,"string",f)&&n.push(r+f),s&&ioe(e,"string",f)&&n.push(r+f)}return n}function dKe(t,e){let r=[];for(let s=0;se?1:e>t?-1:0}function ioe(t,e,r){return t.some(s=>s[e]===r)}function soe(t,e){return Number(String(t).slice(0,-e)+"9".repeat(e))}function ooe(t,e){return t-t%Math.pow(10,e)}function aoe(t){let[e=0,r=""]=t;return r||e>1?`{${e+(r?","+r:"")}}`:""}function yKe(t,e,r){return`[${t}${e-t===1?"":"-"}${e}]`}function loe(t){return/^-?(0+)\d/.test(t)}function EKe(t,e,r){if(!e.isPadded)return t;let s=Math.abs(e.maxLen-String(t).length),a=r.relaxZeros!==!1;switch(s){case 0:return"";case 1:return a?"0?":"0";case 2:return a?"0{0,2}":"00";default:return a?`0{0,${s}}`:`0{${s}}`}}Gd.cache={};Gd.clearCache=()=>Gd.cache={};coe.exports=Gd});var l4=_((oFt,yoe)=>{"use strict";var IKe=Ie("util"),poe=uoe(),foe=t=>t!==null&&typeof t=="object"&&!Array.isArray(t),CKe=t=>e=>t===!0?Number(e):String(e),o4=t=>typeof t=="number"||typeof t=="string"&&t!=="",yB=t=>Number.isInteger(+t),a4=t=>{let e=`${t}`,r=-1;if(e[0]==="-"&&(e=e.slice(1)),e==="0")return!1;for(;e[++r]==="0";);return r>0},wKe=(t,e,r)=>typeof t=="string"||typeof e=="string"?!0:r.stringify===!0,BKe=(t,e,r)=>{if(e>0){let s=t[0]==="-"?"-":"";s&&(t=t.slice(1)),t=s+t.padStart(s?e-1:e,"0")}return r===!1?String(t):t},Aoe=(t,e)=>{let r=t[0]==="-"?"-":"";for(r&&(t=t.slice(1),e--);t.length{t.negatives.sort((c,f)=>cf?1:0),t.positives.sort((c,f)=>cf?1:0);let r=e.capture?"":"?:",s="",a="",n;return t.positives.length&&(s=t.positives.join("|")),t.negatives.length&&(a=`-(${r}${t.negatives.join("|")})`),s&&a?n=`${s}|${a}`:n=s||a,e.wrap?`(${r}${n})`:n},hoe=(t,e,r,s)=>{if(r)return poe(t,e,{wrap:!1,...s});let a=String.fromCharCode(t);if(t===e)return a;let n=String.fromCharCode(e);return`[${a}-${n}]`},goe=(t,e,r)=>{if(Array.isArray(t)){let s=r.wrap===!0,a=r.capture?"":"?:";return s?`(${a}${t.join("|")})`:t.join("|")}return poe(t,e,r)},doe=(...t)=>new RangeError("Invalid range arguments: "+IKe.inspect(...t)),moe=(t,e,r)=>{if(r.strictRanges===!0)throw doe([t,e]);return[]},SKe=(t,e)=>{if(e.strictRanges===!0)throw new TypeError(`Expected step "${t}" to be a number`);return[]},DKe=(t,e,r=1,s={})=>{let a=Number(t),n=Number(e);if(!Number.isInteger(a)||!Number.isInteger(n)){if(s.strictRanges===!0)throw doe([t,e]);return[]}a===0&&(a=0),n===0&&(n=0);let c=a>n,f=String(t),p=String(e),h=String(r);r=Math.max(Math.abs(r),1);let E=a4(f)||a4(p)||a4(h),C=E?Math.max(f.length,p.length,h.length):0,S=E===!1&&wKe(t,e,s)===!1,P=s.transform||CKe(S);if(s.toRegex&&r===1)return hoe(Aoe(t,C),Aoe(e,C),!0,s);let I={negatives:[],positives:[]},R=W=>I[W<0?"negatives":"positives"].push(Math.abs(W)),N=[],U=0;for(;c?a>=n:a<=n;)s.toRegex===!0&&r>1?R(a):N.push(BKe(P(a,U),C,S)),a=c?a-r:a+r,U++;return s.toRegex===!0?r>1?vKe(I,s):goe(N,null,{wrap:!1,...s}):N},bKe=(t,e,r=1,s={})=>{if(!yB(t)&&t.length>1||!yB(e)&&e.length>1)return moe(t,e,s);let a=s.transform||(S=>String.fromCharCode(S)),n=`${t}`.charCodeAt(0),c=`${e}`.charCodeAt(0),f=n>c,p=Math.min(n,c),h=Math.max(n,c);if(s.toRegex&&r===1)return hoe(p,h,!1,s);let E=[],C=0;for(;f?n>=c:n<=c;)E.push(a(n,C)),n=f?n-r:n+r,C++;return s.toRegex===!0?goe(E,null,{wrap:!1,options:s}):E},Ak=(t,e,r,s={})=>{if(e==null&&o4(t))return[t];if(!o4(t)||!o4(e))return moe(t,e,s);if(typeof r=="function")return Ak(t,e,1,{transform:r});if(foe(r))return Ak(t,e,0,r);let a={...s};return a.capture===!0&&(a.wrap=!0),r=r||a.step||1,yB(r)?yB(t)&&yB(e)?DKe(t,e,r,a):bKe(t,e,Math.max(Math.abs(r),1),a):r!=null&&!foe(r)?SKe(r,a):Ak(t,e,1,r)};yoe.exports=Ak});var Coe=_((aFt,Ioe)=>{"use strict";var PKe=l4(),Eoe=uk(),xKe=(t,e={})=>{let r=(s,a={})=>{let n=Eoe.isInvalidBrace(a),c=s.invalid===!0&&e.escapeInvalid===!0,f=n===!0||c===!0,p=e.escapeInvalid===!0?"\\":"",h="";if(s.isOpen===!0||s.isClose===!0)return p+s.value;if(s.type==="open")return f?p+s.value:"(";if(s.type==="close")return f?p+s.value:")";if(s.type==="comma")return s.prev.type==="comma"?"":f?s.value:"|";if(s.value)return s.value;if(s.nodes&&s.ranges>0){let E=Eoe.reduce(s.nodes),C=PKe(...E,{...e,wrap:!1,toRegex:!0});if(C.length!==0)return E.length>1&&C.length>1?`(${C})`:C}if(s.nodes)for(let E of s.nodes)h+=r(E,s);return h};return r(t)};Ioe.exports=xKe});var voe=_((lFt,Boe)=>{"use strict";var kKe=l4(),woe=fk(),RE=uk(),qd=(t="",e="",r=!1)=>{let s=[];if(t=[].concat(t),e=[].concat(e),!e.length)return t;if(!t.length)return r?RE.flatten(e).map(a=>`{${a}}`):e;for(let a of t)if(Array.isArray(a))for(let n of a)s.push(qd(n,e,r));else for(let n of e)r===!0&&typeof n=="string"&&(n=`{${n}}`),s.push(Array.isArray(n)?qd(a,n,r):a+n);return RE.flatten(s)},QKe=(t,e={})=>{let r=e.rangeLimit===void 0?1e3:e.rangeLimit,s=(a,n={})=>{a.queue=[];let c=n,f=n.queue;for(;c.type!=="brace"&&c.type!=="root"&&c.parent;)c=c.parent,f=c.queue;if(a.invalid||a.dollar){f.push(qd(f.pop(),woe(a,e)));return}if(a.type==="brace"&&a.invalid!==!0&&a.nodes.length===2){f.push(qd(f.pop(),["{}"]));return}if(a.nodes&&a.ranges>0){let C=RE.reduce(a.nodes);if(RE.exceedsLimit(...C,e.step,r))throw new RangeError("expanded array length exceeds range limit. Use options.rangeLimit to increase or disable the limit.");let S=kKe(...C,e);S.length===0&&(S=woe(a,e)),f.push(qd(f.pop(),S)),a.nodes=[];return}let p=RE.encloseBrace(a),h=a.queue,E=a;for(;E.type!=="brace"&&E.type!=="root"&&E.parent;)E=E.parent,h=E.queue;for(let C=0;C{"use strict";Soe.exports={MAX_LENGTH:1024*64,CHAR_0:"0",CHAR_9:"9",CHAR_UPPERCASE_A:"A",CHAR_LOWERCASE_A:"a",CHAR_UPPERCASE_Z:"Z",CHAR_LOWERCASE_Z:"z",CHAR_LEFT_PARENTHESES:"(",CHAR_RIGHT_PARENTHESES:")",CHAR_ASTERISK:"*",CHAR_AMPERSAND:"&",CHAR_AT:"@",CHAR_BACKSLASH:"\\",CHAR_BACKTICK:"`",CHAR_CARRIAGE_RETURN:"\r",CHAR_CIRCUMFLEX_ACCENT:"^",CHAR_COLON:":",CHAR_COMMA:",",CHAR_DOLLAR:"$",CHAR_DOT:".",CHAR_DOUBLE_QUOTE:'"',CHAR_EQUAL:"=",CHAR_EXCLAMATION_MARK:"!",CHAR_FORM_FEED:"\f",CHAR_FORWARD_SLASH:"/",CHAR_HASH:"#",CHAR_HYPHEN_MINUS:"-",CHAR_LEFT_ANGLE_BRACKET:"<",CHAR_LEFT_CURLY_BRACE:"{",CHAR_LEFT_SQUARE_BRACKET:"[",CHAR_LINE_FEED:` +`,CHAR_NO_BREAK_SPACE:"\xA0",CHAR_PERCENT:"%",CHAR_PLUS:"+",CHAR_QUESTION_MARK:"?",CHAR_RIGHT_ANGLE_BRACKET:">",CHAR_RIGHT_CURLY_BRACE:"}",CHAR_RIGHT_SQUARE_BRACKET:"]",CHAR_SEMICOLON:";",CHAR_SINGLE_QUOTE:"'",CHAR_SPACE:" ",CHAR_TAB:" ",CHAR_UNDERSCORE:"_",CHAR_VERTICAL_LINE:"|",CHAR_ZERO_WIDTH_NOBREAK_SPACE:"\uFEFF"}});var Qoe=_((uFt,koe)=>{"use strict";var TKe=fk(),{MAX_LENGTH:boe,CHAR_BACKSLASH:c4,CHAR_BACKTICK:RKe,CHAR_COMMA:FKe,CHAR_DOT:NKe,CHAR_LEFT_PARENTHESES:OKe,CHAR_RIGHT_PARENTHESES:LKe,CHAR_LEFT_CURLY_BRACE:MKe,CHAR_RIGHT_CURLY_BRACE:UKe,CHAR_LEFT_SQUARE_BRACKET:Poe,CHAR_RIGHT_SQUARE_BRACKET:xoe,CHAR_DOUBLE_QUOTE:_Ke,CHAR_SINGLE_QUOTE:HKe,CHAR_NO_BREAK_SPACE:jKe,CHAR_ZERO_WIDTH_NOBREAK_SPACE:GKe}=Doe(),qKe=(t,e={})=>{if(typeof t!="string")throw new TypeError("Expected a string");let r=e||{},s=typeof r.maxLength=="number"?Math.min(boe,r.maxLength):boe;if(t.length>s)throw new SyntaxError(`Input length (${t.length}), exceeds max characters (${s})`);let a={type:"root",input:t,nodes:[]},n=[a],c=a,f=a,p=0,h=t.length,E=0,C=0,S,P={},I=()=>t[E++],R=N=>{if(N.type==="text"&&f.type==="dot"&&(f.type="text"),f&&f.type==="text"&&N.type==="text"){f.value+=N.value;return}return c.nodes.push(N),N.parent=c,N.prev=f,f=N,N};for(R({type:"bos"});E0){if(c.ranges>0){c.ranges=0;let N=c.nodes.shift();c.nodes=[N,{type:"text",value:TKe(c)}]}R({type:"comma",value:S}),c.commas++;continue}if(S===NKe&&C>0&&c.commas===0){let N=c.nodes;if(C===0||N.length===0){R({type:"text",value:S});continue}if(f.type==="dot"){if(c.range=[],f.value+=S,f.type="range",c.nodes.length!==3&&c.nodes.length!==5){c.invalid=!0,c.ranges=0,f.type="text";continue}c.ranges++,c.args=[];continue}if(f.type==="range"){N.pop();let U=N[N.length-1];U.value+=f.value+S,f=U,c.ranges--;continue}R({type:"dot",value:S});continue}R({type:"text",value:S})}do if(c=n.pop(),c.type!=="root"){c.nodes.forEach(W=>{W.nodes||(W.type==="open"&&(W.isOpen=!0),W.type==="close"&&(W.isClose=!0),W.nodes||(W.type="text"),W.invalid=!0)});let N=n[n.length-1],U=N.nodes.indexOf(c);N.nodes.splice(U,1,...c.nodes)}while(n.length>0);return R({type:"eos"}),a};koe.exports=qKe});var Foe=_((fFt,Roe)=>{"use strict";var Toe=fk(),WKe=Coe(),YKe=voe(),VKe=Qoe(),jl=(t,e={})=>{let r=[];if(Array.isArray(t))for(let s of t){let a=jl.create(s,e);Array.isArray(a)?r.push(...a):r.push(a)}else r=[].concat(jl.create(t,e));return e&&e.expand===!0&&e.nodupes===!0&&(r=[...new Set(r)]),r};jl.parse=(t,e={})=>VKe(t,e);jl.stringify=(t,e={})=>Toe(typeof t=="string"?jl.parse(t,e):t,e);jl.compile=(t,e={})=>(typeof t=="string"&&(t=jl.parse(t,e)),WKe(t,e));jl.expand=(t,e={})=>{typeof t=="string"&&(t=jl.parse(t,e));let r=YKe(t,e);return e.noempty===!0&&(r=r.filter(Boolean)),e.nodupes===!0&&(r=[...new Set(r)]),r};jl.create=(t,e={})=>t===""||t.length<3?[t]:e.expand!==!0?jl.compile(t,e):jl.expand(t,e);Roe.exports=jl});var EB=_((AFt,Uoe)=>{"use strict";var JKe=Ie("path"),Vf="\\\\/",Noe=`[^${Vf}]`,Dp="\\.",KKe="\\+",zKe="\\?",pk="\\/",XKe="(?=.)",Ooe="[^/]",u4=`(?:${pk}|$)`,Loe=`(?:^|${pk})`,f4=`${Dp}{1,2}${u4}`,ZKe=`(?!${Dp})`,$Ke=`(?!${Loe}${f4})`,eze=`(?!${Dp}{0,1}${u4})`,tze=`(?!${f4})`,rze=`[^.${pk}]`,nze=`${Ooe}*?`,Moe={DOT_LITERAL:Dp,PLUS_LITERAL:KKe,QMARK_LITERAL:zKe,SLASH_LITERAL:pk,ONE_CHAR:XKe,QMARK:Ooe,END_ANCHOR:u4,DOTS_SLASH:f4,NO_DOT:ZKe,NO_DOTS:$Ke,NO_DOT_SLASH:eze,NO_DOTS_SLASH:tze,QMARK_NO_DOT:rze,STAR:nze,START_ANCHOR:Loe},ize={...Moe,SLASH_LITERAL:`[${Vf}]`,QMARK:Noe,STAR:`${Noe}*?`,DOTS_SLASH:`${Dp}{1,2}(?:[${Vf}]|$)`,NO_DOT:`(?!${Dp})`,NO_DOTS:`(?!(?:^|[${Vf}])${Dp}{1,2}(?:[${Vf}]|$))`,NO_DOT_SLASH:`(?!${Dp}{0,1}(?:[${Vf}]|$))`,NO_DOTS_SLASH:`(?!${Dp}{1,2}(?:[${Vf}]|$))`,QMARK_NO_DOT:`[^.${Vf}]`,START_ANCHOR:`(?:^|[${Vf}])`,END_ANCHOR:`(?:[${Vf}]|$)`},sze={alnum:"a-zA-Z0-9",alpha:"a-zA-Z",ascii:"\\x00-\\x7F",blank:" \\t",cntrl:"\\x00-\\x1F\\x7F",digit:"0-9",graph:"\\x21-\\x7E",lower:"a-z",print:"\\x20-\\x7E ",punct:"\\-!\"#$%&'()\\*+,./:;<=>?@[\\]^_`{|}~",space:" \\t\\r\\n\\v\\f",upper:"A-Z",word:"A-Za-z0-9_",xdigit:"A-Fa-f0-9"};Uoe.exports={MAX_LENGTH:1024*64,POSIX_REGEX_SOURCE:sze,REGEX_BACKSLASH:/\\(?![*+?^${}(|)[\]])/g,REGEX_NON_SPECIAL_CHARS:/^[^@![\].,$*+?^{}()|\\/]+/,REGEX_SPECIAL_CHARS:/[-*+?.^${}(|)[\]]/,REGEX_SPECIAL_CHARS_BACKREF:/(\\?)((\W)(\3*))/g,REGEX_SPECIAL_CHARS_GLOBAL:/([-*+?.^${}(|)[\]])/g,REGEX_REMOVE_BACKSLASH:/(?:\[.*?[^\\]\]|\\(?=.))/g,REPLACEMENTS:{"***":"*","**/**":"**","**/**/**":"**"},CHAR_0:48,CHAR_9:57,CHAR_UPPERCASE_A:65,CHAR_LOWERCASE_A:97,CHAR_UPPERCASE_Z:90,CHAR_LOWERCASE_Z:122,CHAR_LEFT_PARENTHESES:40,CHAR_RIGHT_PARENTHESES:41,CHAR_ASTERISK:42,CHAR_AMPERSAND:38,CHAR_AT:64,CHAR_BACKWARD_SLASH:92,CHAR_CARRIAGE_RETURN:13,CHAR_CIRCUMFLEX_ACCENT:94,CHAR_COLON:58,CHAR_COMMA:44,CHAR_DOT:46,CHAR_DOUBLE_QUOTE:34,CHAR_EQUAL:61,CHAR_EXCLAMATION_MARK:33,CHAR_FORM_FEED:12,CHAR_FORWARD_SLASH:47,CHAR_GRAVE_ACCENT:96,CHAR_HASH:35,CHAR_HYPHEN_MINUS:45,CHAR_LEFT_ANGLE_BRACKET:60,CHAR_LEFT_CURLY_BRACE:123,CHAR_LEFT_SQUARE_BRACKET:91,CHAR_LINE_FEED:10,CHAR_NO_BREAK_SPACE:160,CHAR_PERCENT:37,CHAR_PLUS:43,CHAR_QUESTION_MARK:63,CHAR_RIGHT_ANGLE_BRACKET:62,CHAR_RIGHT_CURLY_BRACE:125,CHAR_RIGHT_SQUARE_BRACKET:93,CHAR_SEMICOLON:59,CHAR_SINGLE_QUOTE:39,CHAR_SPACE:32,CHAR_TAB:9,CHAR_UNDERSCORE:95,CHAR_VERTICAL_LINE:124,CHAR_ZERO_WIDTH_NOBREAK_SPACE:65279,SEP:JKe.sep,extglobChars(t){return{"!":{type:"negate",open:"(?:(?!(?:",close:`))${t.STAR})`},"?":{type:"qmark",open:"(?:",close:")?"},"+":{type:"plus",open:"(?:",close:")+"},"*":{type:"star",open:"(?:",close:")*"},"@":{type:"at",open:"(?:",close:")"}}},globChars(t){return t===!0?ize:Moe}}});var IB=_(ol=>{"use strict";var oze=Ie("path"),aze=process.platform==="win32",{REGEX_BACKSLASH:lze,REGEX_REMOVE_BACKSLASH:cze,REGEX_SPECIAL_CHARS:uze,REGEX_SPECIAL_CHARS_GLOBAL:fze}=EB();ol.isObject=t=>t!==null&&typeof t=="object"&&!Array.isArray(t);ol.hasRegexChars=t=>uze.test(t);ol.isRegexChar=t=>t.length===1&&ol.hasRegexChars(t);ol.escapeRegex=t=>t.replace(fze,"\\$1");ol.toPosixSlashes=t=>t.replace(lze,"/");ol.removeBackslashes=t=>t.replace(cze,e=>e==="\\"?"":e);ol.supportsLookbehinds=()=>{let t=process.version.slice(1).split(".").map(Number);return t.length===3&&t[0]>=9||t[0]===8&&t[1]>=10};ol.isWindows=t=>t&&typeof t.windows=="boolean"?t.windows:aze===!0||oze.sep==="\\";ol.escapeLast=(t,e,r)=>{let s=t.lastIndexOf(e,r);return s===-1?t:t[s-1]==="\\"?ol.escapeLast(t,e,s-1):`${t.slice(0,s)}\\${t.slice(s)}`};ol.removePrefix=(t,e={})=>{let r=t;return r.startsWith("./")&&(r=r.slice(2),e.prefix="./"),r};ol.wrapOutput=(t,e={},r={})=>{let s=r.contains?"":"^",a=r.contains?"":"$",n=`${s}(?:${t})${a}`;return e.negated===!0&&(n=`(?:^(?!${n}).*$)`),n}});var Voe=_((hFt,Yoe)=>{"use strict";var _oe=IB(),{CHAR_ASTERISK:A4,CHAR_AT:Aze,CHAR_BACKWARD_SLASH:CB,CHAR_COMMA:pze,CHAR_DOT:p4,CHAR_EXCLAMATION_MARK:h4,CHAR_FORWARD_SLASH:Woe,CHAR_LEFT_CURLY_BRACE:g4,CHAR_LEFT_PARENTHESES:d4,CHAR_LEFT_SQUARE_BRACKET:hze,CHAR_PLUS:gze,CHAR_QUESTION_MARK:Hoe,CHAR_RIGHT_CURLY_BRACE:dze,CHAR_RIGHT_PARENTHESES:joe,CHAR_RIGHT_SQUARE_BRACKET:mze}=EB(),Goe=t=>t===Woe||t===CB,qoe=t=>{t.isPrefix!==!0&&(t.depth=t.isGlobstar?1/0:1)},yze=(t,e)=>{let r=e||{},s=t.length-1,a=r.parts===!0||r.scanToEnd===!0,n=[],c=[],f=[],p=t,h=-1,E=0,C=0,S=!1,P=!1,I=!1,R=!1,N=!1,U=!1,W=!1,ee=!1,ie=!1,ue=!1,le=0,me,pe,Be={value:"",depth:0,isGlob:!1},Ce=()=>h>=s,g=()=>p.charCodeAt(h+1),we=()=>(me=pe,p.charCodeAt(++h));for(;h0&&(Ae=p.slice(0,E),p=p.slice(E),C-=E),ye&&I===!0&&C>0?(ye=p.slice(0,C),se=p.slice(C)):I===!0?(ye="",se=p):ye=p,ye&&ye!==""&&ye!=="/"&&ye!==p&&Goe(ye.charCodeAt(ye.length-1))&&(ye=ye.slice(0,-1)),r.unescape===!0&&(se&&(se=_oe.removeBackslashes(se)),ye&&W===!0&&(ye=_oe.removeBackslashes(ye)));let Z={prefix:Ae,input:t,start:E,base:ye,glob:se,isBrace:S,isBracket:P,isGlob:I,isExtglob:R,isGlobstar:N,negated:ee,negatedExtglob:ie};if(r.tokens===!0&&(Z.maxDepth=0,Goe(pe)||c.push(Be),Z.tokens=c),r.parts===!0||r.tokens===!0){let De;for(let Re=0;Re{"use strict";var hk=EB(),Gl=IB(),{MAX_LENGTH:gk,POSIX_REGEX_SOURCE:Eze,REGEX_NON_SPECIAL_CHARS:Ize,REGEX_SPECIAL_CHARS_BACKREF:Cze,REPLACEMENTS:Joe}=hk,wze=(t,e)=>{if(typeof e.expandRange=="function")return e.expandRange(...t,e);t.sort();let r=`[${t.join("-")}]`;try{new RegExp(r)}catch{return t.map(a=>Gl.escapeRegex(a)).join("..")}return r},FE=(t,e)=>`Missing ${t}: "${e}" - use "\\\\${e}" to match literal characters`,m4=(t,e)=>{if(typeof t!="string")throw new TypeError("Expected a string");t=Joe[t]||t;let r={...e},s=typeof r.maxLength=="number"?Math.min(gk,r.maxLength):gk,a=t.length;if(a>s)throw new SyntaxError(`Input length: ${a}, exceeds maximum allowed length: ${s}`);let n={type:"bos",value:"",output:r.prepend||""},c=[n],f=r.capture?"":"?:",p=Gl.isWindows(e),h=hk.globChars(p),E=hk.extglobChars(h),{DOT_LITERAL:C,PLUS_LITERAL:S,SLASH_LITERAL:P,ONE_CHAR:I,DOTS_SLASH:R,NO_DOT:N,NO_DOT_SLASH:U,NO_DOTS_SLASH:W,QMARK:ee,QMARK_NO_DOT:ie,STAR:ue,START_ANCHOR:le}=h,me=x=>`(${f}(?:(?!${le}${x.dot?R:C}).)*?)`,pe=r.dot?"":N,Be=r.dot?ee:ie,Ce=r.bash===!0?me(r):ue;r.capture&&(Ce=`(${Ce})`),typeof r.noext=="boolean"&&(r.noextglob=r.noext);let g={input:t,index:-1,start:0,dot:r.dot===!0,consumed:"",output:"",prefix:"",backtrack:!1,negated:!1,brackets:0,braces:0,parens:0,quotes:0,globstar:!1,tokens:c};t=Gl.removePrefix(t,g),a=t.length;let we=[],ye=[],Ae=[],se=n,Z,De=()=>g.index===a-1,Re=g.peek=(x=1)=>t[g.index+x],mt=g.advance=()=>t[++g.index]||"",j=()=>t.slice(g.index+1),rt=(x="",w=0)=>{g.consumed+=x,g.index+=w},Fe=x=>{g.output+=x.output!=null?x.output:x.value,rt(x.value)},Ne=()=>{let x=1;for(;Re()==="!"&&(Re(2)!=="("||Re(3)==="?");)mt(),g.start++,x++;return x%2===0?!1:(g.negated=!0,g.start++,!0)},Pe=x=>{g[x]++,Ae.push(x)},Ve=x=>{g[x]--,Ae.pop()},ke=x=>{if(se.type==="globstar"){let w=g.braces>0&&(x.type==="comma"||x.type==="brace"),b=x.extglob===!0||we.length&&(x.type==="pipe"||x.type==="paren");x.type!=="slash"&&x.type!=="paren"&&!w&&!b&&(g.output=g.output.slice(0,-se.output.length),se.type="star",se.value="*",se.output=Ce,g.output+=se.output)}if(we.length&&x.type!=="paren"&&(we[we.length-1].inner+=x.value),(x.value||x.output)&&Fe(x),se&&se.type==="text"&&x.type==="text"){se.value+=x.value,se.output=(se.output||"")+x.value;return}x.prev=se,c.push(x),se=x},it=(x,w)=>{let b={...E[w],conditions:1,inner:""};b.prev=se,b.parens=g.parens,b.output=g.output;let y=(r.capture?"(":"")+b.open;Pe("parens"),ke({type:x,value:w,output:g.output?"":I}),ke({type:"paren",extglob:!0,value:mt(),output:y}),we.push(b)},Ue=x=>{let w=x.close+(r.capture?")":""),b;if(x.type==="negate"){let y=Ce;if(x.inner&&x.inner.length>1&&x.inner.includes("/")&&(y=me(r)),(y!==Ce||De()||/^\)+$/.test(j()))&&(w=x.close=`)$))${y}`),x.inner.includes("*")&&(b=j())&&/^\.[^\\/.]+$/.test(b)){let F=m4(b,{...e,fastpaths:!1}).output;w=x.close=`)${F})${y})`}x.prev.type==="bos"&&(g.negatedExtglob=!0)}ke({type:"paren",extglob:!0,value:Z,output:w}),Ve("parens")};if(r.fastpaths!==!1&&!/(^[*!]|[/()[\]{}"])/.test(t)){let x=!1,w=t.replace(Cze,(b,y,F,z,X,$)=>z==="\\"?(x=!0,b):z==="?"?y?y+z+(X?ee.repeat(X.length):""):$===0?Be+(X?ee.repeat(X.length):""):ee.repeat(F.length):z==="."?C.repeat(F.length):z==="*"?y?y+z+(X?Ce:""):Ce:y?b:`\\${b}`);return x===!0&&(r.unescape===!0?w=w.replace(/\\/g,""):w=w.replace(/\\+/g,b=>b.length%2===0?"\\\\":b?"\\":"")),w===t&&r.contains===!0?(g.output=t,g):(g.output=Gl.wrapOutput(w,g,e),g)}for(;!De();){if(Z=mt(),Z==="\0")continue;if(Z==="\\"){let b=Re();if(b==="/"&&r.bash!==!0||b==="."||b===";")continue;if(!b){Z+="\\",ke({type:"text",value:Z});continue}let y=/^\\+/.exec(j()),F=0;if(y&&y[0].length>2&&(F=y[0].length,g.index+=F,F%2!==0&&(Z+="\\")),r.unescape===!0?Z=mt():Z+=mt(),g.brackets===0){ke({type:"text",value:Z});continue}}if(g.brackets>0&&(Z!=="]"||se.value==="["||se.value==="[^")){if(r.posix!==!1&&Z===":"){let b=se.value.slice(1);if(b.includes("[")&&(se.posix=!0,b.includes(":"))){let y=se.value.lastIndexOf("["),F=se.value.slice(0,y),z=se.value.slice(y+2),X=Eze[z];if(X){se.value=F+X,g.backtrack=!0,mt(),!n.output&&c.indexOf(se)===1&&(n.output=I);continue}}}(Z==="["&&Re()!==":"||Z==="-"&&Re()==="]")&&(Z=`\\${Z}`),Z==="]"&&(se.value==="["||se.value==="[^")&&(Z=`\\${Z}`),r.posix===!0&&Z==="!"&&se.value==="["&&(Z="^"),se.value+=Z,Fe({value:Z});continue}if(g.quotes===1&&Z!=='"'){Z=Gl.escapeRegex(Z),se.value+=Z,Fe({value:Z});continue}if(Z==='"'){g.quotes=g.quotes===1?0:1,r.keepQuotes===!0&&ke({type:"text",value:Z});continue}if(Z==="("){Pe("parens"),ke({type:"paren",value:Z});continue}if(Z===")"){if(g.parens===0&&r.strictBrackets===!0)throw new SyntaxError(FE("opening","("));let b=we[we.length-1];if(b&&g.parens===b.parens+1){Ue(we.pop());continue}ke({type:"paren",value:Z,output:g.parens?")":"\\)"}),Ve("parens");continue}if(Z==="["){if(r.nobracket===!0||!j().includes("]")){if(r.nobracket!==!0&&r.strictBrackets===!0)throw new SyntaxError(FE("closing","]"));Z=`\\${Z}`}else Pe("brackets");ke({type:"bracket",value:Z});continue}if(Z==="]"){if(r.nobracket===!0||se&&se.type==="bracket"&&se.value.length===1){ke({type:"text",value:Z,output:`\\${Z}`});continue}if(g.brackets===0){if(r.strictBrackets===!0)throw new SyntaxError(FE("opening","["));ke({type:"text",value:Z,output:`\\${Z}`});continue}Ve("brackets");let b=se.value.slice(1);if(se.posix!==!0&&b[0]==="^"&&!b.includes("/")&&(Z=`/${Z}`),se.value+=Z,Fe({value:Z}),r.literalBrackets===!1||Gl.hasRegexChars(b))continue;let y=Gl.escapeRegex(se.value);if(g.output=g.output.slice(0,-se.value.length),r.literalBrackets===!0){g.output+=y,se.value=y;continue}se.value=`(${f}${y}|${se.value})`,g.output+=se.value;continue}if(Z==="{"&&r.nobrace!==!0){Pe("braces");let b={type:"brace",value:Z,output:"(",outputIndex:g.output.length,tokensIndex:g.tokens.length};ye.push(b),ke(b);continue}if(Z==="}"){let b=ye[ye.length-1];if(r.nobrace===!0||!b){ke({type:"text",value:Z,output:Z});continue}let y=")";if(b.dots===!0){let F=c.slice(),z=[];for(let X=F.length-1;X>=0&&(c.pop(),F[X].type!=="brace");X--)F[X].type!=="dots"&&z.unshift(F[X].value);y=wze(z,r),g.backtrack=!0}if(b.comma!==!0&&b.dots!==!0){let F=g.output.slice(0,b.outputIndex),z=g.tokens.slice(b.tokensIndex);b.value=b.output="\\{",Z=y="\\}",g.output=F;for(let X of z)g.output+=X.output||X.value}ke({type:"brace",value:Z,output:y}),Ve("braces"),ye.pop();continue}if(Z==="|"){we.length>0&&we[we.length-1].conditions++,ke({type:"text",value:Z});continue}if(Z===","){let b=Z,y=ye[ye.length-1];y&&Ae[Ae.length-1]==="braces"&&(y.comma=!0,b="|"),ke({type:"comma",value:Z,output:b});continue}if(Z==="/"){if(se.type==="dot"&&g.index===g.start+1){g.start=g.index+1,g.consumed="",g.output="",c.pop(),se=n;continue}ke({type:"slash",value:Z,output:P});continue}if(Z==="."){if(g.braces>0&&se.type==="dot"){se.value==="."&&(se.output=C);let b=ye[ye.length-1];se.type="dots",se.output+=Z,se.value+=Z,b.dots=!0;continue}if(g.braces+g.parens===0&&se.type!=="bos"&&se.type!=="slash"){ke({type:"text",value:Z,output:C});continue}ke({type:"dot",value:Z,output:C});continue}if(Z==="?"){if(!(se&&se.value==="(")&&r.noextglob!==!0&&Re()==="("&&Re(2)!=="?"){it("qmark",Z);continue}if(se&&se.type==="paren"){let y=Re(),F=Z;if(y==="<"&&!Gl.supportsLookbehinds())throw new Error("Node.js v10 or higher is required for regex lookbehinds");(se.value==="("&&!/[!=<:]/.test(y)||y==="<"&&!/<([!=]|\w+>)/.test(j()))&&(F=`\\${Z}`),ke({type:"text",value:Z,output:F});continue}if(r.dot!==!0&&(se.type==="slash"||se.type==="bos")){ke({type:"qmark",value:Z,output:ie});continue}ke({type:"qmark",value:Z,output:ee});continue}if(Z==="!"){if(r.noextglob!==!0&&Re()==="("&&(Re(2)!=="?"||!/[!=<:]/.test(Re(3)))){it("negate",Z);continue}if(r.nonegate!==!0&&g.index===0){Ne();continue}}if(Z==="+"){if(r.noextglob!==!0&&Re()==="("&&Re(2)!=="?"){it("plus",Z);continue}if(se&&se.value==="("||r.regex===!1){ke({type:"plus",value:Z,output:S});continue}if(se&&(se.type==="bracket"||se.type==="paren"||se.type==="brace")||g.parens>0){ke({type:"plus",value:Z});continue}ke({type:"plus",value:S});continue}if(Z==="@"){if(r.noextglob!==!0&&Re()==="("&&Re(2)!=="?"){ke({type:"at",extglob:!0,value:Z,output:""});continue}ke({type:"text",value:Z});continue}if(Z!=="*"){(Z==="$"||Z==="^")&&(Z=`\\${Z}`);let b=Ize.exec(j());b&&(Z+=b[0],g.index+=b[0].length),ke({type:"text",value:Z});continue}if(se&&(se.type==="globstar"||se.star===!0)){se.type="star",se.star=!0,se.value+=Z,se.output=Ce,g.backtrack=!0,g.globstar=!0,rt(Z);continue}let x=j();if(r.noextglob!==!0&&/^\([^?]/.test(x)){it("star",Z);continue}if(se.type==="star"){if(r.noglobstar===!0){rt(Z);continue}let b=se.prev,y=b.prev,F=b.type==="slash"||b.type==="bos",z=y&&(y.type==="star"||y.type==="globstar");if(r.bash===!0&&(!F||x[0]&&x[0]!=="/")){ke({type:"star",value:Z,output:""});continue}let X=g.braces>0&&(b.type==="comma"||b.type==="brace"),$=we.length&&(b.type==="pipe"||b.type==="paren");if(!F&&b.type!=="paren"&&!X&&!$){ke({type:"star",value:Z,output:""});continue}for(;x.slice(0,3)==="/**";){let oe=t[g.index+4];if(oe&&oe!=="/")break;x=x.slice(3),rt("/**",3)}if(b.type==="bos"&&De()){se.type="globstar",se.value+=Z,se.output=me(r),g.output=se.output,g.globstar=!0,rt(Z);continue}if(b.type==="slash"&&b.prev.type!=="bos"&&!z&&De()){g.output=g.output.slice(0,-(b.output+se.output).length),b.output=`(?:${b.output}`,se.type="globstar",se.output=me(r)+(r.strictSlashes?")":"|$)"),se.value+=Z,g.globstar=!0,g.output+=b.output+se.output,rt(Z);continue}if(b.type==="slash"&&b.prev.type!=="bos"&&x[0]==="/"){let oe=x[1]!==void 0?"|$":"";g.output=g.output.slice(0,-(b.output+se.output).length),b.output=`(?:${b.output}`,se.type="globstar",se.output=`${me(r)}${P}|${P}${oe})`,se.value+=Z,g.output+=b.output+se.output,g.globstar=!0,rt(Z+mt()),ke({type:"slash",value:"/",output:""});continue}if(b.type==="bos"&&x[0]==="/"){se.type="globstar",se.value+=Z,se.output=`(?:^|${P}|${me(r)}${P})`,g.output=se.output,g.globstar=!0,rt(Z+mt()),ke({type:"slash",value:"/",output:""});continue}g.output=g.output.slice(0,-se.output.length),se.type="globstar",se.output=me(r),se.value+=Z,g.output+=se.output,g.globstar=!0,rt(Z);continue}let w={type:"star",value:Z,output:Ce};if(r.bash===!0){w.output=".*?",(se.type==="bos"||se.type==="slash")&&(w.output=pe+w.output),ke(w);continue}if(se&&(se.type==="bracket"||se.type==="paren")&&r.regex===!0){w.output=Z,ke(w);continue}(g.index===g.start||se.type==="slash"||se.type==="dot")&&(se.type==="dot"?(g.output+=U,se.output+=U):r.dot===!0?(g.output+=W,se.output+=W):(g.output+=pe,se.output+=pe),Re()!=="*"&&(g.output+=I,se.output+=I)),ke(w)}for(;g.brackets>0;){if(r.strictBrackets===!0)throw new SyntaxError(FE("closing","]"));g.output=Gl.escapeLast(g.output,"["),Ve("brackets")}for(;g.parens>0;){if(r.strictBrackets===!0)throw new SyntaxError(FE("closing",")"));g.output=Gl.escapeLast(g.output,"("),Ve("parens")}for(;g.braces>0;){if(r.strictBrackets===!0)throw new SyntaxError(FE("closing","}"));g.output=Gl.escapeLast(g.output,"{"),Ve("braces")}if(r.strictSlashes!==!0&&(se.type==="star"||se.type==="bracket")&&ke({type:"maybe_slash",value:"",output:`${P}?`}),g.backtrack===!0){g.output="";for(let x of g.tokens)g.output+=x.output!=null?x.output:x.value,x.suffix&&(g.output+=x.suffix)}return g};m4.fastpaths=(t,e)=>{let r={...e},s=typeof r.maxLength=="number"?Math.min(gk,r.maxLength):gk,a=t.length;if(a>s)throw new SyntaxError(`Input length: ${a}, exceeds maximum allowed length: ${s}`);t=Joe[t]||t;let n=Gl.isWindows(e),{DOT_LITERAL:c,SLASH_LITERAL:f,ONE_CHAR:p,DOTS_SLASH:h,NO_DOT:E,NO_DOTS:C,NO_DOTS_SLASH:S,STAR:P,START_ANCHOR:I}=hk.globChars(n),R=r.dot?C:E,N=r.dot?S:E,U=r.capture?"":"?:",W={negated:!1,prefix:""},ee=r.bash===!0?".*?":P;r.capture&&(ee=`(${ee})`);let ie=pe=>pe.noglobstar===!0?ee:`(${U}(?:(?!${I}${pe.dot?h:c}).)*?)`,ue=pe=>{switch(pe){case"*":return`${R}${p}${ee}`;case".*":return`${c}${p}${ee}`;case"*.*":return`${R}${ee}${c}${p}${ee}`;case"*/*":return`${R}${ee}${f}${p}${N}${ee}`;case"**":return R+ie(r);case"**/*":return`(?:${R}${ie(r)}${f})?${N}${p}${ee}`;case"**/*.*":return`(?:${R}${ie(r)}${f})?${N}${ee}${c}${p}${ee}`;case"**/.*":return`(?:${R}${ie(r)}${f})?${c}${p}${ee}`;default:{let Be=/^(.*?)\.(\w+)$/.exec(pe);if(!Be)return;let Ce=ue(Be[1]);return Ce?Ce+c+Be[2]:void 0}}},le=Gl.removePrefix(t,W),me=ue(le);return me&&r.strictSlashes!==!0&&(me+=`${f}?`),me};Koe.exports=m4});var Zoe=_((dFt,Xoe)=>{"use strict";var Bze=Ie("path"),vze=Voe(),y4=zoe(),E4=IB(),Sze=EB(),Dze=t=>t&&typeof t=="object"&&!Array.isArray(t),Zi=(t,e,r=!1)=>{if(Array.isArray(t)){let E=t.map(S=>Zi(S,e,r));return S=>{for(let P of E){let I=P(S);if(I)return I}return!1}}let s=Dze(t)&&t.tokens&&t.input;if(t===""||typeof t!="string"&&!s)throw new TypeError("Expected pattern to be a non-empty string");let a=e||{},n=E4.isWindows(e),c=s?Zi.compileRe(t,e):Zi.makeRe(t,e,!1,!0),f=c.state;delete c.state;let p=()=>!1;if(a.ignore){let E={...e,ignore:null,onMatch:null,onResult:null};p=Zi(a.ignore,E,r)}let h=(E,C=!1)=>{let{isMatch:S,match:P,output:I}=Zi.test(E,c,e,{glob:t,posix:n}),R={glob:t,state:f,regex:c,posix:n,input:E,output:I,match:P,isMatch:S};return typeof a.onResult=="function"&&a.onResult(R),S===!1?(R.isMatch=!1,C?R:!1):p(E)?(typeof a.onIgnore=="function"&&a.onIgnore(R),R.isMatch=!1,C?R:!1):(typeof a.onMatch=="function"&&a.onMatch(R),C?R:!0)};return r&&(h.state=f),h};Zi.test=(t,e,r,{glob:s,posix:a}={})=>{if(typeof t!="string")throw new TypeError("Expected input to be a string");if(t==="")return{isMatch:!1,output:""};let n=r||{},c=n.format||(a?E4.toPosixSlashes:null),f=t===s,p=f&&c?c(t):t;return f===!1&&(p=c?c(t):t,f=p===s),(f===!1||n.capture===!0)&&(n.matchBase===!0||n.basename===!0?f=Zi.matchBase(t,e,r,a):f=e.exec(p)),{isMatch:!!f,match:f,output:p}};Zi.matchBase=(t,e,r,s=E4.isWindows(r))=>(e instanceof RegExp?e:Zi.makeRe(e,r)).test(Bze.basename(t));Zi.isMatch=(t,e,r)=>Zi(e,r)(t);Zi.parse=(t,e)=>Array.isArray(t)?t.map(r=>Zi.parse(r,e)):y4(t,{...e,fastpaths:!1});Zi.scan=(t,e)=>vze(t,e);Zi.compileRe=(t,e,r=!1,s=!1)=>{if(r===!0)return t.output;let a=e||{},n=a.contains?"":"^",c=a.contains?"":"$",f=`${n}(?:${t.output})${c}`;t&&t.negated===!0&&(f=`^(?!${f}).*$`);let p=Zi.toRegex(f,e);return s===!0&&(p.state=t),p};Zi.makeRe=(t,e={},r=!1,s=!1)=>{if(!t||typeof t!="string")throw new TypeError("Expected a non-empty string");let a={negated:!1,fastpaths:!0};return e.fastpaths!==!1&&(t[0]==="."||t[0]==="*")&&(a.output=y4.fastpaths(t,e)),a.output||(a=y4(t,e)),Zi.compileRe(a,e,r,s)};Zi.toRegex=(t,e)=>{try{let r=e||{};return new RegExp(t,r.flags||(r.nocase?"i":""))}catch(r){if(e&&e.debug===!0)throw r;return/$^/}};Zi.constants=Sze;Xoe.exports=Zi});var eae=_((mFt,$oe)=>{"use strict";$oe.exports=Zoe()});var Go=_((yFt,iae)=>{"use strict";var rae=Ie("util"),nae=Foe(),Jf=eae(),I4=IB(),tae=t=>t===""||t==="./",xi=(t,e,r)=>{e=[].concat(e),t=[].concat(t);let s=new Set,a=new Set,n=new Set,c=0,f=E=>{n.add(E.output),r&&r.onResult&&r.onResult(E)};for(let E=0;E!s.has(E));if(r&&h.length===0){if(r.failglob===!0)throw new Error(`No matches found for "${e.join(", ")}"`);if(r.nonull===!0||r.nullglob===!0)return r.unescape?e.map(E=>E.replace(/\\/g,"")):e}return h};xi.match=xi;xi.matcher=(t,e)=>Jf(t,e);xi.isMatch=(t,e,r)=>Jf(e,r)(t);xi.any=xi.isMatch;xi.not=(t,e,r={})=>{e=[].concat(e).map(String);let s=new Set,a=[],n=f=>{r.onResult&&r.onResult(f),a.push(f.output)},c=new Set(xi(t,e,{...r,onResult:n}));for(let f of a)c.has(f)||s.add(f);return[...s]};xi.contains=(t,e,r)=>{if(typeof t!="string")throw new TypeError(`Expected a string: "${rae.inspect(t)}"`);if(Array.isArray(e))return e.some(s=>xi.contains(t,s,r));if(typeof e=="string"){if(tae(t)||tae(e))return!1;if(t.includes(e)||t.startsWith("./")&&t.slice(2).includes(e))return!0}return xi.isMatch(t,e,{...r,contains:!0})};xi.matchKeys=(t,e,r)=>{if(!I4.isObject(t))throw new TypeError("Expected the first argument to be an object");let s=xi(Object.keys(t),e,r),a={};for(let n of s)a[n]=t[n];return a};xi.some=(t,e,r)=>{let s=[].concat(t);for(let a of[].concat(e)){let n=Jf(String(a),r);if(s.some(c=>n(c)))return!0}return!1};xi.every=(t,e,r)=>{let s=[].concat(t);for(let a of[].concat(e)){let n=Jf(String(a),r);if(!s.every(c=>n(c)))return!1}return!0};xi.all=(t,e,r)=>{if(typeof t!="string")throw new TypeError(`Expected a string: "${rae.inspect(t)}"`);return[].concat(e).every(s=>Jf(s,r)(t))};xi.capture=(t,e,r)=>{let s=I4.isWindows(r),n=Jf.makeRe(String(t),{...r,capture:!0}).exec(s?I4.toPosixSlashes(e):e);if(n)return n.slice(1).map(c=>c===void 0?"":c)};xi.makeRe=(...t)=>Jf.makeRe(...t);xi.scan=(...t)=>Jf.scan(...t);xi.parse=(t,e)=>{let r=[];for(let s of[].concat(t||[]))for(let a of nae(String(s),e))r.push(Jf.parse(a,e));return r};xi.braces=(t,e)=>{if(typeof t!="string")throw new TypeError("Expected a string");return e&&e.nobrace===!0||!/\{.*\}/.test(t)?[t]:nae(t,e)};xi.braceExpand=(t,e)=>{if(typeof t!="string")throw new TypeError("Expected a string");return xi.braces(t,{...e,expand:!0})};iae.exports=xi});var oae=_((EFt,sae)=>{"use strict";sae.exports=({onlyFirst:t=!1}={})=>{let e=["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)","(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))"].join("|");return new RegExp(e,t?void 0:"g")}});var dk=_((IFt,aae)=>{"use strict";var bze=oae();aae.exports=t=>typeof t=="string"?t.replace(bze(),""):t});function lae(t){return Number.isSafeInteger(t)&&t>=0}var cae=Xe(()=>{});function uae(t){return t!=null&&typeof t!="function"&&lae(t.length)}var fae=Xe(()=>{cae()});function bc(t){return t==="__proto__"}var wB=Xe(()=>{});function NE(t){switch(typeof t){case"number":case"symbol":return!1;case"string":return t.includes(".")||t.includes("[")||t.includes("]")}}var mk=Xe(()=>{});function OE(t){return typeof t=="string"||typeof t=="symbol"?t:Object.is(t?.valueOf?.(),-0)?"-0":String(t)}var yk=Xe(()=>{});function Mu(t){let e=[],r=t.length;if(r===0)return e;let s=0,a="",n="",c=!1;for(t.charCodeAt(0)===46&&(e.push(""),s++);s{});function va(t,e,r){if(t==null)return r;switch(typeof e){case"string":{if(bc(e))return r;let s=t[e];return s===void 0?NE(e)?va(t,Mu(e),r):r:s}case"number":case"symbol":{typeof e=="number"&&(e=OE(e));let s=t[e];return s===void 0?r:s}default:{if(Array.isArray(e))return Pze(t,e,r);if(Object.is(e?.valueOf(),-0)?e="-0":e=String(e),bc(e))return r;let s=t[e];return s===void 0?r:s}}}function Pze(t,e,r){if(e.length===0)return r;let s=t;for(let a=0;a{wB();mk();yk();LE()});function C4(t){return t!==null&&(typeof t=="object"||typeof t=="function")}var Aae=Xe(()=>{});function ME(t){return t==null||typeof t!="object"&&typeof t!="function"}var Ik=Xe(()=>{});function Ck(t,e){return t===e||Number.isNaN(t)&&Number.isNaN(e)}var w4=Xe(()=>{});function Wd(t){return Object.getOwnPropertySymbols(t).filter(e=>Object.prototype.propertyIsEnumerable.call(t,e))}var wk=Xe(()=>{});function Yd(t){return t==null?t===void 0?"[object Undefined]":"[object Null]":Object.prototype.toString.call(t)}var Bk=Xe(()=>{});var vk,UE,_E,HE,Vd,Sk,Dk,bk,Pk,xk,pae,kk,jE,hae,Qk,Tk,Rk,Fk,Nk,gae,Ok,Lk,Mk,dae,Uk,_k,Hk=Xe(()=>{vk="[object RegExp]",UE="[object String]",_E="[object Number]",HE="[object Boolean]",Vd="[object Arguments]",Sk="[object Symbol]",Dk="[object Date]",bk="[object Map]",Pk="[object Set]",xk="[object Array]",pae="[object Function]",kk="[object ArrayBuffer]",jE="[object Object]",hae="[object Error]",Qk="[object DataView]",Tk="[object Uint8Array]",Rk="[object Uint8ClampedArray]",Fk="[object Uint16Array]",Nk="[object Uint32Array]",gae="[object BigUint64Array]",Ok="[object Int8Array]",Lk="[object Int16Array]",Mk="[object Int32Array]",dae="[object BigInt64Array]",Uk="[object Float32Array]",_k="[object Float64Array]"});function GE(t){return ArrayBuffer.isView(t)&&!(t instanceof DataView)}var jk=Xe(()=>{});function mae(t,e){return u0(t,void 0,t,new Map,e)}function u0(t,e,r,s=new Map,a=void 0){let n=a?.(t,e,r,s);if(n!=null)return n;if(ME(t))return t;if(s.has(t))return s.get(t);if(Array.isArray(t)){let c=new Array(t.length);s.set(t,c);for(let f=0;f{wk();Bk();Hk();Ik();jk()});function yae(t){return u0(t,void 0,t,new Map,void 0)}var Eae=Xe(()=>{B4()});function Iae(t,e){return mae(t,(r,s,a,n)=>{let c=e?.(r,s,a,n);if(c!=null)return c;if(typeof t=="object")switch(Object.prototype.toString.call(t)){case _E:case UE:case HE:{let f=new t.constructor(t?.valueOf());return c0(f,t),f}case Vd:{let f={};return c0(f,t),f.length=t.length,f[Symbol.iterator]=t[Symbol.iterator],f}default:return}})}var Cae=Xe(()=>{B4();Hk()});function f0(t){return Iae(t)}var v4=Xe(()=>{Cae()});function Gk(t,e=Number.MAX_SAFE_INTEGER){switch(typeof t){case"number":return Number.isInteger(t)&&t>=0&&t{kze=/^(?:0|[1-9]\d*)$/});function BB(t){return t!==null&&typeof t=="object"&&Yd(t)==="[object Arguments]"}var D4=Xe(()=>{Bk()});function vB(t,e){let r;if(Array.isArray(e)?r=e:typeof e=="string"&&NE(e)&&t?.[e]==null?r=Mu(e):r=[e],r.length===0)return!1;let s=t;for(let a=0;a{mk();S4();D4();LE()});function P4(t){return typeof t=="object"&&t!==null}var wae=Xe(()=>{});function Bae(t){return typeof t=="symbol"||t instanceof Symbol}var vae=Xe(()=>{});function Sae(t,e){return Array.isArray(t)?!1:typeof t=="number"||typeof t=="boolean"||t==null||Bae(t)?!0:typeof t=="string"&&(Tze.test(t)||!Qze.test(t))||e!=null&&Object.hasOwn(e,t)}var Qze,Tze,Dae=Xe(()=>{vae();Qze=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,Tze=/^\w*$/});function A0(t,e){if(t==null)return!0;switch(typeof e){case"symbol":case"number":case"object":{if(Array.isArray(e))return bae(t,e);if(typeof e=="number"?e=OE(e):typeof e=="object"&&(Object.is(e?.valueOf(),-0)?e="-0":e=String(e)),bc(e))return!1;if(t?.[e]===void 0)return!0;try{return delete t[e],!0}catch{return!1}}case"string":{if(t?.[e]===void 0&&NE(e))return bae(t,Mu(e));if(bc(e))return!1;try{return delete t[e],!0}catch{return!1}}}}function bae(t,e){let r=va(t,e.slice(0,-1),t),s=e[e.length-1];if(r?.[s]===void 0)return!0;if(bc(s))return!1;try{return delete r[s],!0}catch{return!1}}var x4=Xe(()=>{Ek();wB();mk();yk();LE()});function Pae(t){return t==null}var xae=Xe(()=>{});var kae,Qae=Xe(()=>{w4();kae=(t,e,r)=>{let s=t[e];(!(Object.hasOwn(t,e)&&Ck(s,r))||r===void 0&&!(e in t))&&(t[e]=r)}});function Tae(t,e,r,s){if(t==null&&!C4(t))return t;let a=Sae(e,t)?[e]:Array.isArray(e)?e:typeof e=="string"?Mu(e):[e],n=t;for(let c=0;c{wB();Qae();S4();Dae();yk();Aae();LE()});function Jd(t,e,r){return Tae(t,e,()=>r,()=>{})}var k4=Xe(()=>{Rae()});function Fae(t,e=0,r={}){typeof r!="object"&&(r={});let s=null,a=null,n=null,c=0,f=null,p,{leading:h=!1,trailing:E=!0,maxWait:C}=r,S="maxWait"in r,P=S?Math.max(Number(C)||0,e):0,I=ue=>(s!==null&&(p=t.apply(a,s)),s=a=null,c=ue,p),R=ue=>(c=ue,f=setTimeout(ee,e),h&&s!==null?I(ue):p),N=ue=>(f=null,E&&s!==null?I(ue):p),U=ue=>{if(n===null)return!0;let le=ue-n,me=le>=e||le<0,pe=S&&ue-c>=P;return me||pe},W=ue=>{let le=n===null?0:ue-n,me=e-le,pe=P-(ue-c);return S?Math.min(me,pe):me},ee=()=>{let ue=Date.now();if(U(ue))return N(ue);f=setTimeout(ee,W(ue))},ie=function(...ue){let le=Date.now(),me=U(le);if(s=ue,a=this,n=le,me){if(f===null)return R(le);if(S)return clearTimeout(f),f=setTimeout(ee,e),I(le)}return f===null&&(f=setTimeout(ee,e)),p};return ie.cancel=()=>{f!==null&&clearTimeout(f),c=0,n=s=a=f=null},ie.flush=()=>f===null?p:N(Date.now()),ie}var Nae=Xe(()=>{});function Q4(t,e=0,r={}){let{leading:s=!0,trailing:a=!0}=r;return Fae(t,e,{leading:s,maxWait:e,trailing:a})}var Oae=Xe(()=>{Nae()});function T4(t){if(t==null)return"";if(typeof t=="string")return t;if(Array.isArray(t))return t.map(T4).join(",");let e=String(t);return e==="0"&&Object.is(Number(t),-0)?"-0":e}var Lae=Xe(()=>{});function R4(t){if(!t||typeof t!="object")return!1;let e=Object.getPrototypeOf(t);return e===null||e===Object.prototype||Object.getPrototypeOf(e)===null?Object.prototype.toString.call(t)==="[object Object]":!1}var Mae=Xe(()=>{});function Uae(t,e,r){return SB(t,e,void 0,void 0,void 0,void 0,r)}function SB(t,e,r,s,a,n,c){let f=c(t,e,r,s,a,n);if(f!==void 0)return f;if(typeof t==typeof e)switch(typeof t){case"bigint":case"string":case"boolean":case"symbol":case"undefined":return t===e;case"number":return t===e||Object.is(t,e);case"function":return t===e;case"object":return DB(t,e,n,c)}return DB(t,e,n,c)}function DB(t,e,r,s){if(Object.is(t,e))return!0;let a=Yd(t),n=Yd(e);if(a===Vd&&(a=jE),n===Vd&&(n=jE),a!==n)return!1;switch(a){case UE:return t.toString()===e.toString();case _E:{let p=t.valueOf(),h=e.valueOf();return Ck(p,h)}case HE:case Dk:case Sk:return Object.is(t.valueOf(),e.valueOf());case vk:return t.source===e.source&&t.flags===e.flags;case pae:return t===e}r=r??new Map;let c=r.get(t),f=r.get(e);if(c!=null&&f!=null)return c===e;r.set(t,e),r.set(e,t);try{switch(a){case bk:{if(t.size!==e.size)return!1;for(let[p,h]of t.entries())if(!e.has(p)||!SB(h,e.get(p),p,t,e,r,s))return!1;return!0}case Pk:{if(t.size!==e.size)return!1;let p=Array.from(t.values()),h=Array.from(e.values());for(let E=0;ESB(C,P,void 0,t,e,r,s));if(S===-1)return!1;h.splice(S,1)}return!0}case xk:case Tk:case Rk:case Fk:case Nk:case gae:case Ok:case Lk:case Mk:case dae:case Uk:case _k:{if(typeof Buffer<"u"&&Buffer.isBuffer(t)!==Buffer.isBuffer(e)||t.length!==e.length)return!1;for(let p=0;p{Mae();wk();Bk();Hk();w4()});function Hae(){}var jae=Xe(()=>{});function F4(t,e){return Uae(t,e,Hae)}var Gae=Xe(()=>{_ae();jae()});function qae(t){return GE(t)}var Wae=Xe(()=>{jk()});function Yae(t){if(typeof t!="object"||t==null)return!1;if(Object.getPrototypeOf(t)===null)return!0;if(Object.prototype.toString.call(t)!=="[object Object]"){let r=t[Symbol.toStringTag];return r==null||!Object.getOwnPropertyDescriptor(t,Symbol.toStringTag)?.writable?!1:t.toString()===`[object ${r}]`}let e=t;for(;Object.getPrototypeOf(e)!==null;)e=Object.getPrototypeOf(e);return Object.getPrototypeOf(t)===e}var Vae=Xe(()=>{});function Jae(t){if(ME(t))return t;if(Array.isArray(t)||GE(t)||t instanceof ArrayBuffer||typeof SharedArrayBuffer<"u"&&t instanceof SharedArrayBuffer)return t.slice(0);let e=Object.getPrototypeOf(t),r=e.constructor;if(t instanceof Date||t instanceof Map||t instanceof Set)return new r(t);if(t instanceof RegExp){let s=new r(t);return s.lastIndex=t.lastIndex,s}if(t instanceof DataView)return new r(t.buffer.slice(0));if(t instanceof Error){let s=new r(t.message);return s.stack=t.stack,s.name=t.name,s.cause=t.cause,s}if(typeof File<"u"&&t instanceof File)return new r([t],t.name,{type:t.type,lastModified:t.lastModified});if(typeof t=="object"){let s=Object.create(e);return Object.assign(s,t)}return t}var Kae=Xe(()=>{Ik();jk()});function N4(t,...e){let r=e.slice(0,-1),s=e[e.length-1],a=t;for(let n=0;n{v4();wB();Kae();Ik();wk();D4();wae();Vae();Wae()});function O4(t,...e){if(t==null)return{};let r=yae(t);for(let s=0;s{x4();Eae()});function Kd(t,...e){if(Pae(t))return{};let r={};for(let s=0;s{Ek();b4();k4();fae();xae()});function $ae(t){return t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()}var ele=Xe(()=>{});function bB(t){return $ae(T4(t))}var tle=Xe(()=>{ele();Lae()});var ql=Xe(()=>{Oae();Gae();v4();Ek();b4();zae();Xae();Zae();k4();x4();tle();LE()});var je={};Vt(je,{AsyncActions:()=>U4,BufferStream:()=>M4,CachingStrategy:()=>fle,DefaultStream:()=>_4,allSettledSafe:()=>Uu,assertNever:()=>G4,bufferStream:()=>WE,buildIgnorePattern:()=>Uze,convertMapsToIndexableObjects:()=>Yk,dynamicRequire:()=>Pp,escapeRegExp:()=>Fze,getArrayWithDefault:()=>xB,getFactoryWithDefault:()=>Yl,getMapWithDefault:()=>q4,getSetWithDefault:()=>bp,groupBy:()=>jze,isIndexableObject:()=>L4,isPathLike:()=>_ze,isTaggedYarnVersion:()=>Rze,makeDeferred:()=>lle,mapAndFilter:()=>Wl,mapAndFind:()=>p0,mergeIntoTarget:()=>ple,overrideType:()=>Nze,parseBoolean:()=>kB,parseDuration:()=>Jk,parseInt:()=>YE,parseOptionalBoolean:()=>Ale,plural:()=>Wk,prettifyAsyncErrors:()=>qE,prettifySyncErrors:()=>W4,releaseAfterUseAsync:()=>Lze,replaceEnvVariables:()=>Vk,sortMap:()=>qs,toMerged:()=>Hze,tryParseOptionalBoolean:()=>Y4,validateEnum:()=>Oze});function Rze(t){return!!(sle.default.valid(t)&&t.match(/^[^-]+(-rc\.[0-9]+)?$/))}function Wk(t,{one:e,more:r,zero:s=r}){return t===0?s:t===1?e:r}function Fze(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function Nze(t){}function G4(t){throw new Error(`Assertion failed: Unexpected object '${t}'`)}function Oze(t,e){let r=Object.values(t);if(!r.includes(e))throw new nt(`Invalid value for enumeration: ${JSON.stringify(e)} (expected one of ${r.map(s=>JSON.stringify(s)).join(", ")})`);return e}function Wl(t,e){let r=[];for(let s of t){let a=e(s);a!==ole&&r.push(a)}return r}function p0(t,e){for(let r of t){let s=e(r);if(s!==ale)return s}}function L4(t){return typeof t=="object"&&t!==null}async function Uu(t){let e=await Promise.allSettled(t),r=[];for(let s of e){if(s.status==="rejected")throw s.reason;r.push(s.value)}return r}function Yk(t){if(t instanceof Map&&(t=Object.fromEntries(t)),L4(t))for(let e of Object.keys(t)){let r=t[e];L4(r)&&(t[e]=Yk(r))}return t}function Yl(t,e,r){let s=t.get(e);return typeof s>"u"&&t.set(e,s=r()),s}function xB(t,e){let r=t.get(e);return typeof r>"u"&&t.set(e,r=[]),r}function bp(t,e){let r=t.get(e);return typeof r>"u"&&t.set(e,r=new Set),r}function q4(t,e){let r=t.get(e);return typeof r>"u"&&t.set(e,r=new Map),r}async function Lze(t,e){if(e==null)return await t();try{return await t()}finally{await e()}}async function qE(t,e){try{return await t()}catch(r){throw r.message=e(r.message),r}}function W4(t,e){try{return t()}catch(r){throw r.message=e(r.message),r}}async function WE(t){return await new Promise((e,r)=>{let s=[];t.on("error",a=>{r(a)}),t.on("data",a=>{s.push(a)}),t.on("end",()=>{e(Buffer.concat(s))})})}function lle(){let t,e;return{promise:new Promise((s,a)=>{t=s,e=a}),resolve:t,reject:e}}function cle(t){return PB(fe.fromPortablePath(t))}function ule(path){let physicalPath=fe.fromPortablePath(path),currentCacheEntry=PB.cache[physicalPath];delete PB.cache[physicalPath];let result;try{result=cle(physicalPath);let freshCacheEntry=PB.cache[physicalPath],dynamicModule=eval("module"),freshCacheIndex=dynamicModule.children.indexOf(freshCacheEntry);freshCacheIndex!==-1&&dynamicModule.children.splice(freshCacheIndex,1)}finally{PB.cache[physicalPath]=currentCacheEntry}return result}function Mze(t){let e=rle.get(t),r=ce.statSync(t);if(e?.mtime===r.mtimeMs)return e.instance;let s=ule(t);return rle.set(t,{mtime:r.mtimeMs,instance:s}),s}function Pp(t,{cachingStrategy:e=2}={}){switch(e){case 0:return ule(t);case 1:return Mze(t);case 2:return cle(t);default:throw new Error("Unsupported caching strategy")}}function qs(t,e){let r=Array.from(t);Array.isArray(e)||(e=[e]);let s=[];for(let n of e)s.push(r.map(c=>n(c)));let a=r.map((n,c)=>c);return a.sort((n,c)=>{for(let f of s){let p=f[n]f[c]?1:0;if(p!==0)return p}return 0}),a.map(n=>r[n])}function Uze(t){return t.length===0?null:t.map(e=>`(${nle.default.makeRe(e,{windows:!1,dot:!0}).source})`).join("|")}function Vk(t,{env:e}){let r=/\\?\${(?[\d\w_]+)(?:)?(?:-(?[^}]*))?}/g;return t.replace(r,(s,...a)=>{if(s.startsWith("\\"))return s.slice(1);let{variableName:n,colon:c,fallback:f}=a[a.length-1],p=Object.hasOwn(e,n),h=e[n];if(h||p&&!c)return h;if(f!=null)return f;throw new nt(`Environment variable not found (${n})`)})}function kB(t){switch(t){case"true":case"1":case 1:case!0:return!0;case"false":case"0":case 0:case!1:return!1;default:throw new Error(`Couldn't parse "${t}" as a boolean`)}}function Ale(t){return typeof t>"u"?t:kB(t)}function Y4(t){try{return Ale(t)}catch{return null}}function _ze(t){return!!(fe.isAbsolute(t)||t.match(/^(\.{1,2}|~)\//))}function ple(t,...e){let r=c=>({value:c}),s=r(t),a=e.map(c=>r(c)),{value:n}=N4(s,...a,(c,f)=>{if(Array.isArray(c)&&Array.isArray(f)){for(let p of f)c.find(h=>F4(h,p))||c.push(p);return c}});return n}function Hze(...t){return ple({},...t)}function jze(t,e){let r=Object.create(null);for(let s of t){let a=s[e];r[a]??=[],r[a].push(s)}return r}function YE(t){return typeof t=="string"?Number.parseInt(t,10):t}function Jk(t,e){let r=Gze.exec(t)?.groups;if(!r)throw new Error(`Couldn't parse "${t}" as a duration`);if(r.unit===void 0)return parseFloat(r.num);let s=H4[r.unit];if(!s)throw new Error(`Invalid duration unit "${r.unit}"`);return parseFloat(r.num)*s/H4[e]}var nle,ile,sle,j4,ole,ale,M4,U4,_4,PB,rle,fle,H4,Gze,Pc=Xe(()=>{Dt();Yt();ql();nle=ut(Go()),ile=ut(Ld()),sle=ut(Ai()),j4=Ie("stream");ole=Symbol();Wl.skip=ole;ale=Symbol();p0.skip=ale;M4=class extends j4.Transform{constructor(){super(...arguments);this.chunks=[]}_transform(r,s,a){if(s!=="buffer"||!Buffer.isBuffer(r))throw new Error("Assertion failed: BufferStream only accept buffers");this.chunks.push(r),a(null,null)}_flush(r){r(null,Buffer.concat(this.chunks))}};U4=class{constructor(e){this.deferred=new Map;this.promises=new Map;this.limit=(0,ile.default)(e)}set(e,r){let s=this.deferred.get(e);typeof s>"u"&&this.deferred.set(e,s=lle());let a=this.limit(()=>r());return this.promises.set(e,a),a.then(()=>{this.promises.get(e)===a&&s.resolve()},n=>{this.promises.get(e)===a&&s.reject(n)}),s.promise}reduce(e,r){let s=this.promises.get(e)??Promise.resolve();this.set(e,()=>r(s))}async wait(){await Promise.all(this.promises.values())}},_4=class extends j4.Transform{constructor(r=Buffer.alloc(0)){super();this.active=!0;this.ifEmpty=r}_transform(r,s,a){if(s!=="buffer"||!Buffer.isBuffer(r))throw new Error("Assertion failed: DefaultStream only accept buffers");this.active=!1,a(null,r)}_flush(r){this.active&&this.ifEmpty.length>0?r(null,this.ifEmpty):r(null)}},PB=eval("require");rle=new Map;fle=(s=>(s[s.NoCache=0]="NoCache",s[s.FsTime=1]="FsTime",s[s.Node=2]="Node",s))(fle||{});H4={ms:1,s:1e3,m:60*1e3,h:60*60*1e3,d:24*60*60*1e3,w:7*24*60*60*1e3},Gze=new RegExp(`^(?\\d*\\.?\\d+)(?${Object.keys(H4).join("|")})?$`)});var VE,V4,J4,hle=Xe(()=>{VE=(r=>(r.HARD="HARD",r.SOFT="SOFT",r))(VE||{}),V4=(s=>(s.Dependency="Dependency",s.PeerDependency="PeerDependency",s.PeerDependencyMeta="PeerDependencyMeta",s))(V4||{}),J4=(s=>(s.Inactive="inactive",s.Redundant="redundant",s.Active="active",s))(J4||{})});var he={};Vt(he,{LogLevel:()=>eQ,Style:()=>Xk,Type:()=>ht,addLogFilterSupport:()=>RB,applyColor:()=>ri,applyHyperlink:()=>KE,applyStyle:()=>zd,json:()=>Xd,jsonOrPretty:()=>Yze,mark:()=>$4,pretty:()=>Ht,prettyField:()=>Kf,prettyList:()=>Z4,prettyTruncatedLocatorList:()=>$k,stripAnsi:()=>JE.default,supportsColor:()=>Zk,supportsHyperlinks:()=>X4,tuple:()=>_u});function gle(t){let e=["KiB","MiB","GiB","TiB"],r=e.length;for(;r>1&&t<1024**r;)r-=1;let s=1024**r;return`${Math.floor(t*100/s)/100} ${e[r-1]}`}function Kk(t,e){if(Array.isArray(e))return e.length===0?ri(t,"[]",ht.CODE):ri(t,"[ ",ht.CODE)+e.map(r=>Kk(t,r)).join(", ")+ri(t," ]",ht.CODE);if(typeof e=="string")return ri(t,JSON.stringify(e),ht.STRING);if(typeof e=="number")return ri(t,JSON.stringify(e),ht.NUMBER);if(typeof e=="boolean")return ri(t,JSON.stringify(e),ht.BOOLEAN);if(e===null)return ri(t,"null",ht.NULL);if(typeof e=="object"&&Object.getPrototypeOf(e)===Object.prototype){let r=Object.entries(e);return r.length===0?ri(t,"{}",ht.CODE):ri(t,"{ ",ht.CODE)+r.map(([s,a])=>`${Kk(t,s)}: ${Kk(t,a)}`).join(", ")+ri(t," }",ht.CODE)}if(typeof e>"u")return ri(t,"undefined",ht.NULL);throw new Error("Assertion failed: The value doesn't seem to be a valid JSON object")}function _u(t,e){return[e,t]}function zd(t,e,r){return t.get("enableColors")&&r&2&&(e=TB.default.bold(e)),e}function ri(t,e,r){if(!t.get("enableColors"))return e;let s=qze.get(r);if(s===null)return e;let a=typeof s>"u"?r:z4.level>=3?s[0]:s[1],n=typeof a=="number"?K4.ansi256(a):a.startsWith("#")?K4.hex(a):K4[a];if(typeof n!="function")throw new Error(`Invalid format type ${a}`);return n(e)}function KE(t,e,r){return t.get("enableHyperlinks")?Wze?`\x1B]8;;${r}\x1B\\${e}\x1B]8;;\x1B\\`:`\x1B]8;;${r}\x07${e}\x1B]8;;\x07`:e}function Ht(t,e,r){if(e===null)return ri(t,"null",ht.NULL);if(Object.hasOwn(zk,r))return zk[r].pretty(t,e);if(typeof e!="string")throw new Error(`Assertion failed: Expected the value to be a string, got ${typeof e}`);return ri(t,e,r)}function Z4(t,e,r,{separator:s=", "}={}){return[...e].map(a=>Ht(t,a,r)).join(s)}function Xd(t,e){if(t===null)return null;if(Object.hasOwn(zk,e))return zk[e].json(t);if(typeof t!="string")throw new Error(`Assertion failed: Expected the value to be a string, got ${typeof t}`);return t}function Yze(t,e,[r,s]){return t?Xd(r,s):Ht(e,r,s)}function $4(t){return{Check:ri(t,"\u2713","green"),Cross:ri(t,"\u2718","red"),Question:ri(t,"?","cyan")}}function Kf(t,{label:e,value:[r,s]}){return`${Ht(t,e,ht.CODE)}: ${Ht(t,r,s)}`}function $k(t,e,r){let s=[],a=[...e],n=r;for(;a.length>0;){let h=a[0],E=`${Yr(t,h)}, `,C=e3(h).length+2;if(s.length>0&&nh).join("").slice(0,-2);let c="X".repeat(a.length.toString().length),f=`and ${c} more.`,p=a.length;for(;s.length>1&&nh).join(""),f.replace(c,Ht(t,p,ht.NUMBER))].join("")}function RB(t,{configuration:e}){let r=e.get("logFilters"),s=new Map,a=new Map,n=[];for(let C of r){let S=C.get("level");if(typeof S>"u")continue;let P=C.get("code");typeof P<"u"&&s.set(P,S);let I=C.get("text");typeof I<"u"&&a.set(I,S);let R=C.get("pattern");typeof R<"u"&&n.push([dle.default.matcher(R,{contains:!0}),S])}n.reverse();let c=(C,S,P)=>{if(C===null||C===0)return P;let I=a.size>0||n.length>0?(0,JE.default)(S):S;if(a.size>0){let R=a.get(I);if(typeof R<"u")return R??P}if(n.length>0){for(let[R,N]of n)if(R(I))return N??P}if(s.size>0){let R=s.get(Yf(C));if(typeof R<"u")return R??P}return P},f=t.reportInfo,p=t.reportWarning,h=t.reportError,E=function(C,S,P,I){switch(c(S,P,I)){case"info":f.call(C,S,P);break;case"warning":p.call(C,S??0,P);break;case"error":h.call(C,S??0,P);break}};t.reportInfo=function(...C){return E(this,...C,"info")},t.reportWarning=function(...C){return E(this,...C,"warning")},t.reportError=function(...C){return E(this,...C,"error")}}var TB,QB,dle,JE,ht,Xk,z4,Zk,X4,K4,qze,qo,zk,Wze,eQ,xc=Xe(()=>{Dt();TB=ut(TE()),QB=ut(Fd());Yt();dle=ut(Go()),JE=ut(dk());Gx();Wo();ht={NO_HINT:"NO_HINT",ID:"ID",NULL:"NULL",SCOPE:"SCOPE",NAME:"NAME",RANGE:"RANGE",REFERENCE:"REFERENCE",NUMBER:"NUMBER",STRING:"STRING",BOOLEAN:"BOOLEAN",PATH:"PATH",URL:"URL",ADDED:"ADDED",REMOVED:"REMOVED",CODE:"CODE",INSPECT:"INSPECT",DURATION:"DURATION",SIZE:"SIZE",SIZE_DIFF:"SIZE_DIFF",IDENT:"IDENT",DESCRIPTOR:"DESCRIPTOR",LOCATOR:"LOCATOR",RESOLUTION:"RESOLUTION",DEPENDENT:"DEPENDENT",PACKAGE_EXTENSION:"PACKAGE_EXTENSION",SETTING:"SETTING",MARKDOWN:"MARKDOWN",MARKDOWN_INLINE:"MARKDOWN_INLINE"},Xk=(e=>(e[e.BOLD=2]="BOLD",e))(Xk||{}),z4=QB.default.GITHUB_ACTIONS?{level:2}:TB.default.supportsColor?{level:TB.default.supportsColor.level}:{level:0},Zk=z4.level!==0,X4=Zk&&!QB.default.GITHUB_ACTIONS&&!QB.default.CIRCLE&&!QB.default.GITLAB,K4=new TB.default.Instance(z4),qze=new Map([[ht.NO_HINT,null],[ht.NULL,["#a853b5",129]],[ht.SCOPE,["#d75f00",166]],[ht.NAME,["#d7875f",173]],[ht.RANGE,["#00afaf",37]],[ht.REFERENCE,["#87afff",111]],[ht.NUMBER,["#ffd700",220]],[ht.STRING,["#b4bd68",32]],[ht.BOOLEAN,["#faa023",209]],[ht.PATH,["#d75fd7",170]],[ht.URL,["#d75fd7",170]],[ht.ADDED,["#5faf00",70]],[ht.REMOVED,["#ff3131",160]],[ht.CODE,["#87afff",111]],[ht.SIZE,["#ffd700",220]]]),qo=t=>t;zk={[ht.ID]:qo({pretty:(t,e)=>typeof e=="number"?ri(t,`${e}`,ht.NUMBER):ri(t,e,ht.CODE),json:t=>t}),[ht.INSPECT]:qo({pretty:(t,e)=>Kk(t,e),json:t=>t}),[ht.NUMBER]:qo({pretty:(t,e)=>ri(t,`${e}`,ht.NUMBER),json:t=>t}),[ht.IDENT]:qo({pretty:(t,e)=>$i(t,e),json:t=>un(t)}),[ht.LOCATOR]:qo({pretty:(t,e)=>Yr(t,e),json:t=>ll(t)}),[ht.DESCRIPTOR]:qo({pretty:(t,e)=>ni(t,e),json:t=>al(t)}),[ht.RESOLUTION]:qo({pretty:(t,{descriptor:e,locator:r})=>FB(t,e,r),json:({descriptor:t,locator:e})=>({descriptor:al(t),locator:e!==null?ll(e):null})}),[ht.DEPENDENT]:qo({pretty:(t,{locator:e,descriptor:r})=>t3(t,e,r),json:({locator:t,descriptor:e})=>({locator:ll(t),descriptor:al(e)})}),[ht.PACKAGE_EXTENSION]:qo({pretty:(t,e)=>{switch(e.type){case"Dependency":return`${$i(t,e.parentDescriptor)} \u27A4 ${ri(t,"dependencies",ht.CODE)} \u27A4 ${$i(t,e.descriptor)}`;case"PeerDependency":return`${$i(t,e.parentDescriptor)} \u27A4 ${ri(t,"peerDependencies",ht.CODE)} \u27A4 ${$i(t,e.descriptor)}`;case"PeerDependencyMeta":return`${$i(t,e.parentDescriptor)} \u27A4 ${ri(t,"peerDependenciesMeta",ht.CODE)} \u27A4 ${$i(t,Sa(e.selector))} \u27A4 ${ri(t,e.key,ht.CODE)}`;default:throw new Error(`Assertion failed: Unsupported package extension type: ${e.type}`)}},json:t=>{switch(t.type){case"Dependency":return`${un(t.parentDescriptor)} > ${un(t.descriptor)}`;case"PeerDependency":return`${un(t.parentDescriptor)} >> ${un(t.descriptor)}`;case"PeerDependencyMeta":return`${un(t.parentDescriptor)} >> ${t.selector} / ${t.key}`;default:throw new Error(`Assertion failed: Unsupported package extension type: ${t.type}`)}}}),[ht.SETTING]:qo({pretty:(t,e)=>(t.get(e),KE(t,ri(t,e,ht.CODE),`https://yarnpkg.com/configuration/yarnrc#${e}`)),json:t=>t}),[ht.DURATION]:qo({pretty:(t,e)=>{if(e>1e3*60){let r=Math.floor(e/1e3/60),s=Math.ceil((e-r*60*1e3)/1e3);return s===0?`${r}m`:`${r}m ${s}s`}else{let r=Math.floor(e/1e3),s=e-r*1e3;return s===0?`${r}s`:`${r}s ${s}ms`}},json:t=>t}),[ht.SIZE]:qo({pretty:(t,e)=>ri(t,gle(e),ht.NUMBER),json:t=>t}),[ht.SIZE_DIFF]:qo({pretty:(t,e)=>{let r=e>=0?"+":"-",s=r==="+"?ht.REMOVED:ht.ADDED;return ri(t,`${r} ${gle(Math.max(Math.abs(e),1))}`,s)},json:t=>t}),[ht.PATH]:qo({pretty:(t,e)=>ri(t,fe.fromPortablePath(e),ht.PATH),json:t=>fe.fromPortablePath(t)}),[ht.MARKDOWN]:qo({pretty:(t,{text:e,format:r,paragraphs:s})=>Ho(e,{format:r,paragraphs:s}),json:({text:t})=>t}),[ht.MARKDOWN_INLINE]:qo({pretty:(t,e)=>(e=e.replace(/(`+)((?:.|[\n])*?)\1/g,(r,s,a)=>Ht(t,s+a+s,ht.CODE)),e=e.replace(/(\*\*)((?:.|[\n])*?)\1/g,(r,s,a)=>zd(t,a,2)),e),json:t=>t})};Wze=!!process.env.KONSOLE_VERSION;eQ=(a=>(a.Error="error",a.Warning="warning",a.Info="info",a.Discard="discard",a))(eQ||{})});var mle=_(zE=>{"use strict";Object.defineProperty(zE,"__esModule",{value:!0});zE.splitWhen=zE.flatten=void 0;function Vze(t){return t.reduce((e,r)=>[].concat(e,r),[])}zE.flatten=Vze;function Jze(t,e){let r=[[]],s=0;for(let a of t)e(a)?(s++,r[s]=[]):r[s].push(a);return r}zE.splitWhen=Jze});var yle=_(tQ=>{"use strict";Object.defineProperty(tQ,"__esModule",{value:!0});tQ.isEnoentCodeError=void 0;function Kze(t){return t.code==="ENOENT"}tQ.isEnoentCodeError=Kze});var Ele=_(rQ=>{"use strict";Object.defineProperty(rQ,"__esModule",{value:!0});rQ.createDirentFromStats=void 0;var r3=class{constructor(e,r){this.name=e,this.isBlockDevice=r.isBlockDevice.bind(r),this.isCharacterDevice=r.isCharacterDevice.bind(r),this.isDirectory=r.isDirectory.bind(r),this.isFIFO=r.isFIFO.bind(r),this.isFile=r.isFile.bind(r),this.isSocket=r.isSocket.bind(r),this.isSymbolicLink=r.isSymbolicLink.bind(r)}};function zze(t,e){return new r3(t,e)}rQ.createDirentFromStats=zze});var Ble=_(cs=>{"use strict";Object.defineProperty(cs,"__esModule",{value:!0});cs.convertPosixPathToPattern=cs.convertWindowsPathToPattern=cs.convertPathToPattern=cs.escapePosixPath=cs.escapeWindowsPath=cs.escape=cs.removeLeadingDotSegment=cs.makeAbsolute=cs.unixify=void 0;var Xze=Ie("os"),Zze=Ie("path"),Ile=Xze.platform()==="win32",$ze=2,eXe=/(\\?)([()*?[\]{|}]|^!|[!+@](?=\()|\\(?![!()*+?@[\]{|}]))/g,tXe=/(\\?)([()[\]{}]|^!|[!+@](?=\())/g,rXe=/^\\\\([.?])/,nXe=/\\(?![!()+@[\]{}])/g;function iXe(t){return t.replace(/\\/g,"/")}cs.unixify=iXe;function sXe(t,e){return Zze.resolve(t,e)}cs.makeAbsolute=sXe;function oXe(t){if(t.charAt(0)==="."){let e=t.charAt(1);if(e==="/"||e==="\\")return t.slice($ze)}return t}cs.removeLeadingDotSegment=oXe;cs.escape=Ile?n3:i3;function n3(t){return t.replace(tXe,"\\$2")}cs.escapeWindowsPath=n3;function i3(t){return t.replace(eXe,"\\$2")}cs.escapePosixPath=i3;cs.convertPathToPattern=Ile?Cle:wle;function Cle(t){return n3(t).replace(rXe,"//$1").replace(nXe,"/")}cs.convertWindowsPathToPattern=Cle;function wle(t){return i3(t)}cs.convertPosixPathToPattern=wle});var Sle=_((JOt,vle)=>{vle.exports=function(e){if(typeof e!="string"||e==="")return!1;for(var r;r=/(\\).|([@?!+*]\(.*\))/g.exec(e);){if(r[2])return!0;e=e.slice(r.index+r[0].length)}return!1}});var Ple=_((KOt,ble)=>{var aXe=Sle(),Dle={"{":"}","(":")","[":"]"},lXe=function(t){if(t[0]==="!")return!0;for(var e=0,r=-2,s=-2,a=-2,n=-2,c=-2;ee&&(c===-1||c>s||(c=t.indexOf("\\",e),c===-1||c>s)))||a!==-1&&t[e]==="{"&&t[e+1]!=="}"&&(a=t.indexOf("}",e),a>e&&(c=t.indexOf("\\",e),c===-1||c>a))||n!==-1&&t[e]==="("&&t[e+1]==="?"&&/[:!=]/.test(t[e+2])&&t[e+3]!==")"&&(n=t.indexOf(")",e),n>e&&(c=t.indexOf("\\",e),c===-1||c>n))||r!==-1&&t[e]==="("&&t[e+1]!=="|"&&(rr&&(c=t.indexOf("\\",r),c===-1||c>n))))return!0;if(t[e]==="\\"){var f=t[e+1];e+=2;var p=Dle[f];if(p){var h=t.indexOf(p,e);h!==-1&&(e=h+1)}if(t[e]==="!")return!0}else e++}return!1},cXe=function(t){if(t[0]==="!")return!0;for(var e=0;e{"use strict";var uXe=Ple(),fXe=Ie("path").posix.dirname,AXe=Ie("os").platform()==="win32",s3="/",pXe=/\\/g,hXe=/[\{\[].*[\}\]]$/,gXe=/(^|[^\\])([\{\[]|\([^\)]+$)/,dXe=/\\([\!\*\?\|\[\]\(\)\{\}])/g;xle.exports=function(e,r){var s=Object.assign({flipBackslashes:!0},r);s.flipBackslashes&&AXe&&e.indexOf(s3)<0&&(e=e.replace(pXe,s3)),hXe.test(e)&&(e+=s3),e+="a";do e=fXe(e);while(uXe(e)||gXe.test(e));return e.replace(dXe,"$1")}});var Mle=_(jr=>{"use strict";Object.defineProperty(jr,"__esModule",{value:!0});jr.removeDuplicateSlashes=jr.matchAny=jr.convertPatternsToRe=jr.makeRe=jr.getPatternParts=jr.expandBraceExpansion=jr.expandPatternsWithBraceExpansion=jr.isAffectDepthOfReadingPattern=jr.endsWithSlashGlobStar=jr.hasGlobStar=jr.getBaseDirectory=jr.isPatternRelatedToParentDirectory=jr.getPatternsOutsideCurrentDirectory=jr.getPatternsInsideCurrentDirectory=jr.getPositivePatterns=jr.getNegativePatterns=jr.isPositivePattern=jr.isNegativePattern=jr.convertToNegativePattern=jr.convertToPositivePattern=jr.isDynamicPattern=jr.isStaticPattern=void 0;var mXe=Ie("path"),yXe=kle(),o3=Go(),Qle="**",EXe="\\",IXe=/[*?]|^!/,CXe=/\[[^[]*]/,wXe=/(?:^|[^!*+?@])\([^(]*\|[^|]*\)/,BXe=/[!*+?@]\([^(]*\)/,vXe=/,|\.\./,SXe=/(?!^)\/{2,}/g;function Tle(t,e={}){return!Rle(t,e)}jr.isStaticPattern=Tle;function Rle(t,e={}){return t===""?!1:!!(e.caseSensitiveMatch===!1||t.includes(EXe)||IXe.test(t)||CXe.test(t)||wXe.test(t)||e.extglob!==!1&&BXe.test(t)||e.braceExpansion!==!1&&DXe(t))}jr.isDynamicPattern=Rle;function DXe(t){let e=t.indexOf("{");if(e===-1)return!1;let r=t.indexOf("}",e+1);if(r===-1)return!1;let s=t.slice(e,r);return vXe.test(s)}function bXe(t){return nQ(t)?t.slice(1):t}jr.convertToPositivePattern=bXe;function PXe(t){return"!"+t}jr.convertToNegativePattern=PXe;function nQ(t){return t.startsWith("!")&&t[1]!=="("}jr.isNegativePattern=nQ;function Fle(t){return!nQ(t)}jr.isPositivePattern=Fle;function xXe(t){return t.filter(nQ)}jr.getNegativePatterns=xXe;function kXe(t){return t.filter(Fle)}jr.getPositivePatterns=kXe;function QXe(t){return t.filter(e=>!a3(e))}jr.getPatternsInsideCurrentDirectory=QXe;function TXe(t){return t.filter(a3)}jr.getPatternsOutsideCurrentDirectory=TXe;function a3(t){return t.startsWith("..")||t.startsWith("./..")}jr.isPatternRelatedToParentDirectory=a3;function RXe(t){return yXe(t,{flipBackslashes:!1})}jr.getBaseDirectory=RXe;function FXe(t){return t.includes(Qle)}jr.hasGlobStar=FXe;function Nle(t){return t.endsWith("/"+Qle)}jr.endsWithSlashGlobStar=Nle;function NXe(t){let e=mXe.basename(t);return Nle(t)||Tle(e)}jr.isAffectDepthOfReadingPattern=NXe;function OXe(t){return t.reduce((e,r)=>e.concat(Ole(r)),[])}jr.expandPatternsWithBraceExpansion=OXe;function Ole(t){let e=o3.braces(t,{expand:!0,nodupes:!0,keepEscaping:!0});return e.sort((r,s)=>r.length-s.length),e.filter(r=>r!=="")}jr.expandBraceExpansion=Ole;function LXe(t,e){let{parts:r}=o3.scan(t,Object.assign(Object.assign({},e),{parts:!0}));return r.length===0&&(r=[t]),r[0].startsWith("/")&&(r[0]=r[0].slice(1),r.unshift("")),r}jr.getPatternParts=LXe;function Lle(t,e){return o3.makeRe(t,e)}jr.makeRe=Lle;function MXe(t,e){return t.map(r=>Lle(r,e))}jr.convertPatternsToRe=MXe;function UXe(t,e){return e.some(r=>r.test(t))}jr.matchAny=UXe;function _Xe(t){return t.replace(SXe,"/")}jr.removeDuplicateSlashes=_Xe});var jle=_((ZOt,Hle)=>{"use strict";var HXe=Ie("stream"),Ule=HXe.PassThrough,jXe=Array.prototype.slice;Hle.exports=GXe;function GXe(){let t=[],e=jXe.call(arguments),r=!1,s=e[e.length-1];s&&!Array.isArray(s)&&s.pipe==null?e.pop():s={};let a=s.end!==!1,n=s.pipeError===!0;s.objectMode==null&&(s.objectMode=!0),s.highWaterMark==null&&(s.highWaterMark=64*1024);let c=Ule(s);function f(){for(let E=0,C=arguments.length;E0||(r=!1,p())}function P(I){function R(){I.removeListener("merge2UnpipeEnd",R),I.removeListener("end",R),n&&I.removeListener("error",N),S()}function N(U){c.emit("error",U)}if(I._readableState.endEmitted)return S();I.on("merge2UnpipeEnd",R),I.on("end",R),n&&I.on("error",N),I.pipe(c,{end:!1}),I.resume()}for(let I=0;I{"use strict";Object.defineProperty(iQ,"__esModule",{value:!0});iQ.merge=void 0;var qXe=jle();function WXe(t){let e=qXe(t);return t.forEach(r=>{r.once("error",s=>e.emit("error",s))}),e.once("close",()=>Gle(t)),e.once("end",()=>Gle(t)),e}iQ.merge=WXe;function Gle(t){t.forEach(e=>e.emit("close"))}});var Wle=_(XE=>{"use strict";Object.defineProperty(XE,"__esModule",{value:!0});XE.isEmpty=XE.isString=void 0;function YXe(t){return typeof t=="string"}XE.isString=YXe;function VXe(t){return t===""}XE.isEmpty=VXe});var xp=_(Yo=>{"use strict";Object.defineProperty(Yo,"__esModule",{value:!0});Yo.string=Yo.stream=Yo.pattern=Yo.path=Yo.fs=Yo.errno=Yo.array=void 0;var JXe=mle();Yo.array=JXe;var KXe=yle();Yo.errno=KXe;var zXe=Ele();Yo.fs=zXe;var XXe=Ble();Yo.path=XXe;var ZXe=Mle();Yo.pattern=ZXe;var $Xe=qle();Yo.stream=$Xe;var eZe=Wle();Yo.string=eZe});var Kle=_(Vo=>{"use strict";Object.defineProperty(Vo,"__esModule",{value:!0});Vo.convertPatternGroupToTask=Vo.convertPatternGroupsToTasks=Vo.groupPatternsByBaseDirectory=Vo.getNegativePatternsAsPositive=Vo.getPositivePatterns=Vo.convertPatternsToTasks=Vo.generate=void 0;var Hu=xp();function tZe(t,e){let r=Yle(t,e),s=Yle(e.ignore,e),a=Vle(r),n=Jle(r,s),c=a.filter(E=>Hu.pattern.isStaticPattern(E,e)),f=a.filter(E=>Hu.pattern.isDynamicPattern(E,e)),p=l3(c,n,!1),h=l3(f,n,!0);return p.concat(h)}Vo.generate=tZe;function Yle(t,e){let r=t;return e.braceExpansion&&(r=Hu.pattern.expandPatternsWithBraceExpansion(r)),e.baseNameMatch&&(r=r.map(s=>s.includes("/")?s:`**/${s}`)),r.map(s=>Hu.pattern.removeDuplicateSlashes(s))}function l3(t,e,r){let s=[],a=Hu.pattern.getPatternsOutsideCurrentDirectory(t),n=Hu.pattern.getPatternsInsideCurrentDirectory(t),c=c3(a),f=c3(n);return s.push(...u3(c,e,r)),"."in f?s.push(f3(".",n,e,r)):s.push(...u3(f,e,r)),s}Vo.convertPatternsToTasks=l3;function Vle(t){return Hu.pattern.getPositivePatterns(t)}Vo.getPositivePatterns=Vle;function Jle(t,e){return Hu.pattern.getNegativePatterns(t).concat(e).map(Hu.pattern.convertToPositivePattern)}Vo.getNegativePatternsAsPositive=Jle;function c3(t){let e={};return t.reduce((r,s)=>{let a=Hu.pattern.getBaseDirectory(s);return a in r?r[a].push(s):r[a]=[s],r},e)}Vo.groupPatternsByBaseDirectory=c3;function u3(t,e,r){return Object.keys(t).map(s=>f3(s,t[s],e,r))}Vo.convertPatternGroupsToTasks=u3;function f3(t,e,r,s){return{dynamic:s,positive:e,negative:r,base:t,patterns:[].concat(e,r.map(Hu.pattern.convertToNegativePattern))}}Vo.convertPatternGroupToTask=f3});var Xle=_(sQ=>{"use strict";Object.defineProperty(sQ,"__esModule",{value:!0});sQ.read=void 0;function rZe(t,e,r){e.fs.lstat(t,(s,a)=>{if(s!==null){zle(r,s);return}if(!a.isSymbolicLink()||!e.followSymbolicLink){A3(r,a);return}e.fs.stat(t,(n,c)=>{if(n!==null){if(e.throwErrorOnBrokenSymbolicLink){zle(r,n);return}A3(r,a);return}e.markSymbolicLink&&(c.isSymbolicLink=()=>!0),A3(r,c)})})}sQ.read=rZe;function zle(t,e){t(e)}function A3(t,e){t(null,e)}});var Zle=_(oQ=>{"use strict";Object.defineProperty(oQ,"__esModule",{value:!0});oQ.read=void 0;function nZe(t,e){let r=e.fs.lstatSync(t);if(!r.isSymbolicLink()||!e.followSymbolicLink)return r;try{let s=e.fs.statSync(t);return e.markSymbolicLink&&(s.isSymbolicLink=()=>!0),s}catch(s){if(!e.throwErrorOnBrokenSymbolicLink)return r;throw s}}oQ.read=nZe});var $le=_(h0=>{"use strict";Object.defineProperty(h0,"__esModule",{value:!0});h0.createFileSystemAdapter=h0.FILE_SYSTEM_ADAPTER=void 0;var aQ=Ie("fs");h0.FILE_SYSTEM_ADAPTER={lstat:aQ.lstat,stat:aQ.stat,lstatSync:aQ.lstatSync,statSync:aQ.statSync};function iZe(t){return t===void 0?h0.FILE_SYSTEM_ADAPTER:Object.assign(Object.assign({},h0.FILE_SYSTEM_ADAPTER),t)}h0.createFileSystemAdapter=iZe});var ece=_(h3=>{"use strict";Object.defineProperty(h3,"__esModule",{value:!0});var sZe=$le(),p3=class{constructor(e={}){this._options=e,this.followSymbolicLink=this._getValue(this._options.followSymbolicLink,!0),this.fs=sZe.createFileSystemAdapter(this._options.fs),this.markSymbolicLink=this._getValue(this._options.markSymbolicLink,!1),this.throwErrorOnBrokenSymbolicLink=this._getValue(this._options.throwErrorOnBrokenSymbolicLink,!0)}_getValue(e,r){return e??r}};h3.default=p3});var Zd=_(g0=>{"use strict";Object.defineProperty(g0,"__esModule",{value:!0});g0.statSync=g0.stat=g0.Settings=void 0;var tce=Xle(),oZe=Zle(),g3=ece();g0.Settings=g3.default;function aZe(t,e,r){if(typeof e=="function"){tce.read(t,d3(),e);return}tce.read(t,d3(e),r)}g0.stat=aZe;function lZe(t,e){let r=d3(e);return oZe.read(t,r)}g0.statSync=lZe;function d3(t={}){return t instanceof g3.default?t:new g3.default(t)}});var ice=_((lLt,nce)=>{var rce;nce.exports=typeof queueMicrotask=="function"?queueMicrotask.bind(typeof window<"u"?window:global):t=>(rce||(rce=Promise.resolve())).then(t).catch(e=>setTimeout(()=>{throw e},0))});var oce=_((cLt,sce)=>{sce.exports=uZe;var cZe=ice();function uZe(t,e){let r,s,a,n=!0;Array.isArray(t)?(r=[],s=t.length):(a=Object.keys(t),r={},s=a.length);function c(p){function h(){e&&e(p,r),e=null}n?cZe(h):h()}function f(p,h,E){r[p]=E,(--s===0||h)&&c(h)}s?a?a.forEach(function(p){t[p](function(h,E){f(p,h,E)})}):t.forEach(function(p,h){p(function(E,C){f(h,E,C)})}):c(null),n=!1}});var m3=_(cQ=>{"use strict";Object.defineProperty(cQ,"__esModule",{value:!0});cQ.IS_SUPPORT_READDIR_WITH_FILE_TYPES=void 0;var lQ=process.versions.node.split(".");if(lQ[0]===void 0||lQ[1]===void 0)throw new Error(`Unexpected behavior. The 'process.versions.node' variable has invalid value: ${process.versions.node}`);var ace=Number.parseInt(lQ[0],10),fZe=Number.parseInt(lQ[1],10),lce=10,AZe=10,pZe=ace>lce,hZe=ace===lce&&fZe>=AZe;cQ.IS_SUPPORT_READDIR_WITH_FILE_TYPES=pZe||hZe});var cce=_(uQ=>{"use strict";Object.defineProperty(uQ,"__esModule",{value:!0});uQ.createDirentFromStats=void 0;var y3=class{constructor(e,r){this.name=e,this.isBlockDevice=r.isBlockDevice.bind(r),this.isCharacterDevice=r.isCharacterDevice.bind(r),this.isDirectory=r.isDirectory.bind(r),this.isFIFO=r.isFIFO.bind(r),this.isFile=r.isFile.bind(r),this.isSocket=r.isSocket.bind(r),this.isSymbolicLink=r.isSymbolicLink.bind(r)}};function gZe(t,e){return new y3(t,e)}uQ.createDirentFromStats=gZe});var E3=_(fQ=>{"use strict";Object.defineProperty(fQ,"__esModule",{value:!0});fQ.fs=void 0;var dZe=cce();fQ.fs=dZe});var I3=_(AQ=>{"use strict";Object.defineProperty(AQ,"__esModule",{value:!0});AQ.joinPathSegments=void 0;function mZe(t,e,r){return t.endsWith(r)?t+e:t+r+e}AQ.joinPathSegments=mZe});var gce=_(d0=>{"use strict";Object.defineProperty(d0,"__esModule",{value:!0});d0.readdir=d0.readdirWithFileTypes=d0.read=void 0;var yZe=Zd(),uce=oce(),EZe=m3(),fce=E3(),Ace=I3();function IZe(t,e,r){if(!e.stats&&EZe.IS_SUPPORT_READDIR_WITH_FILE_TYPES){pce(t,e,r);return}hce(t,e,r)}d0.read=IZe;function pce(t,e,r){e.fs.readdir(t,{withFileTypes:!0},(s,a)=>{if(s!==null){pQ(r,s);return}let n=a.map(f=>({dirent:f,name:f.name,path:Ace.joinPathSegments(t,f.name,e.pathSegmentSeparator)}));if(!e.followSymbolicLinks){C3(r,n);return}let c=n.map(f=>CZe(f,e));uce(c,(f,p)=>{if(f!==null){pQ(r,f);return}C3(r,p)})})}d0.readdirWithFileTypes=pce;function CZe(t,e){return r=>{if(!t.dirent.isSymbolicLink()){r(null,t);return}e.fs.stat(t.path,(s,a)=>{if(s!==null){if(e.throwErrorOnBrokenSymbolicLink){r(s);return}r(null,t);return}t.dirent=fce.fs.createDirentFromStats(t.name,a),r(null,t)})}}function hce(t,e,r){e.fs.readdir(t,(s,a)=>{if(s!==null){pQ(r,s);return}let n=a.map(c=>{let f=Ace.joinPathSegments(t,c,e.pathSegmentSeparator);return p=>{yZe.stat(f,e.fsStatSettings,(h,E)=>{if(h!==null){p(h);return}let C={name:c,path:f,dirent:fce.fs.createDirentFromStats(c,E)};e.stats&&(C.stats=E),p(null,C)})}});uce(n,(c,f)=>{if(c!==null){pQ(r,c);return}C3(r,f)})})}d0.readdir=hce;function pQ(t,e){t(e)}function C3(t,e){t(null,e)}});var Ice=_(m0=>{"use strict";Object.defineProperty(m0,"__esModule",{value:!0});m0.readdir=m0.readdirWithFileTypes=m0.read=void 0;var wZe=Zd(),BZe=m3(),dce=E3(),mce=I3();function vZe(t,e){return!e.stats&&BZe.IS_SUPPORT_READDIR_WITH_FILE_TYPES?yce(t,e):Ece(t,e)}m0.read=vZe;function yce(t,e){return e.fs.readdirSync(t,{withFileTypes:!0}).map(s=>{let a={dirent:s,name:s.name,path:mce.joinPathSegments(t,s.name,e.pathSegmentSeparator)};if(a.dirent.isSymbolicLink()&&e.followSymbolicLinks)try{let n=e.fs.statSync(a.path);a.dirent=dce.fs.createDirentFromStats(a.name,n)}catch(n){if(e.throwErrorOnBrokenSymbolicLink)throw n}return a})}m0.readdirWithFileTypes=yce;function Ece(t,e){return e.fs.readdirSync(t).map(s=>{let a=mce.joinPathSegments(t,s,e.pathSegmentSeparator),n=wZe.statSync(a,e.fsStatSettings),c={name:s,path:a,dirent:dce.fs.createDirentFromStats(s,n)};return e.stats&&(c.stats=n),c})}m0.readdir=Ece});var Cce=_(y0=>{"use strict";Object.defineProperty(y0,"__esModule",{value:!0});y0.createFileSystemAdapter=y0.FILE_SYSTEM_ADAPTER=void 0;var ZE=Ie("fs");y0.FILE_SYSTEM_ADAPTER={lstat:ZE.lstat,stat:ZE.stat,lstatSync:ZE.lstatSync,statSync:ZE.statSync,readdir:ZE.readdir,readdirSync:ZE.readdirSync};function SZe(t){return t===void 0?y0.FILE_SYSTEM_ADAPTER:Object.assign(Object.assign({},y0.FILE_SYSTEM_ADAPTER),t)}y0.createFileSystemAdapter=SZe});var wce=_(B3=>{"use strict";Object.defineProperty(B3,"__esModule",{value:!0});var DZe=Ie("path"),bZe=Zd(),PZe=Cce(),w3=class{constructor(e={}){this._options=e,this.followSymbolicLinks=this._getValue(this._options.followSymbolicLinks,!1),this.fs=PZe.createFileSystemAdapter(this._options.fs),this.pathSegmentSeparator=this._getValue(this._options.pathSegmentSeparator,DZe.sep),this.stats=this._getValue(this._options.stats,!1),this.throwErrorOnBrokenSymbolicLink=this._getValue(this._options.throwErrorOnBrokenSymbolicLink,!0),this.fsStatSettings=new bZe.Settings({followSymbolicLink:this.followSymbolicLinks,fs:this.fs,throwErrorOnBrokenSymbolicLink:this.throwErrorOnBrokenSymbolicLink})}_getValue(e,r){return e??r}};B3.default=w3});var hQ=_(E0=>{"use strict";Object.defineProperty(E0,"__esModule",{value:!0});E0.Settings=E0.scandirSync=E0.scandir=void 0;var Bce=gce(),xZe=Ice(),v3=wce();E0.Settings=v3.default;function kZe(t,e,r){if(typeof e=="function"){Bce.read(t,S3(),e);return}Bce.read(t,S3(e),r)}E0.scandir=kZe;function QZe(t,e){let r=S3(e);return xZe.read(t,r)}E0.scandirSync=QZe;function S3(t={}){return t instanceof v3.default?t:new v3.default(t)}});var Sce=_((ELt,vce)=>{"use strict";function TZe(t){var e=new t,r=e;function s(){var n=e;return n.next?e=n.next:(e=new t,r=e),n.next=null,n}function a(n){r.next=n,r=n}return{get:s,release:a}}vce.exports=TZe});var bce=_((ILt,D3)=>{"use strict";var RZe=Sce();function Dce(t,e,r){if(typeof t=="function"&&(r=e,e=t,t=null),!(r>=1))throw new Error("fastqueue concurrency must be equal to or greater than 1");var s=RZe(FZe),a=null,n=null,c=0,f=null,p={push:R,drain:kc,saturated:kc,pause:E,paused:!1,get concurrency(){return r},set concurrency(ue){if(!(ue>=1))throw new Error("fastqueue concurrency must be equal to or greater than 1");if(r=ue,!p.paused)for(;a&&c=r||p.paused?n?(n.next=me,n=me):(a=me,n=me,p.saturated()):(c++,e.call(t,me.value,me.worked))}function N(ue,le){var me=s.get();me.context=t,me.release=U,me.value=ue,me.callback=le||kc,me.errorHandler=f,c>=r||p.paused?a?(me.next=a,a=me):(a=me,n=me,p.saturated()):(c++,e.call(t,me.value,me.worked))}function U(ue){ue&&s.release(ue);var le=a;le&&c<=r?p.paused?c--:(n===a&&(n=null),a=le.next,le.next=null,e.call(t,le.value,le.worked),n===null&&p.empty()):--c===0&&p.drain()}function W(){a=null,n=null,p.drain=kc}function ee(){a=null,n=null,p.drain(),p.drain=kc}function ie(ue){f=ue}}function kc(){}function FZe(){this.value=null,this.callback=kc,this.next=null,this.release=kc,this.context=null,this.errorHandler=null;var t=this;this.worked=function(r,s){var a=t.callback,n=t.errorHandler,c=t.value;t.value=null,t.callback=kc,t.errorHandler&&n(r,c),a.call(t.context,r,s),t.release(t)}}function NZe(t,e,r){typeof t=="function"&&(r=e,e=t,t=null);function s(E,C){e.call(this,E).then(function(S){C(null,S)},C)}var a=Dce(t,s,r),n=a.push,c=a.unshift;return a.push=f,a.unshift=p,a.drained=h,a;function f(E){var C=new Promise(function(S,P){n(E,function(I,R){if(I){P(I);return}S(R)})});return C.catch(kc),C}function p(E){var C=new Promise(function(S,P){c(E,function(I,R){if(I){P(I);return}S(R)})});return C.catch(kc),C}function h(){if(a.idle())return new Promise(function(S){S()});var E=a.drain,C=new Promise(function(S){a.drain=function(){E(),S()}});return C}}D3.exports=Dce;D3.exports.promise=NZe});var gQ=_(zf=>{"use strict";Object.defineProperty(zf,"__esModule",{value:!0});zf.joinPathSegments=zf.replacePathSegmentSeparator=zf.isAppliedFilter=zf.isFatalError=void 0;function OZe(t,e){return t.errorFilter===null?!0:!t.errorFilter(e)}zf.isFatalError=OZe;function LZe(t,e){return t===null||t(e)}zf.isAppliedFilter=LZe;function MZe(t,e){return t.split(/[/\\]/).join(e)}zf.replacePathSegmentSeparator=MZe;function UZe(t,e,r){return t===""?e:t.endsWith(r)?t+e:t+r+e}zf.joinPathSegments=UZe});var x3=_(P3=>{"use strict";Object.defineProperty(P3,"__esModule",{value:!0});var _Ze=gQ(),b3=class{constructor(e,r){this._root=e,this._settings=r,this._root=_Ze.replacePathSegmentSeparator(e,r.pathSegmentSeparator)}};P3.default=b3});var T3=_(Q3=>{"use strict";Object.defineProperty(Q3,"__esModule",{value:!0});var HZe=Ie("events"),jZe=hQ(),GZe=bce(),dQ=gQ(),qZe=x3(),k3=class extends qZe.default{constructor(e,r){super(e,r),this._settings=r,this._scandir=jZe.scandir,this._emitter=new HZe.EventEmitter,this._queue=GZe(this._worker.bind(this),this._settings.concurrency),this._isFatalError=!1,this._isDestroyed=!1,this._queue.drain=()=>{this._isFatalError||this._emitter.emit("end")}}read(){return this._isFatalError=!1,this._isDestroyed=!1,setImmediate(()=>{this._pushToQueue(this._root,this._settings.basePath)}),this._emitter}get isDestroyed(){return this._isDestroyed}destroy(){if(this._isDestroyed)throw new Error("The reader is already destroyed");this._isDestroyed=!0,this._queue.killAndDrain()}onEntry(e){this._emitter.on("entry",e)}onError(e){this._emitter.once("error",e)}onEnd(e){this._emitter.once("end",e)}_pushToQueue(e,r){let s={directory:e,base:r};this._queue.push(s,a=>{a!==null&&this._handleError(a)})}_worker(e,r){this._scandir(e.directory,this._settings.fsScandirSettings,(s,a)=>{if(s!==null){r(s,void 0);return}for(let n of a)this._handleEntry(n,e.base);r(null,void 0)})}_handleError(e){this._isDestroyed||!dQ.isFatalError(this._settings,e)||(this._isFatalError=!0,this._isDestroyed=!0,this._emitter.emit("error",e))}_handleEntry(e,r){if(this._isDestroyed||this._isFatalError)return;let s=e.path;r!==void 0&&(e.path=dQ.joinPathSegments(r,e.name,this._settings.pathSegmentSeparator)),dQ.isAppliedFilter(this._settings.entryFilter,e)&&this._emitEntry(e),e.dirent.isDirectory()&&dQ.isAppliedFilter(this._settings.deepFilter,e)&&this._pushToQueue(s,r===void 0?void 0:e.path)}_emitEntry(e){this._emitter.emit("entry",e)}};Q3.default=k3});var Pce=_(F3=>{"use strict";Object.defineProperty(F3,"__esModule",{value:!0});var WZe=T3(),R3=class{constructor(e,r){this._root=e,this._settings=r,this._reader=new WZe.default(this._root,this._settings),this._storage=[]}read(e){this._reader.onError(r=>{YZe(e,r)}),this._reader.onEntry(r=>{this._storage.push(r)}),this._reader.onEnd(()=>{VZe(e,this._storage)}),this._reader.read()}};F3.default=R3;function YZe(t,e){t(e)}function VZe(t,e){t(null,e)}});var xce=_(O3=>{"use strict";Object.defineProperty(O3,"__esModule",{value:!0});var JZe=Ie("stream"),KZe=T3(),N3=class{constructor(e,r){this._root=e,this._settings=r,this._reader=new KZe.default(this._root,this._settings),this._stream=new JZe.Readable({objectMode:!0,read:()=>{},destroy:()=>{this._reader.isDestroyed||this._reader.destroy()}})}read(){return this._reader.onError(e=>{this._stream.emit("error",e)}),this._reader.onEntry(e=>{this._stream.push(e)}),this._reader.onEnd(()=>{this._stream.push(null)}),this._reader.read(),this._stream}};O3.default=N3});var kce=_(M3=>{"use strict";Object.defineProperty(M3,"__esModule",{value:!0});var zZe=hQ(),mQ=gQ(),XZe=x3(),L3=class extends XZe.default{constructor(){super(...arguments),this._scandir=zZe.scandirSync,this._storage=[],this._queue=new Set}read(){return this._pushToQueue(this._root,this._settings.basePath),this._handleQueue(),this._storage}_pushToQueue(e,r){this._queue.add({directory:e,base:r})}_handleQueue(){for(let e of this._queue.values())this._handleDirectory(e.directory,e.base)}_handleDirectory(e,r){try{let s=this._scandir(e,this._settings.fsScandirSettings);for(let a of s)this._handleEntry(a,r)}catch(s){this._handleError(s)}}_handleError(e){if(mQ.isFatalError(this._settings,e))throw e}_handleEntry(e,r){let s=e.path;r!==void 0&&(e.path=mQ.joinPathSegments(r,e.name,this._settings.pathSegmentSeparator)),mQ.isAppliedFilter(this._settings.entryFilter,e)&&this._pushToStorage(e),e.dirent.isDirectory()&&mQ.isAppliedFilter(this._settings.deepFilter,e)&&this._pushToQueue(s,r===void 0?void 0:e.path)}_pushToStorage(e){this._storage.push(e)}};M3.default=L3});var Qce=_(_3=>{"use strict";Object.defineProperty(_3,"__esModule",{value:!0});var ZZe=kce(),U3=class{constructor(e,r){this._root=e,this._settings=r,this._reader=new ZZe.default(this._root,this._settings)}read(){return this._reader.read()}};_3.default=U3});var Tce=_(j3=>{"use strict";Object.defineProperty(j3,"__esModule",{value:!0});var $Ze=Ie("path"),e$e=hQ(),H3=class{constructor(e={}){this._options=e,this.basePath=this._getValue(this._options.basePath,void 0),this.concurrency=this._getValue(this._options.concurrency,Number.POSITIVE_INFINITY),this.deepFilter=this._getValue(this._options.deepFilter,null),this.entryFilter=this._getValue(this._options.entryFilter,null),this.errorFilter=this._getValue(this._options.errorFilter,null),this.pathSegmentSeparator=this._getValue(this._options.pathSegmentSeparator,$Ze.sep),this.fsScandirSettings=new e$e.Settings({followSymbolicLinks:this._options.followSymbolicLinks,fs:this._options.fs,pathSegmentSeparator:this._options.pathSegmentSeparator,stats:this._options.stats,throwErrorOnBrokenSymbolicLink:this._options.throwErrorOnBrokenSymbolicLink})}_getValue(e,r){return e??r}};j3.default=H3});var EQ=_(Xf=>{"use strict";Object.defineProperty(Xf,"__esModule",{value:!0});Xf.Settings=Xf.walkStream=Xf.walkSync=Xf.walk=void 0;var Rce=Pce(),t$e=xce(),r$e=Qce(),G3=Tce();Xf.Settings=G3.default;function n$e(t,e,r){if(typeof e=="function"){new Rce.default(t,yQ()).read(e);return}new Rce.default(t,yQ(e)).read(r)}Xf.walk=n$e;function i$e(t,e){let r=yQ(e);return new r$e.default(t,r).read()}Xf.walkSync=i$e;function s$e(t,e){let r=yQ(e);return new t$e.default(t,r).read()}Xf.walkStream=s$e;function yQ(t={}){return t instanceof G3.default?t:new G3.default(t)}});var IQ=_(W3=>{"use strict";Object.defineProperty(W3,"__esModule",{value:!0});var o$e=Ie("path"),a$e=Zd(),Fce=xp(),q3=class{constructor(e){this._settings=e,this._fsStatSettings=new a$e.Settings({followSymbolicLink:this._settings.followSymbolicLinks,fs:this._settings.fs,throwErrorOnBrokenSymbolicLink:this._settings.followSymbolicLinks})}_getFullEntryPath(e){return o$e.resolve(this._settings.cwd,e)}_makeEntry(e,r){let s={name:r,path:r,dirent:Fce.fs.createDirentFromStats(r,e)};return this._settings.stats&&(s.stats=e),s}_isFatalError(e){return!Fce.errno.isEnoentCodeError(e)&&!this._settings.suppressErrors}};W3.default=q3});var J3=_(V3=>{"use strict";Object.defineProperty(V3,"__esModule",{value:!0});var l$e=Ie("stream"),c$e=Zd(),u$e=EQ(),f$e=IQ(),Y3=class extends f$e.default{constructor(){super(...arguments),this._walkStream=u$e.walkStream,this._stat=c$e.stat}dynamic(e,r){return this._walkStream(e,r)}static(e,r){let s=e.map(this._getFullEntryPath,this),a=new l$e.PassThrough({objectMode:!0});a._write=(n,c,f)=>this._getEntry(s[n],e[n],r).then(p=>{p!==null&&r.entryFilter(p)&&a.push(p),n===s.length-1&&a.end(),f()}).catch(f);for(let n=0;nthis._makeEntry(a,r)).catch(a=>{if(s.errorFilter(a))return null;throw a})}_getStat(e){return new Promise((r,s)=>{this._stat(e,this._fsStatSettings,(a,n)=>a===null?r(n):s(a))})}};V3.default=Y3});var Nce=_(z3=>{"use strict";Object.defineProperty(z3,"__esModule",{value:!0});var A$e=EQ(),p$e=IQ(),h$e=J3(),K3=class extends p$e.default{constructor(){super(...arguments),this._walkAsync=A$e.walk,this._readerStream=new h$e.default(this._settings)}dynamic(e,r){return new Promise((s,a)=>{this._walkAsync(e,r,(n,c)=>{n===null?s(c):a(n)})})}async static(e,r){let s=[],a=this._readerStream.static(e,r);return new Promise((n,c)=>{a.once("error",c),a.on("data",f=>s.push(f)),a.once("end",()=>n(s))})}};z3.default=K3});var Oce=_(Z3=>{"use strict";Object.defineProperty(Z3,"__esModule",{value:!0});var NB=xp(),X3=class{constructor(e,r,s){this._patterns=e,this._settings=r,this._micromatchOptions=s,this._storage=[],this._fillStorage()}_fillStorage(){for(let e of this._patterns){let r=this._getPatternSegments(e),s=this._splitSegmentsIntoSections(r);this._storage.push({complete:s.length<=1,pattern:e,segments:r,sections:s})}}_getPatternSegments(e){return NB.pattern.getPatternParts(e,this._micromatchOptions).map(s=>NB.pattern.isDynamicPattern(s,this._settings)?{dynamic:!0,pattern:s,patternRe:NB.pattern.makeRe(s,this._micromatchOptions)}:{dynamic:!1,pattern:s})}_splitSegmentsIntoSections(e){return NB.array.splitWhen(e,r=>r.dynamic&&NB.pattern.hasGlobStar(r.pattern))}};Z3.default=X3});var Lce=_(e8=>{"use strict";Object.defineProperty(e8,"__esModule",{value:!0});var g$e=Oce(),$3=class extends g$e.default{match(e){let r=e.split("/"),s=r.length,a=this._storage.filter(n=>!n.complete||n.segments.length>s);for(let n of a){let c=n.sections[0];if(!n.complete&&s>c.length||r.every((p,h)=>{let E=n.segments[h];return!!(E.dynamic&&E.patternRe.test(p)||!E.dynamic&&E.pattern===p)}))return!0}return!1}};e8.default=$3});var Mce=_(r8=>{"use strict";Object.defineProperty(r8,"__esModule",{value:!0});var CQ=xp(),d$e=Lce(),t8=class{constructor(e,r){this._settings=e,this._micromatchOptions=r}getFilter(e,r,s){let a=this._getMatcher(r),n=this._getNegativePatternsRe(s);return c=>this._filter(e,c,a,n)}_getMatcher(e){return new d$e.default(e,this._settings,this._micromatchOptions)}_getNegativePatternsRe(e){let r=e.filter(CQ.pattern.isAffectDepthOfReadingPattern);return CQ.pattern.convertPatternsToRe(r,this._micromatchOptions)}_filter(e,r,s,a){if(this._isSkippedByDeep(e,r.path)||this._isSkippedSymbolicLink(r))return!1;let n=CQ.path.removeLeadingDotSegment(r.path);return this._isSkippedByPositivePatterns(n,s)?!1:this._isSkippedByNegativePatterns(n,a)}_isSkippedByDeep(e,r){return this._settings.deep===1/0?!1:this._getEntryLevel(e,r)>=this._settings.deep}_getEntryLevel(e,r){let s=r.split("/").length;if(e==="")return s;let a=e.split("/").length;return s-a}_isSkippedSymbolicLink(e){return!this._settings.followSymbolicLinks&&e.dirent.isSymbolicLink()}_isSkippedByPositivePatterns(e,r){return!this._settings.baseNameMatch&&!r.match(e)}_isSkippedByNegativePatterns(e,r){return!CQ.pattern.matchAny(e,r)}};r8.default=t8});var Uce=_(i8=>{"use strict";Object.defineProperty(i8,"__esModule",{value:!0});var $d=xp(),n8=class{constructor(e,r){this._settings=e,this._micromatchOptions=r,this.index=new Map}getFilter(e,r){let s=$d.pattern.convertPatternsToRe(e,this._micromatchOptions),a=$d.pattern.convertPatternsToRe(r,Object.assign(Object.assign({},this._micromatchOptions),{dot:!0}));return n=>this._filter(n,s,a)}_filter(e,r,s){let a=$d.path.removeLeadingDotSegment(e.path);if(this._settings.unique&&this._isDuplicateEntry(a)||this._onlyFileFilter(e)||this._onlyDirectoryFilter(e)||this._isSkippedByAbsoluteNegativePatterns(a,s))return!1;let n=e.dirent.isDirectory(),c=this._isMatchToPatterns(a,r,n)&&!this._isMatchToPatterns(a,s,n);return this._settings.unique&&c&&this._createIndexRecord(a),c}_isDuplicateEntry(e){return this.index.has(e)}_createIndexRecord(e){this.index.set(e,void 0)}_onlyFileFilter(e){return this._settings.onlyFiles&&!e.dirent.isFile()}_onlyDirectoryFilter(e){return this._settings.onlyDirectories&&!e.dirent.isDirectory()}_isSkippedByAbsoluteNegativePatterns(e,r){if(!this._settings.absolute)return!1;let s=$d.path.makeAbsolute(this._settings.cwd,e);return $d.pattern.matchAny(s,r)}_isMatchToPatterns(e,r,s){let a=$d.pattern.matchAny(e,r);return!a&&s?$d.pattern.matchAny(e+"/",r):a}};i8.default=n8});var _ce=_(o8=>{"use strict";Object.defineProperty(o8,"__esModule",{value:!0});var m$e=xp(),s8=class{constructor(e){this._settings=e}getFilter(){return e=>this._isNonFatalError(e)}_isNonFatalError(e){return m$e.errno.isEnoentCodeError(e)||this._settings.suppressErrors}};o8.default=s8});var jce=_(l8=>{"use strict";Object.defineProperty(l8,"__esModule",{value:!0});var Hce=xp(),a8=class{constructor(e){this._settings=e}getTransformer(){return e=>this._transform(e)}_transform(e){let r=e.path;return this._settings.absolute&&(r=Hce.path.makeAbsolute(this._settings.cwd,r),r=Hce.path.unixify(r)),this._settings.markDirectories&&e.dirent.isDirectory()&&(r+="/"),this._settings.objectMode?Object.assign(Object.assign({},e),{path:r}):r}};l8.default=a8});var wQ=_(u8=>{"use strict";Object.defineProperty(u8,"__esModule",{value:!0});var y$e=Ie("path"),E$e=Mce(),I$e=Uce(),C$e=_ce(),w$e=jce(),c8=class{constructor(e){this._settings=e,this.errorFilter=new C$e.default(this._settings),this.entryFilter=new I$e.default(this._settings,this._getMicromatchOptions()),this.deepFilter=new E$e.default(this._settings,this._getMicromatchOptions()),this.entryTransformer=new w$e.default(this._settings)}_getRootDirectory(e){return y$e.resolve(this._settings.cwd,e.base)}_getReaderOptions(e){let r=e.base==="."?"":e.base;return{basePath:r,pathSegmentSeparator:"/",concurrency:this._settings.concurrency,deepFilter:this.deepFilter.getFilter(r,e.positive,e.negative),entryFilter:this.entryFilter.getFilter(e.positive,e.negative),errorFilter:this.errorFilter.getFilter(),followSymbolicLinks:this._settings.followSymbolicLinks,fs:this._settings.fs,stats:this._settings.stats,throwErrorOnBrokenSymbolicLink:this._settings.throwErrorOnBrokenSymbolicLink,transform:this.entryTransformer.getTransformer()}}_getMicromatchOptions(){return{dot:this._settings.dot,matchBase:this._settings.baseNameMatch,nobrace:!this._settings.braceExpansion,nocase:!this._settings.caseSensitiveMatch,noext:!this._settings.extglob,noglobstar:!this._settings.globstar,posix:!0,strictSlashes:!1}}};u8.default=c8});var Gce=_(A8=>{"use strict";Object.defineProperty(A8,"__esModule",{value:!0});var B$e=Nce(),v$e=wQ(),f8=class extends v$e.default{constructor(){super(...arguments),this._reader=new B$e.default(this._settings)}async read(e){let r=this._getRootDirectory(e),s=this._getReaderOptions(e);return(await this.api(r,e,s)).map(n=>s.transform(n))}api(e,r,s){return r.dynamic?this._reader.dynamic(e,s):this._reader.static(r.patterns,s)}};A8.default=f8});var qce=_(h8=>{"use strict";Object.defineProperty(h8,"__esModule",{value:!0});var S$e=Ie("stream"),D$e=J3(),b$e=wQ(),p8=class extends b$e.default{constructor(){super(...arguments),this._reader=new D$e.default(this._settings)}read(e){let r=this._getRootDirectory(e),s=this._getReaderOptions(e),a=this.api(r,e,s),n=new S$e.Readable({objectMode:!0,read:()=>{}});return a.once("error",c=>n.emit("error",c)).on("data",c=>n.emit("data",s.transform(c))).once("end",()=>n.emit("end")),n.once("close",()=>a.destroy()),n}api(e,r,s){return r.dynamic?this._reader.dynamic(e,s):this._reader.static(r.patterns,s)}};h8.default=p8});var Wce=_(d8=>{"use strict";Object.defineProperty(d8,"__esModule",{value:!0});var P$e=Zd(),x$e=EQ(),k$e=IQ(),g8=class extends k$e.default{constructor(){super(...arguments),this._walkSync=x$e.walkSync,this._statSync=P$e.statSync}dynamic(e,r){return this._walkSync(e,r)}static(e,r){let s=[];for(let a of e){let n=this._getFullEntryPath(a),c=this._getEntry(n,a,r);c===null||!r.entryFilter(c)||s.push(c)}return s}_getEntry(e,r,s){try{let a=this._getStat(e);return this._makeEntry(a,r)}catch(a){if(s.errorFilter(a))return null;throw a}}_getStat(e){return this._statSync(e,this._fsStatSettings)}};d8.default=g8});var Yce=_(y8=>{"use strict";Object.defineProperty(y8,"__esModule",{value:!0});var Q$e=Wce(),T$e=wQ(),m8=class extends T$e.default{constructor(){super(...arguments),this._reader=new Q$e.default(this._settings)}read(e){let r=this._getRootDirectory(e),s=this._getReaderOptions(e);return this.api(r,e,s).map(s.transform)}api(e,r,s){return r.dynamic?this._reader.dynamic(e,s):this._reader.static(r.patterns,s)}};y8.default=m8});var Vce=_(eI=>{"use strict";Object.defineProperty(eI,"__esModule",{value:!0});eI.DEFAULT_FILE_SYSTEM_ADAPTER=void 0;var $E=Ie("fs"),R$e=Ie("os"),F$e=Math.max(R$e.cpus().length,1);eI.DEFAULT_FILE_SYSTEM_ADAPTER={lstat:$E.lstat,lstatSync:$E.lstatSync,stat:$E.stat,statSync:$E.statSync,readdir:$E.readdir,readdirSync:$E.readdirSync};var E8=class{constructor(e={}){this._options=e,this.absolute=this._getValue(this._options.absolute,!1),this.baseNameMatch=this._getValue(this._options.baseNameMatch,!1),this.braceExpansion=this._getValue(this._options.braceExpansion,!0),this.caseSensitiveMatch=this._getValue(this._options.caseSensitiveMatch,!0),this.concurrency=this._getValue(this._options.concurrency,F$e),this.cwd=this._getValue(this._options.cwd,process.cwd()),this.deep=this._getValue(this._options.deep,1/0),this.dot=this._getValue(this._options.dot,!1),this.extglob=this._getValue(this._options.extglob,!0),this.followSymbolicLinks=this._getValue(this._options.followSymbolicLinks,!0),this.fs=this._getFileSystemMethods(this._options.fs),this.globstar=this._getValue(this._options.globstar,!0),this.ignore=this._getValue(this._options.ignore,[]),this.markDirectories=this._getValue(this._options.markDirectories,!1),this.objectMode=this._getValue(this._options.objectMode,!1),this.onlyDirectories=this._getValue(this._options.onlyDirectories,!1),this.onlyFiles=this._getValue(this._options.onlyFiles,!0),this.stats=this._getValue(this._options.stats,!1),this.suppressErrors=this._getValue(this._options.suppressErrors,!1),this.throwErrorOnBrokenSymbolicLink=this._getValue(this._options.throwErrorOnBrokenSymbolicLink,!1),this.unique=this._getValue(this._options.unique,!0),this.onlyDirectories&&(this.onlyFiles=!1),this.stats&&(this.objectMode=!0),this.ignore=[].concat(this.ignore)}_getValue(e,r){return e===void 0?r:e}_getFileSystemMethods(e={}){return Object.assign(Object.assign({},eI.DEFAULT_FILE_SYSTEM_ADAPTER),e)}};eI.default=E8});var BQ=_((WLt,Kce)=>{"use strict";var Jce=Kle(),N$e=Gce(),O$e=qce(),L$e=Yce(),I8=Vce(),Qc=xp();async function C8(t,e){ju(t);let r=w8(t,N$e.default,e),s=await Promise.all(r);return Qc.array.flatten(s)}(function(t){t.glob=t,t.globSync=e,t.globStream=r,t.async=t;function e(h,E){ju(h);let C=w8(h,L$e.default,E);return Qc.array.flatten(C)}t.sync=e;function r(h,E){ju(h);let C=w8(h,O$e.default,E);return Qc.stream.merge(C)}t.stream=r;function s(h,E){ju(h);let C=[].concat(h),S=new I8.default(E);return Jce.generate(C,S)}t.generateTasks=s;function a(h,E){ju(h);let C=new I8.default(E);return Qc.pattern.isDynamicPattern(h,C)}t.isDynamicPattern=a;function n(h){return ju(h),Qc.path.escape(h)}t.escapePath=n;function c(h){return ju(h),Qc.path.convertPathToPattern(h)}t.convertPathToPattern=c;let f;(function(h){function E(S){return ju(S),Qc.path.escapePosixPath(S)}h.escapePath=E;function C(S){return ju(S),Qc.path.convertPosixPathToPattern(S)}h.convertPathToPattern=C})(f=t.posix||(t.posix={}));let p;(function(h){function E(S){return ju(S),Qc.path.escapeWindowsPath(S)}h.escapePath=E;function C(S){return ju(S),Qc.path.convertWindowsPathToPattern(S)}h.convertPathToPattern=C})(p=t.win32||(t.win32={}))})(C8||(C8={}));function w8(t,e,r){let s=[].concat(t),a=new I8.default(r),n=Jce.generate(s,a),c=new e(a);return n.map(c.read,c)}function ju(t){if(![].concat(t).every(s=>Qc.string.isString(s)&&!Qc.string.isEmpty(s)))throw new TypeError("Patterns must be a string (non empty) or an array of strings")}Kce.exports=C8});var Nn={};Vt(Nn,{checksumFile:()=>SQ,checksumPattern:()=>DQ,makeHash:()=>us});function us(...t){let e=(0,vQ.createHash)("sha512"),r="";for(let s of t)typeof s=="string"?r+=s:s&&(r&&(e.update(r),r=""),e.update(s));return r&&e.update(r),e.digest("hex")}async function SQ(t,{baseFs:e,algorithm:r}={baseFs:ce,algorithm:"sha512"}){let s=await e.openPromise(t,"r");try{let n=Buffer.allocUnsafeSlow(65536),c=(0,vQ.createHash)(r),f=0;for(;(f=await e.readPromise(s,n,0,65536))!==0;)c.update(f===65536?n:n.slice(0,f));return c.digest("hex")}finally{await e.closePromise(s)}}async function DQ(t,{cwd:e}){let s=(await(0,B8.default)(t,{cwd:fe.fromPortablePath(e),onlyDirectories:!0})).map(f=>`${f}/**/*`),a=await(0,B8.default)([t,...s],{cwd:fe.fromPortablePath(e),onlyFiles:!1});a.sort();let n=await Promise.all(a.map(async f=>{let p=[Buffer.from(f)],h=J.join(e,fe.toPortablePath(f)),E=await ce.lstatPromise(h);return E.isSymbolicLink()?p.push(Buffer.from(await ce.readlinkPromise(h))):E.isFile()&&p.push(await ce.readFilePromise(h)),p.join("\0")})),c=(0,vQ.createHash)("sha512");for(let f of n)c.update(f);return c.digest("hex")}var vQ,B8,I0=Xe(()=>{Dt();vQ=Ie("crypto"),B8=ut(BQ())});var G={};Vt(G,{allPeerRequests:()=>qB,areDescriptorsEqual:()=>eue,areIdentsEqual:()=>UB,areLocatorsEqual:()=>_B,areVirtualPackagesEquivalent:()=>Y$e,bindDescriptor:()=>q$e,bindLocator:()=>W$e,convertDescriptorToLocator:()=>bQ,convertLocatorToDescriptor:()=>S8,convertPackageToLocator:()=>H$e,convertToIdent:()=>_$e,convertToManifestRange:()=>ret,copyPackage:()=>LB,devirtualizeDescriptor:()=>MB,devirtualizeLocator:()=>rI,ensureDevirtualizedDescriptor:()=>j$e,ensureDevirtualizedLocator:()=>G$e,getIdentVendorPath:()=>x8,isPackageCompatible:()=>TQ,isVirtualDescriptor:()=>kp,isVirtualLocator:()=>Gu,makeDescriptor:()=>On,makeIdent:()=>Da,makeLocator:()=>Ws,makeRange:()=>kQ,parseDescriptor:()=>C0,parseFileStyleRange:()=>eet,parseIdent:()=>Sa,parseLocator:()=>Qp,parseRange:()=>em,prettyDependent:()=>t3,prettyDescriptor:()=>ni,prettyIdent:()=>$i,prettyLocator:()=>Yr,prettyLocatorNoColors:()=>e3,prettyRange:()=>iI,prettyReference:()=>jB,prettyResolution:()=>FB,prettyWorkspace:()=>GB,renamePackage:()=>D8,slugifyIdent:()=>v8,slugifyLocator:()=>nI,sortDescriptors:()=>sI,stringifyDescriptor:()=>al,stringifyIdent:()=>un,stringifyLocator:()=>ll,tryParseDescriptor:()=>HB,tryParseIdent:()=>tue,tryParseLocator:()=>xQ,tryParseRange:()=>$$e,unwrapIdentFromScope:()=>iet,virtualizeDescriptor:()=>b8,virtualizePackage:()=>P8,wrapIdentIntoScope:()=>net});function Da(t,e){if(t?.startsWith("@"))throw new Error("Invalid scope: don't prefix it with '@'");return{identHash:us(t,e),scope:t,name:e}}function On(t,e){return{identHash:t.identHash,scope:t.scope,name:t.name,descriptorHash:us(t.identHash,e),range:e}}function Ws(t,e){return{identHash:t.identHash,scope:t.scope,name:t.name,locatorHash:us(t.identHash,e),reference:e}}function _$e(t){return{identHash:t.identHash,scope:t.scope,name:t.name}}function bQ(t){return{identHash:t.identHash,scope:t.scope,name:t.name,locatorHash:t.descriptorHash,reference:t.range}}function S8(t){return{identHash:t.identHash,scope:t.scope,name:t.name,descriptorHash:t.locatorHash,range:t.reference}}function H$e(t){return{identHash:t.identHash,scope:t.scope,name:t.name,locatorHash:t.locatorHash,reference:t.reference}}function D8(t,e){return{identHash:e.identHash,scope:e.scope,name:e.name,locatorHash:e.locatorHash,reference:e.reference,version:t.version,languageName:t.languageName,linkType:t.linkType,conditions:t.conditions,dependencies:new Map(t.dependencies),peerDependencies:new Map(t.peerDependencies),dependenciesMeta:new Map(t.dependenciesMeta),peerDependenciesMeta:new Map(t.peerDependenciesMeta),bin:new Map(t.bin)}}function LB(t){return D8(t,t)}function b8(t,e){if(e.includes("#"))throw new Error("Invalid entropy");return On(t,`virtual:${e}#${t.range}`)}function P8(t,e){if(e.includes("#"))throw new Error("Invalid entropy");return D8(t,Ws(t,`virtual:${e}#${t.reference}`))}function kp(t){return t.range.startsWith(OB)}function Gu(t){return t.reference.startsWith(OB)}function MB(t){if(!kp(t))throw new Error("Not a virtual descriptor");return On(t,t.range.replace(PQ,""))}function rI(t){if(!Gu(t))throw new Error("Not a virtual descriptor");return Ws(t,t.reference.replace(PQ,""))}function j$e(t){return kp(t)?On(t,t.range.replace(PQ,"")):t}function G$e(t){return Gu(t)?Ws(t,t.reference.replace(PQ,"")):t}function q$e(t,e){return t.range.includes("::")?t:On(t,`${t.range}::${tI.default.stringify(e)}`)}function W$e(t,e){return t.reference.includes("::")?t:Ws(t,`${t.reference}::${tI.default.stringify(e)}`)}function UB(t,e){return t.identHash===e.identHash}function eue(t,e){return t.descriptorHash===e.descriptorHash}function _B(t,e){return t.locatorHash===e.locatorHash}function Y$e(t,e){if(!Gu(t))throw new Error("Invalid package type");if(!Gu(e))throw new Error("Invalid package type");if(!UB(t,e)||t.dependencies.size!==e.dependencies.size)return!1;for(let r of t.dependencies.values()){let s=e.dependencies.get(r.identHash);if(!s||!eue(r,s))return!1}return!0}function Sa(t){let e=tue(t);if(!e)throw new Error(`Invalid ident (${t})`);return e}function tue(t){let e=t.match(V$e);if(!e)return null;let[,r,s]=e;return Da(typeof r<"u"?r:null,s)}function C0(t,e=!1){let r=HB(t,e);if(!r)throw new Error(`Invalid descriptor (${t})`);return r}function HB(t,e=!1){let r=e?t.match(J$e):t.match(K$e);if(!r)return null;let[,s,a,n]=r;if(n==="unknown")throw new Error(`Invalid range (${t})`);let c=typeof s<"u"?s:null,f=typeof n<"u"?n:"unknown";return On(Da(c,a),f)}function Qp(t,e=!1){let r=xQ(t,e);if(!r)throw new Error(`Invalid locator (${t})`);return r}function xQ(t,e=!1){let r=e?t.match(z$e):t.match(X$e);if(!r)return null;let[,s,a,n]=r;if(n==="unknown")throw new Error(`Invalid reference (${t})`);let c=typeof s<"u"?s:null,f=typeof n<"u"?n:"unknown";return Ws(Da(c,a),f)}function em(t,e){let r=t.match(Z$e);if(r===null)throw new Error(`Invalid range (${t})`);let s=typeof r[1]<"u"?r[1]:null;if(typeof e?.requireProtocol=="string"&&s!==e.requireProtocol)throw new Error(`Invalid protocol (${s})`);if(e?.requireProtocol&&s===null)throw new Error(`Missing protocol (${s})`);let a=typeof r[3]<"u"?decodeURIComponent(r[2]):null;if(e?.requireSource&&a===null)throw new Error(`Missing source (${t})`);let n=typeof r[3]<"u"?decodeURIComponent(r[3]):decodeURIComponent(r[2]),c=e?.parseSelector?tI.default.parse(n):n,f=typeof r[4]<"u"?tI.default.parse(r[4]):null;return{protocol:s,source:a,selector:c,params:f}}function $$e(t,e){try{return em(t,e)}catch{return null}}function eet(t,{protocol:e}){let{selector:r,params:s}=em(t,{requireProtocol:e,requireBindings:!0});if(typeof s.locator!="string")throw new Error(`Assertion failed: Invalid bindings for ${t}`);return{parentLocator:Qp(s.locator,!0),path:r}}function zce(t){return t=t.replaceAll("%","%25"),t=t.replaceAll(":","%3A"),t=t.replaceAll("#","%23"),t}function tet(t){return t===null?!1:Object.entries(t).length>0}function kQ({protocol:t,source:e,selector:r,params:s}){let a="";return t!==null&&(a+=`${t}`),e!==null&&(a+=`${zce(e)}#`),a+=zce(r),tet(s)&&(a+=`::${tI.default.stringify(s)}`),a}function ret(t){let{params:e,protocol:r,source:s,selector:a}=em(t);for(let n in e)n.startsWith("__")&&delete e[n];return kQ({protocol:r,source:s,params:e,selector:a})}function un(t){return t.scope?`@${t.scope}/${t.name}`:`${t.name}`}function net(t,e){return t.scope?Da(e,`${t.scope}__${t.name}`):Da(e,t.name)}function iet(t,e){if(t.scope!==e)return t;let r=t.name.indexOf("__");if(r===-1)return Da(null,t.name);let s=t.name.slice(0,r),a=t.name.slice(r+2);return Da(s,a)}function al(t){return t.scope?`@${t.scope}/${t.name}@${t.range}`:`${t.name}@${t.range}`}function ll(t){return t.scope?`@${t.scope}/${t.name}@${t.reference}`:`${t.name}@${t.reference}`}function v8(t){return t.scope!==null?`@${t.scope}-${t.name}`:t.name}function nI(t){let{protocol:e,selector:r}=em(t.reference),s=e!==null?e.replace(set,""):"exotic",a=Xce.default.valid(r),n=a!==null?`${s}-${a}`:`${s}`,c=10;return t.scope?`${v8(t)}-${n}-${t.locatorHash.slice(0,c)}`:`${v8(t)}-${n}-${t.locatorHash.slice(0,c)}`}function $i(t,e){return e.scope?`${Ht(t,`@${e.scope}/`,ht.SCOPE)}${Ht(t,e.name,ht.NAME)}`:`${Ht(t,e.name,ht.NAME)}`}function QQ(t){if(t.startsWith(OB)){let e=QQ(t.substring(t.indexOf("#")+1)),r=t.substring(OB.length,OB.length+M$e);return`${e} [${r}]`}else return t.replace(oet,"?[...]")}function iI(t,e){return`${Ht(t,QQ(e),ht.RANGE)}`}function ni(t,e){return`${$i(t,e)}${Ht(t,"@",ht.RANGE)}${iI(t,e.range)}`}function jB(t,e){return`${Ht(t,QQ(e),ht.REFERENCE)}`}function Yr(t,e){return`${$i(t,e)}${Ht(t,"@",ht.REFERENCE)}${jB(t,e.reference)}`}function e3(t){return`${un(t)}@${QQ(t.reference)}`}function sI(t){return qs(t,[e=>un(e),e=>e.range])}function GB(t,e){return $i(t,e.anchoredLocator)}function FB(t,e,r){let s=kp(e)?MB(e):e;return r===null?`${ni(t,s)} \u2192 ${$4(t).Cross}`:s.identHash===r.identHash?`${ni(t,s)} \u2192 ${jB(t,r.reference)}`:`${ni(t,s)} \u2192 ${Yr(t,r)}`}function t3(t,e,r){return r===null?`${Yr(t,e)}`:`${Yr(t,e)} (via ${iI(t,r.range)})`}function x8(t){return`node_modules/${un(t)}`}function TQ(t,e){return t.conditions?U$e(t.conditions,r=>{let[,s,a]=r.match($ce),n=e[s];return n?n.includes(a):!0}):!0}function qB(t){let e=new Set;if("children"in t)e.add(t);else for(let r of t.requests.values())e.add(r);for(let r of e)for(let s of r.children.values())e.add(s);return e}var tI,Xce,Zce,OB,M$e,$ce,U$e,PQ,V$e,J$e,K$e,z$e,X$e,Z$e,set,oet,Wo=Xe(()=>{tI=ut(Ie("querystring")),Xce=ut(Ai()),Zce=ut(Ise());xc();I0();Pc();Wo();OB="virtual:",M$e=5,$ce=/(os|cpu|libc)=([a-z0-9_-]+)/,U$e=(0,Zce.makeParser)($ce);PQ=/^[^#]*#/;V$e=/^(?:@([^/]+?)\/)?([^@/]+)$/;J$e=/^(?:@([^/]+?)\/)?([^@/]+?)(?:@(.+))$/,K$e=/^(?:@([^/]+?)\/)?([^@/]+?)(?:@(.+))?$/;z$e=/^(?:@([^/]+?)\/)?([^@/]+?)(?:@(.+))$/,X$e=/^(?:@([^/]+?)\/)?([^@/]+?)(?:@(.+))?$/;Z$e=/^([^#:]*:)?((?:(?!::)[^#])*)(?:#((?:(?!::).)*))?(?:::(.*))?$/;set=/:$/;oet=/\?.*/});var rue,nue=Xe(()=>{Wo();rue={hooks:{reduceDependency:(t,e,r,s,{resolver:a,resolveOptions:n})=>{for(let{pattern:c,reference:f}of e.topLevelWorkspace.manifest.resolutions){if(c.from&&(c.from.fullName!==un(r)||e.configuration.normalizeLocator(Ws(Sa(c.from.fullName),c.from.description??r.reference)).locatorHash!==r.locatorHash)||c.descriptor.fullName!==un(t)||e.configuration.normalizeDependency(On(Qp(c.descriptor.fullName),c.descriptor.description??t.range)).descriptorHash!==t.descriptorHash)continue;return a.bindDescriptor(e.configuration.normalizeDependency(On(t,f)),e.topLevelWorkspace.anchoredLocator,n)}return t},validateProject:async(t,e)=>{for(let r of t.workspaces){let s=GB(t.configuration,r);await t.configuration.triggerHook(a=>a.validateWorkspace,r,{reportWarning:(a,n)=>e.reportWarning(a,`${s}: ${n}`),reportError:(a,n)=>e.reportError(a,`${s}: ${n}`)})}},validateWorkspace:async(t,e)=>{let{manifest:r}=t;r.resolutions.length&&t.cwd!==t.project.cwd&&r.errors.push(new Error("Resolutions field will be ignored"));for(let s of r.errors)e.reportWarning(57,s.message)}}}});var Ei,tm=Xe(()=>{Ei=class t{static{this.protocol="workspace:"}supportsDescriptor(e,r){return!!(e.range.startsWith(t.protocol)||r.project.tryWorkspaceByDescriptor(e)!==null)}supportsLocator(e,r){return!!e.reference.startsWith(t.protocol)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,s){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,s){return[s.project.getWorkspaceByDescriptor(e).anchoredLocator]}async getSatisfying(e,r,s,a){let[n]=await this.getCandidates(e,r,a);return{locators:s.filter(c=>c.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){let s=r.project.getWorkspaceByCwd(e.reference.slice(t.protocol.length));return{...e,version:s.manifest.version||"0.0.0",languageName:"unknown",linkType:"SOFT",conditions:null,dependencies:r.project.configuration.normalizeDependencyMap(new Map([...s.manifest.dependencies,...s.manifest.devDependencies])),peerDependencies:new Map([...s.manifest.peerDependencies]),dependenciesMeta:s.manifest.dependenciesMeta,peerDependenciesMeta:s.manifest.peerDependenciesMeta,bin:s.manifest.bin}}}});var Fr={};Vt(Fr,{SemVer:()=>lue.SemVer,clean:()=>cet,getComparator:()=>oue,mergeComparators:()=>k8,satisfiesWithPrereleases:()=>Zf,simplifyRanges:()=>Q8,stringifyComparator:()=>aue,validRange:()=>cl});function Zf(t,e,r=!1){if(!t)return!1;let s=`${e}${r}`,a=iue.get(s);if(typeof a>"u")try{a=new Tp.default.Range(e,{includePrerelease:!0,loose:r})}catch{return!1}finally{iue.set(s,a||null)}else if(a===null)return!1;let n;try{n=new Tp.default.SemVer(t,a)}catch{return!1}return a.test(n)?!0:(n.prerelease&&(n.prerelease=[]),a.set.some(c=>{for(let f of c)f.semver.prerelease&&(f.semver.prerelease=[]);return c.every(f=>f.test(n))}))}function cl(t){if(t.indexOf(":")!==-1)return null;let e=sue.get(t);if(typeof e<"u")return e;try{e=new Tp.default.Range(t)}catch{e=null}return sue.set(t,e),e}function cet(t){let e=aet.exec(t);return e?e[1]:null}function oue(t){if(t.semver===Tp.default.Comparator.ANY)return{gt:null,lt:null};switch(t.operator){case"":return{gt:[">=",t.semver],lt:["<=",t.semver]};case">":case">=":return{gt:[t.operator,t.semver],lt:null};case"<":case"<=":return{gt:null,lt:[t.operator,t.semver]};default:throw new Error(`Assertion failed: Unexpected comparator operator (${t.operator})`)}}function k8(t){if(t.length===0)return null;let e=null,r=null;for(let s of t){if(s.gt){let a=e!==null?Tp.default.compare(s.gt[1],e[1]):null;(a===null||a>0||a===0&&s.gt[0]===">")&&(e=s.gt)}if(s.lt){let a=r!==null?Tp.default.compare(s.lt[1],r[1]):null;(a===null||a<0||a===0&&s.lt[0]==="<")&&(r=s.lt)}}if(e&&r){let s=Tp.default.compare(e[1],r[1]);if(s===0&&(e[0]===">"||r[0]==="<")||s>0)return null}return{gt:e,lt:r}}function aue(t){if(t.gt&&t.lt){if(t.gt[0]===">="&&t.lt[0]==="<="&&t.gt[1].version===t.lt[1].version)return t.gt[1].version;if(t.gt[0]===">="&&t.lt[0]==="<"){if(t.lt[1].version===`${t.gt[1].major+1}.0.0-0`)return`^${t.gt[1].version}`;if(t.lt[1].version===`${t.gt[1].major}.${t.gt[1].minor+1}.0-0`)return`~${t.gt[1].version}`}}let e=[];return t.gt&&e.push(t.gt[0]+t.gt[1].version),t.lt&&e.push(t.lt[0]+t.lt[1].version),e.length?e.join(" "):"*"}function Q8(t){let e=t.map(uet).map(s=>cl(s).set.map(a=>a.map(n=>oue(n)))),r=e.shift().map(s=>k8(s)).filter(s=>s!==null);for(let s of e){let a=[];for(let n of r)for(let c of s){let f=k8([n,...c]);f!==null&&a.push(f)}r=a}return r.length===0?null:r.map(s=>aue(s)).join(" || ")}function uet(t){let e=t.split("||");if(e.length>1){let r=new Set;for(let s of e)e.some(a=>a!==s&&Tp.default.subset(s,a))||r.add(s);if(r.size{Tp=ut(Ai()),lue=ut(Ai()),iue=new Map;sue=new Map;aet=/^(?:[\sv=]*?)((0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)(?:\s*)$/});function cue(t){let e=t.match(/^[ \t]+/m);return e?e[0]:" "}function uue(t){return t.charCodeAt(0)===65279?t.slice(1):t}function ba(t){return t.replace(/\\/g,"/")}function RQ(t,{yamlCompatibilityMode:e}){return e?Y4(t):typeof t>"u"||typeof t=="boolean"?t:null}function fue(t,e){let r=e.search(/[^!]/);if(r===-1)return"invalid";let s=r%2===0?"":"!",a=e.slice(r);return`${s}${t}=${a}`}function T8(t,e){return e.length===1?fue(t,e[0]):`(${e.map(r=>fue(t,r)).join(" | ")})`}var Aue,Ut,oI=Xe(()=>{Dt();wc();Aue=ut(Ai());tm();Pc();Rp();Wo();Ut=class t{constructor(){this.indent=" ";this.name=null;this.version=null;this.os=null;this.cpu=null;this.libc=null;this.type=null;this.packageManager=null;this.private=!1;this.license=null;this.main=null;this.module=null;this.browser=null;this.languageName=null;this.bin=new Map;this.scripts=new Map;this.dependencies=new Map;this.devDependencies=new Map;this.peerDependencies=new Map;this.workspaceDefinitions=[];this.dependenciesMeta=new Map;this.peerDependenciesMeta=new Map;this.resolutions=[];this.files=null;this.publishConfig=null;this.installConfig=null;this.preferUnplugged=null;this.raw={};this.errors=[]}static{this.fileName="package.json"}static{this.allDependencies=["dependencies","devDependencies","peerDependencies"]}static{this.hardDependencies=["dependencies","devDependencies"]}static async tryFind(e,{baseFs:r=new Yn}={}){let s=J.join(e,"package.json");try{return await t.fromFile(s,{baseFs:r})}catch(a){if(a.code==="ENOENT")return null;throw a}}static async find(e,{baseFs:r}={}){let s=await t.tryFind(e,{baseFs:r});if(s===null)throw new Error("Manifest not found");return s}static async fromFile(e,{baseFs:r=new Yn}={}){let s=new t;return await s.loadFile(e,{baseFs:r}),s}static fromText(e){let r=new t;return r.loadFromText(e),r}loadFromText(e){let r;try{r=JSON.parse(uue(e)||"{}")}catch(s){throw s.message+=` (when parsing ${e})`,s}this.load(r),this.indent=cue(e)}async loadFile(e,{baseFs:r=new Yn}){let s=await r.readFilePromise(e,"utf8"),a;try{a=JSON.parse(uue(s)||"{}")}catch(n){throw n.message+=` (when parsing ${e})`,n}this.load(a),this.indent=cue(s)}load(e,{yamlCompatibilityMode:r=!1}={}){if(typeof e!="object"||e===null)throw new Error(`Utterly invalid manifest data (${e})`);this.raw=e;let s=[];if(this.name=null,typeof e.name=="string")try{this.name=Sa(e.name)}catch{s.push(new Error("Parsing failed for the 'name' field"))}if(typeof e.version=="string"?this.version=e.version:this.version=null,Array.isArray(e.os)){let n=[];this.os=n;for(let c of e.os)typeof c!="string"?s.push(new Error("Parsing failed for the 'os' field")):n.push(c)}else this.os=null;if(Array.isArray(e.cpu)){let n=[];this.cpu=n;for(let c of e.cpu)typeof c!="string"?s.push(new Error("Parsing failed for the 'cpu' field")):n.push(c)}else this.cpu=null;if(Array.isArray(e.libc)){let n=[];this.libc=n;for(let c of e.libc)typeof c!="string"?s.push(new Error("Parsing failed for the 'libc' field")):n.push(c)}else this.libc=null;if(typeof e.type=="string"?this.type=e.type:this.type=null,typeof e.packageManager=="string"?this.packageManager=e.packageManager:this.packageManager=null,typeof e.private=="boolean"?this.private=e.private:this.private=!1,typeof e.license=="string"?this.license=e.license:this.license=null,typeof e.languageName=="string"?this.languageName=e.languageName:this.languageName=null,typeof e.main=="string"?this.main=ba(e.main):this.main=null,typeof e.module=="string"?this.module=ba(e.module):this.module=null,e.browser!=null)if(typeof e.browser=="string")this.browser=ba(e.browser);else{this.browser=new Map;for(let[n,c]of Object.entries(e.browser))this.browser.set(ba(n),typeof c=="string"?ba(c):c)}else this.browser=null;if(this.bin=new Map,typeof e.bin=="string")e.bin.trim()===""?s.push(new Error("Invalid bin field")):this.name!==null?this.bin.set(this.name.name,ba(e.bin)):s.push(new Error("String bin field, but no attached package name"));else if(typeof e.bin=="object"&&e.bin!==null)for(let[n,c]of Object.entries(e.bin)){if(typeof c!="string"||c.trim()===""){s.push(new Error(`Invalid bin definition for '${n}'`));continue}let f=Sa(n);this.bin.set(f.name,ba(c))}if(this.scripts=new Map,typeof e.scripts=="object"&&e.scripts!==null)for(let[n,c]of Object.entries(e.scripts)){if(typeof c!="string"){s.push(new Error(`Invalid script definition for '${n}'`));continue}this.scripts.set(n,c)}if(this.dependencies=new Map,typeof e.dependencies=="object"&&e.dependencies!==null)for(let[n,c]of Object.entries(e.dependencies)){if(typeof c!="string"){s.push(new Error(`Invalid dependency range for '${n}'`));continue}let f;try{f=Sa(n)}catch{s.push(new Error(`Parsing failed for the dependency name '${n}'`));continue}let p=On(f,c);this.dependencies.set(p.identHash,p)}if(this.devDependencies=new Map,typeof e.devDependencies=="object"&&e.devDependencies!==null)for(let[n,c]of Object.entries(e.devDependencies)){if(typeof c!="string"){s.push(new Error(`Invalid dependency range for '${n}'`));continue}let f;try{f=Sa(n)}catch{s.push(new Error(`Parsing failed for the dependency name '${n}'`));continue}let p=On(f,c);this.devDependencies.set(p.identHash,p)}if(this.peerDependencies=new Map,typeof e.peerDependencies=="object"&&e.peerDependencies!==null)for(let[n,c]of Object.entries(e.peerDependencies)){let f;try{f=Sa(n)}catch{s.push(new Error(`Parsing failed for the dependency name '${n}'`));continue}(typeof c!="string"||!c.startsWith(Ei.protocol)&&!cl(c))&&(s.push(new Error(`Invalid dependency range for '${n}'`)),c="*");let p=On(f,c);this.peerDependencies.set(p.identHash,p)}typeof e.workspaces=="object"&&e.workspaces!==null&&e.workspaces.nohoist&&s.push(new Error("'nohoist' is deprecated, please use 'installConfig.hoistingLimits' instead"));let a=Array.isArray(e.workspaces)?e.workspaces:typeof e.workspaces=="object"&&e.workspaces!==null&&Array.isArray(e.workspaces.packages)?e.workspaces.packages:[];this.workspaceDefinitions=[];for(let n of a){if(typeof n!="string"){s.push(new Error(`Invalid workspace definition for '${n}'`));continue}this.workspaceDefinitions.push({pattern:n})}if(this.dependenciesMeta=new Map,typeof e.dependenciesMeta=="object"&&e.dependenciesMeta!==null)for(let[n,c]of Object.entries(e.dependenciesMeta)){if(typeof c!="object"||c===null){s.push(new Error(`Invalid meta field for '${n}`));continue}let f=C0(n),p=this.ensureDependencyMeta(f),h=RQ(c.built,{yamlCompatibilityMode:r});if(h===null){s.push(new Error(`Invalid built meta field for '${n}'`));continue}let E=RQ(c.optional,{yamlCompatibilityMode:r});if(E===null){s.push(new Error(`Invalid optional meta field for '${n}'`));continue}let C=RQ(c.unplugged,{yamlCompatibilityMode:r});if(C===null){s.push(new Error(`Invalid unplugged meta field for '${n}'`));continue}Object.assign(p,{built:h,optional:E,unplugged:C})}if(this.peerDependenciesMeta=new Map,typeof e.peerDependenciesMeta=="object"&&e.peerDependenciesMeta!==null)for(let[n,c]of Object.entries(e.peerDependenciesMeta)){if(typeof c!="object"||c===null){s.push(new Error(`Invalid meta field for '${n}'`));continue}let f=C0(n),p=this.ensurePeerDependencyMeta(f),h=RQ(c.optional,{yamlCompatibilityMode:r});if(h===null){s.push(new Error(`Invalid optional meta field for '${n}'`));continue}Object.assign(p,{optional:h})}if(this.resolutions=[],typeof e.resolutions=="object"&&e.resolutions!==null)for(let[n,c]of Object.entries(e.resolutions)){if(typeof c!="string"){s.push(new Error(`Invalid resolution entry for '${n}'`));continue}try{this.resolutions.push({pattern:px(n),reference:c})}catch(f){s.push(f);continue}}if(Array.isArray(e.files)){this.files=new Set;for(let n of e.files){if(typeof n!="string"){s.push(new Error(`Invalid files entry for '${n}'`));continue}this.files.add(n)}}else this.files=null;if(typeof e.publishConfig=="object"&&e.publishConfig!==null){if(this.publishConfig={},typeof e.publishConfig.access=="string"&&(this.publishConfig.access=e.publishConfig.access),typeof e.publishConfig.main=="string"&&(this.publishConfig.main=ba(e.publishConfig.main)),typeof e.publishConfig.module=="string"&&(this.publishConfig.module=ba(e.publishConfig.module)),e.publishConfig.browser!=null)if(typeof e.publishConfig.browser=="string")this.publishConfig.browser=ba(e.publishConfig.browser);else{this.publishConfig.browser=new Map;for(let[n,c]of Object.entries(e.publishConfig.browser))this.publishConfig.browser.set(ba(n),typeof c=="string"?ba(c):c)}if(typeof e.publishConfig.registry=="string"&&(this.publishConfig.registry=e.publishConfig.registry),typeof e.publishConfig.provenance=="boolean"&&(this.publishConfig.provenance=e.publishConfig.provenance),typeof e.publishConfig.bin=="string")this.name!==null?this.publishConfig.bin=new Map([[this.name.name,ba(e.publishConfig.bin)]]):s.push(new Error("String bin field, but no attached package name"));else if(typeof e.publishConfig.bin=="object"&&e.publishConfig.bin!==null){this.publishConfig.bin=new Map;for(let[n,c]of Object.entries(e.publishConfig.bin)){if(typeof c!="string"){s.push(new Error(`Invalid bin definition for '${n}'`));continue}this.publishConfig.bin.set(n,ba(c))}}if(Array.isArray(e.publishConfig.executableFiles)){this.publishConfig.executableFiles=new Set;for(let n of e.publishConfig.executableFiles){if(typeof n!="string"){s.push(new Error("Invalid executable file definition"));continue}this.publishConfig.executableFiles.add(ba(n))}}}else this.publishConfig=null;if(typeof e.installConfig=="object"&&e.installConfig!==null){this.installConfig={};for(let n of Object.keys(e.installConfig))n==="hoistingLimits"?typeof e.installConfig.hoistingLimits=="string"?this.installConfig.hoistingLimits=e.installConfig.hoistingLimits:s.push(new Error("Invalid hoisting limits definition")):n=="selfReferences"?typeof e.installConfig.selfReferences=="boolean"?this.installConfig.selfReferences=e.installConfig.selfReferences:s.push(new Error("Invalid selfReferences definition, must be a boolean value")):s.push(new Error(`Unrecognized installConfig key: ${n}`))}else this.installConfig=null;if(typeof e.optionalDependencies=="object"&&e.optionalDependencies!==null)for(let[n,c]of Object.entries(e.optionalDependencies)){if(typeof c!="string"){s.push(new Error(`Invalid dependency range for '${n}'`));continue}let f;try{f=Sa(n)}catch{s.push(new Error(`Parsing failed for the dependency name '${n}'`));continue}let p=On(f,c);this.dependencies.set(p.identHash,p);let h=On(f,"unknown"),E=this.ensureDependencyMeta(h);Object.assign(E,{optional:!0})}typeof e.preferUnplugged=="boolean"?this.preferUnplugged=e.preferUnplugged:this.preferUnplugged=null,this.errors=s}getForScope(e){switch(e){case"dependencies":return this.dependencies;case"devDependencies":return this.devDependencies;case"peerDependencies":return this.peerDependencies;default:throw new Error(`Unsupported value ("${e}")`)}}hasConsumerDependency(e){return!!(this.dependencies.has(e.identHash)||this.peerDependencies.has(e.identHash))}hasHardDependency(e){return!!(this.dependencies.has(e.identHash)||this.devDependencies.has(e.identHash))}hasSoftDependency(e){return!!this.peerDependencies.has(e.identHash)}hasDependency(e){return!!(this.hasHardDependency(e)||this.hasSoftDependency(e))}getConditions(){let e=[];return this.os&&this.os.length>0&&e.push(T8("os",this.os)),this.cpu&&this.cpu.length>0&&e.push(T8("cpu",this.cpu)),this.libc&&this.libc.length>0&&e.push(T8("libc",this.libc)),e.length>0?e.join(" & "):null}ensureDependencyMeta(e){if(e.range!=="unknown"&&!Aue.default.valid(e.range))throw new Error(`Invalid meta field range for '${al(e)}'`);let r=un(e),s=e.range!=="unknown"?e.range:null,a=this.dependenciesMeta.get(r);a||this.dependenciesMeta.set(r,a=new Map);let n=a.get(s);return n||a.set(s,n={}),n}ensurePeerDependencyMeta(e){if(e.range!=="unknown")throw new Error(`Invalid meta field range for '${al(e)}'`);let r=un(e),s=this.peerDependenciesMeta.get(r);return s||this.peerDependenciesMeta.set(r,s={}),s}setRawField(e,r,{after:s=[]}={}){let a=new Set(s.filter(n=>Object.hasOwn(this.raw,n)));if(a.size===0||Object.hasOwn(this.raw,e))this.raw[e]=r;else{let n=this.raw,c=this.raw={},f=!1;for(let p of Object.keys(n))c[p]=n[p],f||(a.delete(p),a.size===0&&(c[e]=r,f=!0))}}exportTo(e,{compatibilityMode:r=!0}={}){if(Object.assign(e,this.raw),this.name!==null?e.name=un(this.name):delete e.name,this.version!==null?e.version=this.version:delete e.version,this.os!==null?e.os=this.os:delete e.os,this.cpu!==null?e.cpu=this.cpu:delete e.cpu,this.type!==null?e.type=this.type:delete e.type,this.packageManager!==null?e.packageManager=this.packageManager:delete e.packageManager,this.private?e.private=!0:delete e.private,this.license!==null?e.license=this.license:delete e.license,this.languageName!==null?e.languageName=this.languageName:delete e.languageName,this.main!==null?e.main=this.main:delete e.main,this.module!==null?e.module=this.module:delete e.module,this.browser!==null){let n=this.browser;typeof n=="string"?e.browser=n:n instanceof Map&&(e.browser=Object.assign({},...Array.from(n.keys()).sort().map(c=>({[c]:n.get(c)}))))}else delete e.browser;this.bin.size===1&&this.name!==null&&this.bin.has(this.name.name)?e.bin=this.bin.get(this.name.name):this.bin.size>0?e.bin=Object.assign({},...Array.from(this.bin.keys()).sort().map(n=>({[n]:this.bin.get(n)}))):delete e.bin,this.workspaceDefinitions.length>0?this.raw.workspaces&&!Array.isArray(this.raw.workspaces)?e.workspaces={...this.raw.workspaces,packages:this.workspaceDefinitions.map(({pattern:n})=>n)}:e.workspaces=this.workspaceDefinitions.map(({pattern:n})=>n):this.raw.workspaces&&!Array.isArray(this.raw.workspaces)&&Object.keys(this.raw.workspaces).length>0?e.workspaces=this.raw.workspaces:delete e.workspaces;let s=[],a=[];for(let n of this.dependencies.values()){let c=this.dependenciesMeta.get(un(n)),f=!1;if(r&&c){let p=c.get(null);p&&p.optional&&(f=!0)}f?a.push(n):s.push(n)}s.length>0?e.dependencies=Object.assign({},...sI(s).map(n=>({[un(n)]:n.range}))):delete e.dependencies,a.length>0?e.optionalDependencies=Object.assign({},...sI(a).map(n=>({[un(n)]:n.range}))):delete e.optionalDependencies,this.devDependencies.size>0?e.devDependencies=Object.assign({},...sI(this.devDependencies.values()).map(n=>({[un(n)]:n.range}))):delete e.devDependencies,this.peerDependencies.size>0?e.peerDependencies=Object.assign({},...sI(this.peerDependencies.values()).map(n=>({[un(n)]:n.range}))):delete e.peerDependencies,e.dependenciesMeta={};for(let[n,c]of qs(this.dependenciesMeta.entries(),([f,p])=>f))for(let[f,p]of qs(c.entries(),([h,E])=>h!==null?`0${h}`:"1")){let h=f!==null?al(On(Sa(n),f)):n,E={...p};r&&f===null&&delete E.optional,Object.keys(E).length!==0&&(e.dependenciesMeta[h]=E)}if(Object.keys(e.dependenciesMeta).length===0&&delete e.dependenciesMeta,this.peerDependenciesMeta.size>0?e.peerDependenciesMeta=Object.assign({},...qs(this.peerDependenciesMeta.entries(),([n,c])=>n).map(([n,c])=>({[n]:c}))):delete e.peerDependenciesMeta,this.resolutions.length>0?e.resolutions=Object.assign({},...this.resolutions.map(({pattern:n,reference:c})=>({[hx(n)]:c}))):delete e.resolutions,this.files!==null?e.files=Array.from(this.files):delete e.files,this.preferUnplugged!==null?e.preferUnplugged=this.preferUnplugged:delete e.preferUnplugged,this.scripts!==null&&this.scripts.size>0){e.scripts??={};for(let n of Object.keys(e.scripts))this.scripts.has(n)||delete e.scripts[n];for(let[n,c]of this.scripts.entries())e.scripts[n]=c}else delete e.scripts;return e}}});function Aet(t){return typeof t.reportCode<"u"}var pue,hue,fet,jt,Ao,Tc=Xe(()=>{ql();pue=Ie("stream"),hue=Ie("string_decoder"),fet=15,jt=class extends Error{constructor(r,s,a){super(s);this.reportExtra=a;this.reportCode=r}};Ao=class{constructor(){this.cacheHits=new Set;this.cacheMisses=new Set;this.reportedInfos=new Set;this.reportedWarnings=new Set;this.reportedErrors=new Set}getRecommendedLength(){return 180}reportCacheHit(e){this.cacheHits.add(e.locatorHash)}reportCacheMiss(e,r){this.cacheMisses.add(e.locatorHash)}static progressViaCounter(e){let r=0,s,a=new Promise(p=>{s=p}),n=p=>{let h=s;a=new Promise(E=>{s=E}),r=p,h()},c=(p=0)=>{n(r+1)},f=async function*(){for(;r{r=c}),a=Q4(c=>{let f=r;s=new Promise(p=>{r=p}),e=c,f()},1e3/fet),n=async function*(){for(;;)await s,yield{title:e}}();return{[Symbol.asyncIterator](){return n},hasProgress:!1,hasTitle:!0,setTitle:a}}async startProgressPromise(e,r){let s=this.reportProgress(e);try{return await r(e)}finally{s.stop()}}startProgressSync(e,r){let s=this.reportProgress(e);try{return r(e)}finally{s.stop()}}reportInfoOnce(e,r,s){let a=s&&s.key?s.key:r;this.reportedInfos.has(a)||(this.reportedInfos.add(a),this.reportInfo(e,r),s?.reportExtra?.(this))}reportWarningOnce(e,r,s){let a=s&&s.key?s.key:r;this.reportedWarnings.has(a)||(this.reportedWarnings.add(a),this.reportWarning(e,r),s?.reportExtra?.(this))}reportErrorOnce(e,r,s){let a=s&&s.key?s.key:r;this.reportedErrors.has(a)||(this.reportedErrors.add(a),this.reportError(e,r),s?.reportExtra?.(this))}reportExceptionOnce(e){Aet(e)?this.reportErrorOnce(e.reportCode,e.message,{key:e,reportExtra:e.reportExtra}):this.reportErrorOnce(1,e.stack||e.message,{key:e})}createStreamReporter(e=null){let r=new pue.PassThrough,s=new hue.StringDecoder,a="";return r.on("data",n=>{let c=s.write(n),f;do if(f=c.indexOf(` +`),f!==-1){let p=a+c.substring(0,f);c=c.substring(f+1),a="",e!==null?this.reportInfo(null,`${e} ${p}`):this.reportInfo(null,p)}while(f!==-1);a+=c}),r.on("end",()=>{let n=s.end();n!==""&&(e!==null?this.reportInfo(null,`${e} ${n}`):this.reportInfo(null,n))}),r}}});var aI,R8=Xe(()=>{Tc();Wo();aI=class{constructor(e){this.fetchers=e}supports(e,r){return!!this.tryFetcher(e,r)}getLocalPath(e,r){return this.getFetcher(e,r).getLocalPath(e,r)}async fetch(e,r){return await this.getFetcher(e,r).fetch(e,r)}tryFetcher(e,r){let s=this.fetchers.find(a=>a.supports(e,r));return s||null}getFetcher(e,r){let s=this.fetchers.find(a=>a.supports(e,r));if(!s)throw new jt(11,`${Yr(r.project.configuration,e)} isn't supported by any available fetcher`);return s}}});var rm,F8=Xe(()=>{Wo();rm=class{constructor(e){this.resolvers=e.filter(r=>r)}supportsDescriptor(e,r){return!!this.tryResolverByDescriptor(e,r)}supportsLocator(e,r){return!!this.tryResolverByLocator(e,r)}shouldPersistResolution(e,r){return this.getResolverByLocator(e,r).shouldPersistResolution(e,r)}bindDescriptor(e,r,s){return this.getResolverByDescriptor(e,s).bindDescriptor(e,r,s)}getResolutionDependencies(e,r){return this.getResolverByDescriptor(e,r).getResolutionDependencies(e,r)}async getCandidates(e,r,s){return await this.getResolverByDescriptor(e,s).getCandidates(e,r,s)}async getSatisfying(e,r,s,a){return this.getResolverByDescriptor(e,a).getSatisfying(e,r,s,a)}async resolve(e,r){return await this.getResolverByLocator(e,r).resolve(e,r)}tryResolverByDescriptor(e,r){let s=this.resolvers.find(a=>a.supportsDescriptor(e,r));return s||null}getResolverByDescriptor(e,r){let s=this.resolvers.find(a=>a.supportsDescriptor(e,r));if(!s)throw new Error(`${ni(r.project.configuration,e)} isn't supported by any available resolver`);return s}tryResolverByLocator(e,r){let s=this.resolvers.find(a=>a.supportsLocator(e,r));return s||null}getResolverByLocator(e,r){let s=this.resolvers.find(a=>a.supportsLocator(e,r));if(!s)throw new Error(`${Yr(r.project.configuration,e)} isn't supported by any available resolver`);return s}}});var lI,N8=Xe(()=>{Dt();Wo();lI=class{supports(e){return!!e.reference.startsWith("virtual:")}getLocalPath(e,r){let s=e.reference.indexOf("#");if(s===-1)throw new Error("Invalid virtual package reference");let a=e.reference.slice(s+1),n=Ws(e,a);return r.fetcher.getLocalPath(n,r)}async fetch(e,r){let s=e.reference.indexOf("#");if(s===-1)throw new Error("Invalid virtual package reference");let a=e.reference.slice(s+1),n=Ws(e,a),c=await r.fetcher.fetch(n,r);return await this.ensureVirtualLink(e,c,r)}getLocatorFilename(e){return nI(e)}async ensureVirtualLink(e,r,s){let a=r.packageFs.getRealPath(),n=s.project.configuration.get("virtualFolder"),c=this.getLocatorFilename(e),f=uo.makeVirtualPath(n,c,a),p=new _f(f,{baseFs:r.packageFs,pathUtils:J});return{...r,packageFs:p}}}});var FQ,gue=Xe(()=>{FQ=class t{static{this.protocol="virtual:"}static isVirtualDescriptor(e){return!!e.range.startsWith(t.protocol)}static isVirtualLocator(e){return!!e.reference.startsWith(t.protocol)}supportsDescriptor(e,r){return t.isVirtualDescriptor(e)}supportsLocator(e,r){return t.isVirtualLocator(e)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,s){throw new Error('Assertion failed: calling "bindDescriptor" on a virtual descriptor is unsupported')}getResolutionDependencies(e,r){throw new Error('Assertion failed: calling "getResolutionDependencies" on a virtual descriptor is unsupported')}async getCandidates(e,r,s){throw new Error('Assertion failed: calling "getCandidates" on a virtual descriptor is unsupported')}async getSatisfying(e,r,s,a){throw new Error('Assertion failed: calling "getSatisfying" on a virtual descriptor is unsupported')}async resolve(e,r){throw new Error('Assertion failed: calling "resolve" on a virtual locator is unsupported')}}});var cI,O8=Xe(()=>{Dt();tm();cI=class{supports(e){return!!e.reference.startsWith(Ei.protocol)}getLocalPath(e,r){return this.getWorkspace(e,r).cwd}async fetch(e,r){let s=this.getWorkspace(e,r).cwd;return{packageFs:new Sn(s),prefixPath:vt.dot,localPath:s}}getWorkspace(e,r){return r.project.getWorkspaceByCwd(e.reference.slice(Ei.protocol.length))}}});function WB(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function due(t){return typeof t>"u"?3:WB(t)?0:Array.isArray(t)?1:2}function U8(t,e){return Object.hasOwn(t,e)}function het(t){return WB(t)&&U8(t,"onConflict")&&typeof t.onConflict=="string"}function get(t){if(typeof t>"u")return{onConflict:"default",value:t};if(!het(t))return{onConflict:"default",value:t};if(U8(t,"value"))return t;let{onConflict:e,...r}=t;return{onConflict:e,value:r}}function mue(t,e){let r=WB(t)&&U8(t,e)?t[e]:void 0;return get(r)}function uI(t,e){return[t,e,yue]}function _8(t){return Array.isArray(t)?t[2]===yue:!1}function L8(t,e){if(WB(t)){let r={};for(let s of Object.keys(t))r[s]=L8(t[s],e);return uI(e,r)}return Array.isArray(t)?uI(e,t.map(r=>L8(r,e))):uI(e,t)}function M8(t,e,r,s,a){let n,c=[],f=a,p=0;for(let E=a-1;E>=s;--E){let[C,S]=t[E],{onConflict:P,value:I}=mue(S,r),R=due(I);if(R!==3){if(n??=R,R!==n||P==="hardReset"){p=f;break}if(R===2)return uI(C,I);if(c.unshift([C,I]),P==="reset"){p=E;break}P==="extend"&&E===s&&(s=0),f=E}}if(typeof n>"u")return null;let h=c.map(([E])=>E).join(", ");switch(n){case 1:return uI(h,new Array().concat(...c.map(([E,C])=>C.map(S=>L8(S,E)))));case 0:{let E=Object.assign({},...c.map(([,R])=>R)),C=Object.keys(E),S={},P=t.map(([R,N])=>[R,mue(N,r).value]),I=pet(P,([R,N])=>{let U=due(N);return U!==0&&U!==3});if(I!==-1){let R=P.slice(I+1);for(let N of C)S[N]=M8(R,e,N,0,R.length)}else for(let R of C)S[R]=M8(P,e,R,p,P.length);return uI(h,S)}default:throw new Error("Assertion failed: Non-extendable value type")}}function Eue(t){return M8(t.map(([e,r])=>[e,{".":r}]),[],".",0,t.length)}function YB(t){return _8(t)?t[1]:t}function NQ(t){let e=_8(t)?t[1]:t;if(Array.isArray(e))return e.map(r=>NQ(r));if(WB(e)){let r={};for(let[s,a]of Object.entries(e))r[s]=NQ(a);return r}return e}function H8(t){return _8(t)?t[0]:null}var pet,yue,Iue=Xe(()=>{pet=(t,e,r)=>{let s=[...t];return s.reverse(),s.findIndex(e,r)};yue=Symbol()});var OQ={};Vt(OQ,{getDefaultGlobalFolder:()=>G8,getHomeFolder:()=>fI,isFolderInside:()=>q8});function G8(){if(process.platform==="win32"){let t=fe.toPortablePath(process.env.LOCALAPPDATA||fe.join((0,j8.homedir)(),"AppData","Local"));return J.resolve(t,"Yarn/Berry")}if(process.env.XDG_DATA_HOME){let t=fe.toPortablePath(process.env.XDG_DATA_HOME);return J.resolve(t,"yarn/berry")}return J.resolve(fI(),".yarn/berry")}function fI(){return fe.toPortablePath((0,j8.homedir)()||"/usr/local/share")}function q8(t,e){let r=J.relative(e,t);return r&&!r.startsWith("..")&&!J.isAbsolute(r)}var j8,LQ=Xe(()=>{Dt();j8=Ie("os")});var Bue=_((EMt,wue)=>{"use strict";var W8=Ie("https"),Y8=Ie("http"),{URL:Cue}=Ie("url"),V8=class extends Y8.Agent{constructor(e){let{proxy:r,proxyRequestOptions:s,...a}=e;super(a),this.proxy=typeof r=="string"?new Cue(r):r,this.proxyRequestOptions=s||{}}createConnection(e,r){let s={...this.proxyRequestOptions,method:"CONNECT",host:this.proxy.hostname,port:this.proxy.port,path:`${e.host}:${e.port}`,setHost:!1,headers:{...this.proxyRequestOptions.headers,connection:this.keepAlive?"keep-alive":"close",host:`${e.host}:${e.port}`},agent:!1,timeout:e.timeout||0};if(this.proxy.username||this.proxy.password){let n=Buffer.from(`${decodeURIComponent(this.proxy.username||"")}:${decodeURIComponent(this.proxy.password||"")}`).toString("base64");s.headers["proxy-authorization"]=`Basic ${n}`}this.proxy.protocol==="https:"&&(s.servername=this.proxy.hostname);let a=(this.proxy.protocol==="http:"?Y8:W8).request(s);a.once("connect",(n,c,f)=>{a.removeAllListeners(),c.removeAllListeners(),n.statusCode===200?r(null,c):(c.destroy(),r(new Error(`Bad response: ${n.statusCode}`),null))}),a.once("timeout",()=>{a.destroy(new Error("Proxy timeout"))}),a.once("error",n=>{a.removeAllListeners(),r(n,null)}),a.end()}},J8=class extends W8.Agent{constructor(e){let{proxy:r,proxyRequestOptions:s,...a}=e;super(a),this.proxy=typeof r=="string"?new Cue(r):r,this.proxyRequestOptions=s||{}}createConnection(e,r){let s={...this.proxyRequestOptions,method:"CONNECT",host:this.proxy.hostname,port:this.proxy.port,path:`${e.host}:${e.port}`,setHost:!1,headers:{...this.proxyRequestOptions.headers,connection:this.keepAlive?"keep-alive":"close",host:`${e.host}:${e.port}`},agent:!1,timeout:e.timeout||0};if(this.proxy.username||this.proxy.password){let n=Buffer.from(`${decodeURIComponent(this.proxy.username||"")}:${decodeURIComponent(this.proxy.password||"")}`).toString("base64");s.headers["proxy-authorization"]=`Basic ${n}`}this.proxy.protocol==="https:"&&(s.servername=this.proxy.hostname);let a=(this.proxy.protocol==="http:"?Y8:W8).request(s);a.once("connect",(n,c,f)=>{if(a.removeAllListeners(),c.removeAllListeners(),n.statusCode===200){let p=super.createConnection({...e,socket:c});r(null,p)}else c.destroy(),r(new Error(`Bad response: ${n.statusCode}`),null)}),a.once("timeout",()=>{a.destroy(new Error("Proxy timeout"))}),a.once("error",n=>{a.removeAllListeners(),r(n,null)}),a.end()}};wue.exports={HttpProxyAgent:V8,HttpsProxyAgent:J8}});var K8,vue,Sue,Due=Xe(()=>{K8=ut(Bue(),1),vue=K8.default.HttpProxyAgent,Sue=K8.default.HttpsProxyAgent});var Np=_((Fp,MQ)=>{"use strict";Object.defineProperty(Fp,"__esModule",{value:!0});var bue=["Int8Array","Uint8Array","Uint8ClampedArray","Int16Array","Uint16Array","Int32Array","Uint32Array","Float32Array","Float64Array","BigInt64Array","BigUint64Array"];function met(t){return bue.includes(t)}var yet=["Function","Generator","AsyncGenerator","GeneratorFunction","AsyncGeneratorFunction","AsyncFunction","Observable","Array","Buffer","Blob","Object","RegExp","Date","Error","Map","Set","WeakMap","WeakSet","ArrayBuffer","SharedArrayBuffer","DataView","Promise","URL","FormData","URLSearchParams","HTMLElement",...bue];function Eet(t){return yet.includes(t)}var Iet=["null","undefined","string","number","bigint","boolean","symbol"];function Cet(t){return Iet.includes(t)}function AI(t){return e=>typeof e===t}var{toString:Pue}=Object.prototype,VB=t=>{let e=Pue.call(t).slice(8,-1);if(/HTML\w+Element/.test(e)&&be.domElement(t))return"HTMLElement";if(Eet(e))return e},pi=t=>e=>VB(e)===t;function be(t){if(t===null)return"null";switch(typeof t){case"undefined":return"undefined";case"string":return"string";case"number":return"number";case"boolean":return"boolean";case"function":return"Function";case"bigint":return"bigint";case"symbol":return"symbol";default:}if(be.observable(t))return"Observable";if(be.array(t))return"Array";if(be.buffer(t))return"Buffer";let e=VB(t);if(e)return e;if(t instanceof String||t instanceof Boolean||t instanceof Number)throw new TypeError("Please don't use object wrappers for primitive types");return"Object"}be.undefined=AI("undefined");be.string=AI("string");var wet=AI("number");be.number=t=>wet(t)&&!be.nan(t);be.bigint=AI("bigint");be.function_=AI("function");be.null_=t=>t===null;be.class_=t=>be.function_(t)&&t.toString().startsWith("class ");be.boolean=t=>t===!0||t===!1;be.symbol=AI("symbol");be.numericString=t=>be.string(t)&&!be.emptyStringOrWhitespace(t)&&!Number.isNaN(Number(t));be.array=(t,e)=>Array.isArray(t)?be.function_(e)?t.every(e):!0:!1;be.buffer=t=>{var e,r,s,a;return(a=(s=(r=(e=t)===null||e===void 0?void 0:e.constructor)===null||r===void 0?void 0:r.isBuffer)===null||s===void 0?void 0:s.call(r,t))!==null&&a!==void 0?a:!1};be.blob=t=>pi("Blob")(t);be.nullOrUndefined=t=>be.null_(t)||be.undefined(t);be.object=t=>!be.null_(t)&&(typeof t=="object"||be.function_(t));be.iterable=t=>{var e;return be.function_((e=t)===null||e===void 0?void 0:e[Symbol.iterator])};be.asyncIterable=t=>{var e;return be.function_((e=t)===null||e===void 0?void 0:e[Symbol.asyncIterator])};be.generator=t=>{var e,r;return be.iterable(t)&&be.function_((e=t)===null||e===void 0?void 0:e.next)&&be.function_((r=t)===null||r===void 0?void 0:r.throw)};be.asyncGenerator=t=>be.asyncIterable(t)&&be.function_(t.next)&&be.function_(t.throw);be.nativePromise=t=>pi("Promise")(t);var Bet=t=>{var e,r;return be.function_((e=t)===null||e===void 0?void 0:e.then)&&be.function_((r=t)===null||r===void 0?void 0:r.catch)};be.promise=t=>be.nativePromise(t)||Bet(t);be.generatorFunction=pi("GeneratorFunction");be.asyncGeneratorFunction=t=>VB(t)==="AsyncGeneratorFunction";be.asyncFunction=t=>VB(t)==="AsyncFunction";be.boundFunction=t=>be.function_(t)&&!t.hasOwnProperty("prototype");be.regExp=pi("RegExp");be.date=pi("Date");be.error=pi("Error");be.map=t=>pi("Map")(t);be.set=t=>pi("Set")(t);be.weakMap=t=>pi("WeakMap")(t);be.weakSet=t=>pi("WeakSet")(t);be.int8Array=pi("Int8Array");be.uint8Array=pi("Uint8Array");be.uint8ClampedArray=pi("Uint8ClampedArray");be.int16Array=pi("Int16Array");be.uint16Array=pi("Uint16Array");be.int32Array=pi("Int32Array");be.uint32Array=pi("Uint32Array");be.float32Array=pi("Float32Array");be.float64Array=pi("Float64Array");be.bigInt64Array=pi("BigInt64Array");be.bigUint64Array=pi("BigUint64Array");be.arrayBuffer=pi("ArrayBuffer");be.sharedArrayBuffer=pi("SharedArrayBuffer");be.dataView=pi("DataView");be.enumCase=(t,e)=>Object.values(e).includes(t);be.directInstanceOf=(t,e)=>Object.getPrototypeOf(t)===e.prototype;be.urlInstance=t=>pi("URL")(t);be.urlString=t=>{if(!be.string(t))return!1;try{return new URL(t),!0}catch{return!1}};be.truthy=t=>!!t;be.falsy=t=>!t;be.nan=t=>Number.isNaN(t);be.primitive=t=>be.null_(t)||Cet(typeof t);be.integer=t=>Number.isInteger(t);be.safeInteger=t=>Number.isSafeInteger(t);be.plainObject=t=>{if(Pue.call(t)!=="[object Object]")return!1;let e=Object.getPrototypeOf(t);return e===null||e===Object.getPrototypeOf({})};be.typedArray=t=>met(VB(t));var vet=t=>be.safeInteger(t)&&t>=0;be.arrayLike=t=>!be.nullOrUndefined(t)&&!be.function_(t)&&vet(t.length);be.inRange=(t,e)=>{if(be.number(e))return t>=Math.min(0,e)&&t<=Math.max(e,0);if(be.array(e)&&e.length===2)return t>=Math.min(...e)&&t<=Math.max(...e);throw new TypeError(`Invalid range: ${JSON.stringify(e)}`)};var Det=1,bet=["innerHTML","ownerDocument","style","attributes","nodeValue"];be.domElement=t=>be.object(t)&&t.nodeType===Det&&be.string(t.nodeName)&&!be.plainObject(t)&&bet.every(e=>e in t);be.observable=t=>{var e,r,s,a;return t?t===((r=(e=t)[Symbol.observable])===null||r===void 0?void 0:r.call(e))||t===((a=(s=t)["@@observable"])===null||a===void 0?void 0:a.call(s)):!1};be.nodeStream=t=>be.object(t)&&be.function_(t.pipe)&&!be.observable(t);be.infinite=t=>t===1/0||t===-1/0;var xue=t=>e=>be.integer(e)&&Math.abs(e%2)===t;be.evenInteger=xue(0);be.oddInteger=xue(1);be.emptyArray=t=>be.array(t)&&t.length===0;be.nonEmptyArray=t=>be.array(t)&&t.length>0;be.emptyString=t=>be.string(t)&&t.length===0;var Pet=t=>be.string(t)&&!/\S/.test(t);be.emptyStringOrWhitespace=t=>be.emptyString(t)||Pet(t);be.nonEmptyString=t=>be.string(t)&&t.length>0;be.nonEmptyStringAndNotWhitespace=t=>be.string(t)&&!be.emptyStringOrWhitespace(t);be.emptyObject=t=>be.object(t)&&!be.map(t)&&!be.set(t)&&Object.keys(t).length===0;be.nonEmptyObject=t=>be.object(t)&&!be.map(t)&&!be.set(t)&&Object.keys(t).length>0;be.emptySet=t=>be.set(t)&&t.size===0;be.nonEmptySet=t=>be.set(t)&&t.size>0;be.emptyMap=t=>be.map(t)&&t.size===0;be.nonEmptyMap=t=>be.map(t)&&t.size>0;be.propertyKey=t=>be.any([be.string,be.number,be.symbol],t);be.formData=t=>pi("FormData")(t);be.urlSearchParams=t=>pi("URLSearchParams")(t);var kue=(t,e,r)=>{if(!be.function_(e))throw new TypeError(`Invalid predicate: ${JSON.stringify(e)}`);if(r.length===0)throw new TypeError("Invalid number of values");return t.call(r,e)};be.any=(t,...e)=>(be.array(t)?t:[t]).some(s=>kue(Array.prototype.some,s,e));be.all=(t,...e)=>kue(Array.prototype.every,t,e);var _t=(t,e,r,s={})=>{if(!t){let{multipleValues:a}=s,n=a?`received values of types ${[...new Set(r.map(c=>`\`${be(c)}\``))].join(", ")}`:`received value of type \`${be(r)}\``;throw new TypeError(`Expected value which is \`${e}\`, ${n}.`)}};Fp.assert={undefined:t=>_t(be.undefined(t),"undefined",t),string:t=>_t(be.string(t),"string",t),number:t=>_t(be.number(t),"number",t),bigint:t=>_t(be.bigint(t),"bigint",t),function_:t=>_t(be.function_(t),"Function",t),null_:t=>_t(be.null_(t),"null",t),class_:t=>_t(be.class_(t),"Class",t),boolean:t=>_t(be.boolean(t),"boolean",t),symbol:t=>_t(be.symbol(t),"symbol",t),numericString:t=>_t(be.numericString(t),"string with a number",t),array:(t,e)=>{_t(be.array(t),"Array",t),e&&t.forEach(e)},buffer:t=>_t(be.buffer(t),"Buffer",t),blob:t=>_t(be.blob(t),"Blob",t),nullOrUndefined:t=>_t(be.nullOrUndefined(t),"null or undefined",t),object:t=>_t(be.object(t),"Object",t),iterable:t=>_t(be.iterable(t),"Iterable",t),asyncIterable:t=>_t(be.asyncIterable(t),"AsyncIterable",t),generator:t=>_t(be.generator(t),"Generator",t),asyncGenerator:t=>_t(be.asyncGenerator(t),"AsyncGenerator",t),nativePromise:t=>_t(be.nativePromise(t),"native Promise",t),promise:t=>_t(be.promise(t),"Promise",t),generatorFunction:t=>_t(be.generatorFunction(t),"GeneratorFunction",t),asyncGeneratorFunction:t=>_t(be.asyncGeneratorFunction(t),"AsyncGeneratorFunction",t),asyncFunction:t=>_t(be.asyncFunction(t),"AsyncFunction",t),boundFunction:t=>_t(be.boundFunction(t),"Function",t),regExp:t=>_t(be.regExp(t),"RegExp",t),date:t=>_t(be.date(t),"Date",t),error:t=>_t(be.error(t),"Error",t),map:t=>_t(be.map(t),"Map",t),set:t=>_t(be.set(t),"Set",t),weakMap:t=>_t(be.weakMap(t),"WeakMap",t),weakSet:t=>_t(be.weakSet(t),"WeakSet",t),int8Array:t=>_t(be.int8Array(t),"Int8Array",t),uint8Array:t=>_t(be.uint8Array(t),"Uint8Array",t),uint8ClampedArray:t=>_t(be.uint8ClampedArray(t),"Uint8ClampedArray",t),int16Array:t=>_t(be.int16Array(t),"Int16Array",t),uint16Array:t=>_t(be.uint16Array(t),"Uint16Array",t),int32Array:t=>_t(be.int32Array(t),"Int32Array",t),uint32Array:t=>_t(be.uint32Array(t),"Uint32Array",t),float32Array:t=>_t(be.float32Array(t),"Float32Array",t),float64Array:t=>_t(be.float64Array(t),"Float64Array",t),bigInt64Array:t=>_t(be.bigInt64Array(t),"BigInt64Array",t),bigUint64Array:t=>_t(be.bigUint64Array(t),"BigUint64Array",t),arrayBuffer:t=>_t(be.arrayBuffer(t),"ArrayBuffer",t),sharedArrayBuffer:t=>_t(be.sharedArrayBuffer(t),"SharedArrayBuffer",t),dataView:t=>_t(be.dataView(t),"DataView",t),enumCase:(t,e)=>_t(be.enumCase(t,e),"EnumCase",t),urlInstance:t=>_t(be.urlInstance(t),"URL",t),urlString:t=>_t(be.urlString(t),"string with a URL",t),truthy:t=>_t(be.truthy(t),"truthy",t),falsy:t=>_t(be.falsy(t),"falsy",t),nan:t=>_t(be.nan(t),"NaN",t),primitive:t=>_t(be.primitive(t),"primitive",t),integer:t=>_t(be.integer(t),"integer",t),safeInteger:t=>_t(be.safeInteger(t),"integer",t),plainObject:t=>_t(be.plainObject(t),"plain object",t),typedArray:t=>_t(be.typedArray(t),"TypedArray",t),arrayLike:t=>_t(be.arrayLike(t),"array-like",t),domElement:t=>_t(be.domElement(t),"HTMLElement",t),observable:t=>_t(be.observable(t),"Observable",t),nodeStream:t=>_t(be.nodeStream(t),"Node.js Stream",t),infinite:t=>_t(be.infinite(t),"infinite number",t),emptyArray:t=>_t(be.emptyArray(t),"empty array",t),nonEmptyArray:t=>_t(be.nonEmptyArray(t),"non-empty array",t),emptyString:t=>_t(be.emptyString(t),"empty string",t),emptyStringOrWhitespace:t=>_t(be.emptyStringOrWhitespace(t),"empty string or whitespace",t),nonEmptyString:t=>_t(be.nonEmptyString(t),"non-empty string",t),nonEmptyStringAndNotWhitespace:t=>_t(be.nonEmptyStringAndNotWhitespace(t),"non-empty string and not whitespace",t),emptyObject:t=>_t(be.emptyObject(t),"empty object",t),nonEmptyObject:t=>_t(be.nonEmptyObject(t),"non-empty object",t),emptySet:t=>_t(be.emptySet(t),"empty set",t),nonEmptySet:t=>_t(be.nonEmptySet(t),"non-empty set",t),emptyMap:t=>_t(be.emptyMap(t),"empty map",t),nonEmptyMap:t=>_t(be.nonEmptyMap(t),"non-empty map",t),propertyKey:t=>_t(be.propertyKey(t),"PropertyKey",t),formData:t=>_t(be.formData(t),"FormData",t),urlSearchParams:t=>_t(be.urlSearchParams(t),"URLSearchParams",t),evenInteger:t=>_t(be.evenInteger(t),"even integer",t),oddInteger:t=>_t(be.oddInteger(t),"odd integer",t),directInstanceOf:(t,e)=>_t(be.directInstanceOf(t,e),"T",t),inRange:(t,e)=>_t(be.inRange(t,e),"in range",t),any:(t,...e)=>_t(be.any(t,...e),"predicate returns truthy for any value",e,{multipleValues:!0}),all:(t,...e)=>_t(be.all(t,...e),"predicate returns truthy for all values",e,{multipleValues:!0})};Object.defineProperties(be,{class:{value:be.class_},function:{value:be.function_},null:{value:be.null_}});Object.defineProperties(Fp.assert,{class:{value:Fp.assert.class_},function:{value:Fp.assert.function_},null:{value:Fp.assert.null_}});Fp.default=be;MQ.exports=be;MQ.exports.default=be;MQ.exports.assert=Fp.assert});var Que=_((CMt,z8)=>{"use strict";var UQ=class extends Error{constructor(e){super(e||"Promise was canceled"),this.name="CancelError"}get isCanceled(){return!0}},_Q=class t{static fn(e){return(...r)=>new t((s,a,n)=>{r.push(n),e(...r).then(s,a)})}constructor(e){this._cancelHandlers=[],this._isPending=!0,this._isCanceled=!1,this._rejectOnCancel=!0,this._promise=new Promise((r,s)=>{this._reject=s;let a=f=>{this._isPending=!1,r(f)},n=f=>{this._isPending=!1,s(f)},c=f=>{if(!this._isPending)throw new Error("The `onCancel` handler was attached after the promise settled.");this._cancelHandlers.push(f)};return Object.defineProperties(c,{shouldReject:{get:()=>this._rejectOnCancel,set:f=>{this._rejectOnCancel=f}}}),e(a,n,c)})}then(e,r){return this._promise.then(e,r)}catch(e){return this._promise.catch(e)}finally(e){return this._promise.finally(e)}cancel(e){if(!(!this._isPending||this._isCanceled)){if(this._cancelHandlers.length>0)try{for(let r of this._cancelHandlers)r()}catch(r){this._reject(r)}this._isCanceled=!0,this._rejectOnCancel&&this._reject(new UQ(e))}}get isCanceled(){return this._isCanceled}};Object.setPrototypeOf(_Q.prototype,Promise.prototype);z8.exports=_Q;z8.exports.CancelError=UQ});var Tue=_((Z8,$8)=>{"use strict";Object.defineProperty(Z8,"__esModule",{value:!0});function xet(t){return t.encrypted}var X8=(t,e)=>{let r;typeof e=="function"?r={connect:e}:r=e;let s=typeof r.connect=="function",a=typeof r.secureConnect=="function",n=typeof r.close=="function",c=()=>{s&&r.connect(),xet(t)&&a&&(t.authorized?r.secureConnect():t.authorizationError||t.once("secureConnect",r.secureConnect)),n&&t.once("close",r.close)};t.writable&&!t.connecting?c():t.connecting?t.once("connect",c):t.destroyed&&n&&r.close(t._hadError)};Z8.default=X8;$8.exports=X8;$8.exports.default=X8});var Rue=_((tH,rH)=>{"use strict";Object.defineProperty(tH,"__esModule",{value:!0});var ket=Tue(),Qet=Number(process.versions.node.split(".")[0]),eH=t=>{let e={start:Date.now(),socket:void 0,lookup:void 0,connect:void 0,secureConnect:void 0,upload:void 0,response:void 0,end:void 0,error:void 0,abort:void 0,phases:{wait:void 0,dns:void 0,tcp:void 0,tls:void 0,request:void 0,firstByte:void 0,download:void 0,total:void 0}};t.timings=e;let r=c=>{let f=c.emit.bind(c);c.emit=(p,...h)=>(p==="error"&&(e.error=Date.now(),e.phases.total=e.error-e.start,c.emit=f),f(p,...h))};r(t),t.prependOnceListener("abort",()=>{e.abort=Date.now(),(!e.response||Qet>=13)&&(e.phases.total=Date.now()-e.start)});let s=c=>{e.socket=Date.now(),e.phases.wait=e.socket-e.start;let f=()=>{e.lookup=Date.now(),e.phases.dns=e.lookup-e.socket};c.prependOnceListener("lookup",f),ket.default(c,{connect:()=>{e.connect=Date.now(),e.lookup===void 0&&(c.removeListener("lookup",f),e.lookup=e.connect,e.phases.dns=e.lookup-e.socket),e.phases.tcp=e.connect-e.lookup},secureConnect:()=>{e.secureConnect=Date.now(),e.phases.tls=e.secureConnect-e.connect}})};t.socket?s(t.socket):t.prependOnceListener("socket",s);let a=()=>{var c;e.upload=Date.now(),e.phases.request=e.upload-(c=e.secureConnect,c??e.connect)};return(typeof t.writableFinished=="boolean"?t.writableFinished:t.finished&&t.outputSize===0&&(!t.socket||t.socket.writableLength===0))?a():t.prependOnceListener("finish",a),t.prependOnceListener("response",c=>{e.response=Date.now(),e.phases.firstByte=e.response-e.upload,c.timings=e,r(c),c.prependOnceListener("end",()=>{e.end=Date.now(),e.phases.download=e.end-e.response,e.phases.total=e.end-e.start})}),e};tH.default=eH;rH.exports=eH;rH.exports.default=eH});var _ue=_((wMt,sH)=>{"use strict";var{V4MAPPED:Tet,ADDRCONFIG:Ret,ALL:Uue,promises:{Resolver:Fue},lookup:Fet}=Ie("dns"),{promisify:nH}=Ie("util"),Net=Ie("os"),pI=Symbol("cacheableLookupCreateConnection"),iH=Symbol("cacheableLookupInstance"),Nue=Symbol("expires"),Oet=typeof Uue=="number",Oue=t=>{if(!(t&&typeof t.createConnection=="function"))throw new Error("Expected an Agent instance as the first argument")},Let=t=>{for(let e of t)e.family!==6&&(e.address=`::ffff:${e.address}`,e.family=6)},Lue=()=>{let t=!1,e=!1;for(let r of Object.values(Net.networkInterfaces()))for(let s of r)if(!s.internal&&(s.family==="IPv6"?e=!0:t=!0,t&&e))return{has4:t,has6:e};return{has4:t,has6:e}},Met=t=>Symbol.iterator in t,Mue={ttl:!0},Uet={all:!0},HQ=class{constructor({cache:e=new Map,maxTtl:r=1/0,fallbackDuration:s=3600,errorTtl:a=.15,resolver:n=new Fue,lookup:c=Fet}={}){if(this.maxTtl=r,this.errorTtl=a,this._cache=e,this._resolver=n,this._dnsLookup=nH(c),this._resolver instanceof Fue?(this._resolve4=this._resolver.resolve4.bind(this._resolver),this._resolve6=this._resolver.resolve6.bind(this._resolver)):(this._resolve4=nH(this._resolver.resolve4.bind(this._resolver)),this._resolve6=nH(this._resolver.resolve6.bind(this._resolver))),this._iface=Lue(),this._pending={},this._nextRemovalTime=!1,this._hostnamesToFallback=new Set,s<1)this._fallback=!1;else{this._fallback=!0;let f=setInterval(()=>{this._hostnamesToFallback.clear()},s*1e3);f.unref&&f.unref()}this.lookup=this.lookup.bind(this),this.lookupAsync=this.lookupAsync.bind(this)}set servers(e){this.clear(),this._resolver.setServers(e)}get servers(){return this._resolver.getServers()}lookup(e,r,s){if(typeof r=="function"?(s=r,r={}):typeof r=="number"&&(r={family:r}),!s)throw new Error("Callback must be a function.");this.lookupAsync(e,r).then(a=>{r.all?s(null,a):s(null,a.address,a.family,a.expires,a.ttl)},s)}async lookupAsync(e,r={}){typeof r=="number"&&(r={family:r});let s=await this.query(e);if(r.family===6){let a=s.filter(n=>n.family===6);r.hints&Tet&&(Oet&&r.hints&Uue||a.length===0)?Let(s):s=a}else r.family===4&&(s=s.filter(a=>a.family===4));if(r.hints&Ret){let{_iface:a}=this;s=s.filter(n=>n.family===6?a.has6:a.has4)}if(s.length===0){let a=new Error(`cacheableLookup ENOTFOUND ${e}`);throw a.code="ENOTFOUND",a.hostname=e,a}return r.all?s:s[0]}async query(e){let r=await this._cache.get(e);if(!r){let s=this._pending[e];if(s)r=await s;else{let a=this.queryAndCache(e);this._pending[e]=a,r=await a}}return r=r.map(s=>({...s})),r}async _resolve(e){let r=async h=>{try{return await h}catch(E){if(E.code==="ENODATA"||E.code==="ENOTFOUND")return[];throw E}},[s,a]=await Promise.all([this._resolve4(e,Mue),this._resolve6(e,Mue)].map(h=>r(h))),n=0,c=0,f=0,p=Date.now();for(let h of s)h.family=4,h.expires=p+h.ttl*1e3,n=Math.max(n,h.ttl);for(let h of a)h.family=6,h.expires=p+h.ttl*1e3,c=Math.max(c,h.ttl);return s.length>0?a.length>0?f=Math.min(n,c):f=n:f=c,{entries:[...s,...a],cacheTtl:f}}async _lookup(e){try{return{entries:await this._dnsLookup(e,{all:!0}),cacheTtl:0}}catch{return{entries:[],cacheTtl:0}}}async _set(e,r,s){if(this.maxTtl>0&&s>0){s=Math.min(s,this.maxTtl)*1e3,r[Nue]=Date.now()+s;try{await this._cache.set(e,r,s)}catch(a){this.lookupAsync=async()=>{let n=new Error("Cache Error. Please recreate the CacheableLookup instance.");throw n.cause=a,n}}Met(this._cache)&&this._tick(s)}}async queryAndCache(e){if(this._hostnamesToFallback.has(e))return this._dnsLookup(e,Uet);try{let r=await this._resolve(e);r.entries.length===0&&this._fallback&&(r=await this._lookup(e),r.entries.length!==0&&this._hostnamesToFallback.add(e));let s=r.entries.length===0?this.errorTtl:r.cacheTtl;return await this._set(e,r.entries,s),delete this._pending[e],r.entries}catch(r){throw delete this._pending[e],r}}_tick(e){let r=this._nextRemovalTime;(!r||e{this._nextRemovalTime=!1;let s=1/0,a=Date.now();for(let[n,c]of this._cache){let f=c[Nue];a>=f?this._cache.delete(n):f("lookup"in r||(r.lookup=this.lookup),e[pI](r,s))}uninstall(e){if(Oue(e),e[pI]){if(e[iH]!==this)throw new Error("The agent is not owned by this CacheableLookup instance");e.createConnection=e[pI],delete e[pI],delete e[iH]}}updateInterfaceInfo(){let{_iface:e}=this;this._iface=Lue(),(e.has4&&!this._iface.has4||e.has6&&!this._iface.has6)&&this._cache.clear()}clear(e){if(e){this._cache.delete(e);return}this._cache.clear()}};sH.exports=HQ;sH.exports.default=HQ});var Gue=_((BMt,oH)=>{"use strict";var _et=typeof URL>"u"?Ie("url").URL:URL,Het="text/plain",jet="us-ascii",Hue=(t,e)=>e.some(r=>r instanceof RegExp?r.test(t):r===t),Get=(t,{stripHash:e})=>{let r=t.match(/^data:([^,]*?),([^#]*?)(?:#(.*))?$/);if(!r)throw new Error(`Invalid URL: ${t}`);let s=r[1].split(";"),a=r[2],n=e?"":r[3],c=!1;s[s.length-1]==="base64"&&(s.pop(),c=!0);let f=(s.shift()||"").toLowerCase(),h=[...s.map(E=>{let[C,S=""]=E.split("=").map(P=>P.trim());return C==="charset"&&(S=S.toLowerCase(),S===jet)?"":`${C}${S?`=${S}`:""}`}).filter(Boolean)];return c&&h.push("base64"),(h.length!==0||f&&f!==Het)&&h.unshift(f),`data:${h.join(";")},${c?a.trim():a}${n?`#${n}`:""}`},jue=(t,e)=>{if(e={defaultProtocol:"http:",normalizeProtocol:!0,forceHttp:!1,forceHttps:!1,stripAuthentication:!0,stripHash:!1,stripWWW:!0,removeQueryParameters:[/^utm_\w+/i],removeTrailingSlash:!0,removeDirectoryIndex:!1,sortQueryParameters:!0,...e},Reflect.has(e,"normalizeHttps"))throw new Error("options.normalizeHttps is renamed to options.forceHttp");if(Reflect.has(e,"normalizeHttp"))throw new Error("options.normalizeHttp is renamed to options.forceHttps");if(Reflect.has(e,"stripFragment"))throw new Error("options.stripFragment is renamed to options.stripHash");if(t=t.trim(),/^data:/i.test(t))return Get(t,e);let r=t.startsWith("//");!r&&/^\.*\//.test(t)||(t=t.replace(/^(?!(?:\w+:)?\/\/)|^\/\//,e.defaultProtocol));let a=new _et(t);if(e.forceHttp&&e.forceHttps)throw new Error("The `forceHttp` and `forceHttps` options cannot be used together");if(e.forceHttp&&a.protocol==="https:"&&(a.protocol="http:"),e.forceHttps&&a.protocol==="http:"&&(a.protocol="https:"),e.stripAuthentication&&(a.username="",a.password=""),e.stripHash&&(a.hash=""),a.pathname&&(a.pathname=a.pathname.replace(/((?!:).|^)\/{2,}/g,(n,c)=>/^(?!\/)/g.test(c)?`${c}/`:"/")),a.pathname&&(a.pathname=decodeURI(a.pathname)),e.removeDirectoryIndex===!0&&(e.removeDirectoryIndex=[/^index\.[a-z]+$/]),Array.isArray(e.removeDirectoryIndex)&&e.removeDirectoryIndex.length>0){let n=a.pathname.split("/"),c=n[n.length-1];Hue(c,e.removeDirectoryIndex)&&(n=n.slice(0,n.length-1),a.pathname=n.slice(1).join("/")+"/")}if(a.hostname&&(a.hostname=a.hostname.replace(/\.$/,""),e.stripWWW&&/^www\.([a-z\-\d]{2,63})\.([a-z.]{2,5})$/.test(a.hostname)&&(a.hostname=a.hostname.replace(/^www\./,""))),Array.isArray(e.removeQueryParameters))for(let n of[...a.searchParams.keys()])Hue(n,e.removeQueryParameters)&&a.searchParams.delete(n);return e.sortQueryParameters&&a.searchParams.sort(),e.removeTrailingSlash&&(a.pathname=a.pathname.replace(/\/$/,"")),t=a.toString(),(e.removeTrailingSlash||a.pathname==="/")&&a.hash===""&&(t=t.replace(/\/$/,"")),r&&!e.normalizeProtocol&&(t=t.replace(/^http:\/\//,"//")),e.stripProtocol&&(t=t.replace(/^(?:https?:)?\/\//,"")),t};oH.exports=jue;oH.exports.default=jue});var Yue=_((vMt,Wue)=>{Wue.exports=que;function que(t,e){if(t&&e)return que(t)(e);if(typeof t!="function")throw new TypeError("need wrapper function");return Object.keys(t).forEach(function(s){r[s]=t[s]}),r;function r(){for(var s=new Array(arguments.length),a=0;a{var Vue=Yue();aH.exports=Vue(jQ);aH.exports.strict=Vue(Jue);jQ.proto=jQ(function(){Object.defineProperty(Function.prototype,"once",{value:function(){return jQ(this)},configurable:!0}),Object.defineProperty(Function.prototype,"onceStrict",{value:function(){return Jue(this)},configurable:!0})});function jQ(t){var e=function(){return e.called?e.value:(e.called=!0,e.value=t.apply(this,arguments))};return e.called=!1,e}function Jue(t){var e=function(){if(e.called)throw new Error(e.onceError);return e.called=!0,e.value=t.apply(this,arguments)},r=t.name||"Function wrapped with `once`";return e.onceError=r+" shouldn't be called more than once",e.called=!1,e}});var cH=_((DMt,zue)=>{var qet=lH(),Wet=function(){},Yet=function(t){return t.setHeader&&typeof t.abort=="function"},Vet=function(t){return t.stdio&&Array.isArray(t.stdio)&&t.stdio.length===3},Kue=function(t,e,r){if(typeof e=="function")return Kue(t,null,e);e||(e={}),r=qet(r||Wet);var s=t._writableState,a=t._readableState,n=e.readable||e.readable!==!1&&t.readable,c=e.writable||e.writable!==!1&&t.writable,f=function(){t.writable||p()},p=function(){c=!1,n||r.call(t)},h=function(){n=!1,c||r.call(t)},E=function(I){r.call(t,I?new Error("exited with error code: "+I):null)},C=function(I){r.call(t,I)},S=function(){if(n&&!(a&&a.ended))return r.call(t,new Error("premature close"));if(c&&!(s&&s.ended))return r.call(t,new Error("premature close"))},P=function(){t.req.on("finish",p)};return Yet(t)?(t.on("complete",p),t.on("abort",S),t.req?P():t.on("request",P)):c&&!s&&(t.on("end",f),t.on("close",f)),Vet(t)&&t.on("exit",E),t.on("end",h),t.on("finish",p),e.error!==!1&&t.on("error",C),t.on("close",S),function(){t.removeListener("complete",p),t.removeListener("abort",S),t.removeListener("request",P),t.req&&t.req.removeListener("finish",p),t.removeListener("end",f),t.removeListener("close",f),t.removeListener("finish",p),t.removeListener("exit",E),t.removeListener("end",h),t.removeListener("error",C),t.removeListener("close",S)}};zue.exports=Kue});var $ue=_((bMt,Zue)=>{var Jet=lH(),Ket=cH(),uH=Ie("fs"),JB=function(){},zet=/^v?\.0/.test(process.version),GQ=function(t){return typeof t=="function"},Xet=function(t){return!zet||!uH?!1:(t instanceof(uH.ReadStream||JB)||t instanceof(uH.WriteStream||JB))&&GQ(t.close)},Zet=function(t){return t.setHeader&&GQ(t.abort)},$et=function(t,e,r,s){s=Jet(s);var a=!1;t.on("close",function(){a=!0}),Ket(t,{readable:e,writable:r},function(c){if(c)return s(c);a=!0,s()});var n=!1;return function(c){if(!a&&!n){if(n=!0,Xet(t))return t.close(JB);if(Zet(t))return t.abort();if(GQ(t.destroy))return t.destroy();s(c||new Error("stream was destroyed"))}}},Xue=function(t){t()},ett=function(t,e){return t.pipe(e)},ttt=function(){var t=Array.prototype.slice.call(arguments),e=GQ(t[t.length-1]||JB)&&t.pop()||JB;if(Array.isArray(t[0])&&(t=t[0]),t.length<2)throw new Error("pump requires two streams per minimum");var r,s=t.map(function(a,n){var c=n0;return $et(a,c,f,function(p){r||(r=p),p&&s.forEach(Xue),!c&&(s.forEach(Xue),e(r))})});return t.reduce(ett)};Zue.exports=ttt});var tfe=_((PMt,efe)=>{"use strict";var{PassThrough:rtt}=Ie("stream");efe.exports=t=>{t={...t};let{array:e}=t,{encoding:r}=t,s=r==="buffer",a=!1;e?a=!(r||s):r=r||"utf8",s&&(r=null);let n=new rtt({objectMode:a});r&&n.setEncoding(r);let c=0,f=[];return n.on("data",p=>{f.push(p),a?c=f.length:c+=p.length}),n.getBufferedValue=()=>e?f:s?Buffer.concat(f,c):f.join(""),n.getBufferedLength=()=>c,n}});var rfe=_((xMt,hI)=>{"use strict";var ntt=$ue(),itt=tfe(),qQ=class extends Error{constructor(){super("maxBuffer exceeded"),this.name="MaxBufferError"}};async function WQ(t,e){if(!t)return Promise.reject(new Error("Expected a stream"));e={maxBuffer:1/0,...e};let{maxBuffer:r}=e,s;return await new Promise((a,n)=>{let c=f=>{f&&(f.bufferedData=s.getBufferedValue()),n(f)};s=ntt(t,itt(e),f=>{if(f){c(f);return}a()}),s.on("data",()=>{s.getBufferedLength()>r&&c(new qQ)})}),s.getBufferedValue()}hI.exports=WQ;hI.exports.default=WQ;hI.exports.buffer=(t,e)=>WQ(t,{...e,encoding:"buffer"});hI.exports.array=(t,e)=>WQ(t,{...e,array:!0});hI.exports.MaxBufferError=qQ});var ife=_((QMt,nfe)=>{"use strict";var stt=new Set([200,203,204,206,300,301,308,404,405,410,414,501]),ott=new Set([200,203,204,300,301,302,303,307,308,404,405,410,414,501]),att=new Set([500,502,503,504]),ltt={date:!0,connection:!0,"keep-alive":!0,"proxy-authenticate":!0,"proxy-authorization":!0,te:!0,trailer:!0,"transfer-encoding":!0,upgrade:!0},ctt={"content-length":!0,"content-encoding":!0,"transfer-encoding":!0,"content-range":!0};function nm(t){let e=parseInt(t,10);return isFinite(e)?e:0}function utt(t){return t?att.has(t.status):!0}function fH(t){let e={};if(!t)return e;let r=t.trim().split(/,/);for(let s of r){let[a,n]=s.split(/=/,2);e[a.trim()]=n===void 0?!0:n.trim().replace(/^"|"$/g,"")}return e}function ftt(t){let e=[];for(let r in t){let s=t[r];e.push(s===!0?r:r+"="+s)}if(e.length)return e.join(", ")}nfe.exports=class{constructor(e,r,{shared:s,cacheHeuristic:a,immutableMinTimeToLive:n,ignoreCargoCult:c,_fromObject:f}={}){if(f){this._fromObject(f);return}if(!r||!r.headers)throw Error("Response headers missing");this._assertRequestHasHeaders(e),this._responseTime=this.now(),this._isShared=s!==!1,this._cacheHeuristic=a!==void 0?a:.1,this._immutableMinTtl=n!==void 0?n:24*3600*1e3,this._status="status"in r?r.status:200,this._resHeaders=r.headers,this._rescc=fH(r.headers["cache-control"]),this._method="method"in e?e.method:"GET",this._url=e.url,this._host=e.headers.host,this._noAuthorization=!e.headers.authorization,this._reqHeaders=r.headers.vary?e.headers:null,this._reqcc=fH(e.headers["cache-control"]),c&&"pre-check"in this._rescc&&"post-check"in this._rescc&&(delete this._rescc["pre-check"],delete this._rescc["post-check"],delete this._rescc["no-cache"],delete this._rescc["no-store"],delete this._rescc["must-revalidate"],this._resHeaders=Object.assign({},this._resHeaders,{"cache-control":ftt(this._rescc)}),delete this._resHeaders.expires,delete this._resHeaders.pragma),r.headers["cache-control"]==null&&/no-cache/.test(r.headers.pragma)&&(this._rescc["no-cache"]=!0)}now(){return Date.now()}storable(){return!!(!this._reqcc["no-store"]&&(this._method==="GET"||this._method==="HEAD"||this._method==="POST"&&this._hasExplicitExpiration())&&ott.has(this._status)&&!this._rescc["no-store"]&&(!this._isShared||!this._rescc.private)&&(!this._isShared||this._noAuthorization||this._allowsStoringAuthenticated())&&(this._resHeaders.expires||this._rescc["max-age"]||this._isShared&&this._rescc["s-maxage"]||this._rescc.public||stt.has(this._status)))}_hasExplicitExpiration(){return this._isShared&&this._rescc["s-maxage"]||this._rescc["max-age"]||this._resHeaders.expires}_assertRequestHasHeaders(e){if(!e||!e.headers)throw Error("Request headers missing")}satisfiesWithoutRevalidation(e){this._assertRequestHasHeaders(e);let r=fH(e.headers["cache-control"]);return r["no-cache"]||/no-cache/.test(e.headers.pragma)||r["max-age"]&&this.age()>r["max-age"]||r["min-fresh"]&&this.timeToLive()<1e3*r["min-fresh"]||this.stale()&&!(r["max-stale"]&&!this._rescc["must-revalidate"]&&(r["max-stale"]===!0||r["max-stale"]>this.age()-this.maxAge()))?!1:this._requestMatches(e,!1)}_requestMatches(e,r){return(!this._url||this._url===e.url)&&this._host===e.headers.host&&(!e.method||this._method===e.method||r&&e.method==="HEAD")&&this._varyMatches(e)}_allowsStoringAuthenticated(){return this._rescc["must-revalidate"]||this._rescc.public||this._rescc["s-maxage"]}_varyMatches(e){if(!this._resHeaders.vary)return!0;if(this._resHeaders.vary==="*")return!1;let r=this._resHeaders.vary.trim().toLowerCase().split(/\s*,\s*/);for(let s of r)if(e.headers[s]!==this._reqHeaders[s])return!1;return!0}_copyWithoutHopByHopHeaders(e){let r={};for(let s in e)ltt[s]||(r[s]=e[s]);if(e.connection){let s=e.connection.trim().split(/\s*,\s*/);for(let a of s)delete r[a]}if(r.warning){let s=r.warning.split(/,/).filter(a=>!/^\s*1[0-9][0-9]/.test(a));s.length?r.warning=s.join(",").trim():delete r.warning}return r}responseHeaders(){let e=this._copyWithoutHopByHopHeaders(this._resHeaders),r=this.age();return r>3600*24&&!this._hasExplicitExpiration()&&this.maxAge()>3600*24&&(e.warning=(e.warning?`${e.warning}, `:"")+'113 - "rfc7234 5.5.4"'),e.age=`${Math.round(r)}`,e.date=new Date(this.now()).toUTCString(),e}date(){let e=Date.parse(this._resHeaders.date);return isFinite(e)?e:this._responseTime}age(){let e=this._ageValue(),r=(this.now()-this._responseTime)/1e3;return e+r}_ageValue(){return nm(this._resHeaders.age)}maxAge(){if(!this.storable()||this._rescc["no-cache"]||this._isShared&&this._resHeaders["set-cookie"]&&!this._rescc.public&&!this._rescc.immutable||this._resHeaders.vary==="*")return 0;if(this._isShared){if(this._rescc["proxy-revalidate"])return 0;if(this._rescc["s-maxage"])return nm(this._rescc["s-maxage"])}if(this._rescc["max-age"])return nm(this._rescc["max-age"]);let e=this._rescc.immutable?this._immutableMinTtl:0,r=this.date();if(this._resHeaders.expires){let s=Date.parse(this._resHeaders.expires);return Number.isNaN(s)||ss)return Math.max(e,(r-s)/1e3*this._cacheHeuristic)}return e}timeToLive(){let e=this.maxAge()-this.age(),r=e+nm(this._rescc["stale-if-error"]),s=e+nm(this._rescc["stale-while-revalidate"]);return Math.max(0,e,r,s)*1e3}stale(){return this.maxAge()<=this.age()}_useStaleIfError(){return this.maxAge()+nm(this._rescc["stale-if-error"])>this.age()}useStaleWhileRevalidate(){return this.maxAge()+nm(this._rescc["stale-while-revalidate"])>this.age()}static fromObject(e){return new this(void 0,void 0,{_fromObject:e})}_fromObject(e){if(this._responseTime)throw Error("Reinitialized");if(!e||e.v!==1)throw Error("Invalid serialization");this._responseTime=e.t,this._isShared=e.sh,this._cacheHeuristic=e.ch,this._immutableMinTtl=e.imm!==void 0?e.imm:24*3600*1e3,this._status=e.st,this._resHeaders=e.resh,this._rescc=e.rescc,this._method=e.m,this._url=e.u,this._host=e.h,this._noAuthorization=e.a,this._reqHeaders=e.reqh,this._reqcc=e.reqcc}toObject(){return{v:1,t:this._responseTime,sh:this._isShared,ch:this._cacheHeuristic,imm:this._immutableMinTtl,st:this._status,resh:this._resHeaders,rescc:this._rescc,m:this._method,u:this._url,h:this._host,a:this._noAuthorization,reqh:this._reqHeaders,reqcc:this._reqcc}}revalidationHeaders(e){this._assertRequestHasHeaders(e);let r=this._copyWithoutHopByHopHeaders(e.headers);if(delete r["if-range"],!this._requestMatches(e,!0)||!this.storable())return delete r["if-none-match"],delete r["if-modified-since"],r;if(this._resHeaders.etag&&(r["if-none-match"]=r["if-none-match"]?`${r["if-none-match"]}, ${this._resHeaders.etag}`:this._resHeaders.etag),r["accept-ranges"]||r["if-match"]||r["if-unmodified-since"]||this._method&&this._method!="GET"){if(delete r["if-modified-since"],r["if-none-match"]){let a=r["if-none-match"].split(/,/).filter(n=>!/^\s*W\//.test(n));a.length?r["if-none-match"]=a.join(",").trim():delete r["if-none-match"]}}else this._resHeaders["last-modified"]&&!r["if-modified-since"]&&(r["if-modified-since"]=this._resHeaders["last-modified"]);return r}revalidatedPolicy(e,r){if(this._assertRequestHasHeaders(e),this._useStaleIfError()&&utt(r))return{modified:!1,matches:!1,policy:this};if(!r||!r.headers)throw Error("Response headers missing");let s=!1;if(r.status!==void 0&&r.status!=304?s=!1:r.headers.etag&&!/^\s*W\//.test(r.headers.etag)?s=this._resHeaders.etag&&this._resHeaders.etag.replace(/^\s*W\//,"")===r.headers.etag:this._resHeaders.etag&&r.headers.etag?s=this._resHeaders.etag.replace(/^\s*W\//,"")===r.headers.etag.replace(/^\s*W\//,""):this._resHeaders["last-modified"]?s=this._resHeaders["last-modified"]===r.headers["last-modified"]:!this._resHeaders.etag&&!this._resHeaders["last-modified"]&&!r.headers.etag&&!r.headers["last-modified"]&&(s=!0),!s)return{policy:new this.constructor(e,r),modified:r.status!=304,matches:!1};let a={};for(let c in this._resHeaders)a[c]=c in r.headers&&!ctt[c]?r.headers[c]:this._resHeaders[c];let n=Object.assign({},r,{status:this._status,method:this._method,headers:a});return{policy:new this.constructor(e,n,{shared:this._isShared,cacheHeuristic:this._cacheHeuristic,immutableMinTimeToLive:this._immutableMinTtl}),modified:!1,matches:!0}}}});var YQ=_((TMt,sfe)=>{"use strict";sfe.exports=t=>{let e={};for(let[r,s]of Object.entries(t))e[r.toLowerCase()]=s;return e}});var afe=_((RMt,ofe)=>{"use strict";var Att=Ie("stream").Readable,ptt=YQ(),AH=class extends Att{constructor(e,r,s,a){if(typeof e!="number")throw new TypeError("Argument `statusCode` should be a number");if(typeof r!="object")throw new TypeError("Argument `headers` should be an object");if(!(s instanceof Buffer))throw new TypeError("Argument `body` should be a buffer");if(typeof a!="string")throw new TypeError("Argument `url` should be a string");super(),this.statusCode=e,this.headers=ptt(r),this.body=s,this.url=a}_read(){this.push(this.body),this.push(null)}};ofe.exports=AH});var cfe=_((FMt,lfe)=>{"use strict";var htt=["destroy","setTimeout","socket","headers","trailers","rawHeaders","statusCode","httpVersion","httpVersionMinor","httpVersionMajor","rawTrailers","statusMessage"];lfe.exports=(t,e)=>{let r=new Set(Object.keys(t).concat(htt));for(let s of r)s in e||(e[s]=typeof t[s]=="function"?t[s].bind(t):t[s])}});var ffe=_((NMt,ufe)=>{"use strict";var gtt=Ie("stream").PassThrough,dtt=cfe(),mtt=t=>{if(!(t&&t.pipe))throw new TypeError("Parameter `response` must be a response stream.");let e=new gtt;return dtt(t,e),t.pipe(e)};ufe.exports=mtt});var Afe=_(pH=>{pH.stringify=function t(e){if(typeof e>"u")return e;if(e&&Buffer.isBuffer(e))return JSON.stringify(":base64:"+e.toString("base64"));if(e&&e.toJSON&&(e=e.toJSON()),e&&typeof e=="object"){var r="",s=Array.isArray(e);r=s?"[":"{";var a=!0;for(var n in e){var c=typeof e[n]=="function"||!s&&typeof e[n]>"u";Object.hasOwnProperty.call(e,n)&&!c&&(a||(r+=","),a=!1,s?e[n]==null?r+="null":r+=t(e[n]):e[n]!==void 0&&(r+=t(n)+":"+t(e[n])))}return r+=s?"]":"}",r}else return typeof e=="string"?JSON.stringify(/^:/.test(e)?":"+e:e):typeof e>"u"?"null":JSON.stringify(e)};pH.parse=function(t){return JSON.parse(t,function(e,r){return typeof r=="string"?/^:base64:/.test(r)?Buffer.from(r.substring(8),"base64"):/^:/.test(r)?r.substring(1):r:r})}});var dfe=_((LMt,gfe)=>{"use strict";var ytt=Ie("events"),pfe=Afe(),Ett=t=>{let e={redis:"@keyv/redis",rediss:"@keyv/redis",mongodb:"@keyv/mongo",mongo:"@keyv/mongo",sqlite:"@keyv/sqlite",postgresql:"@keyv/postgres",postgres:"@keyv/postgres",mysql:"@keyv/mysql",etcd:"@keyv/etcd",offline:"@keyv/offline",tiered:"@keyv/tiered"};if(t.adapter||t.uri){let r=t.adapter||/^[^:+]*/.exec(t.uri)[0];return new(Ie(e[r]))(t)}return new Map},hfe=["sqlite","postgres","mysql","mongo","redis","tiered"],hH=class extends ytt{constructor(e,{emitErrors:r=!0,...s}={}){if(super(),this.opts={namespace:"keyv",serialize:pfe.stringify,deserialize:pfe.parse,...typeof e=="string"?{uri:e}:e,...s},!this.opts.store){let n={...this.opts};this.opts.store=Ett(n)}if(this.opts.compression){let n=this.opts.compression;this.opts.serialize=n.serialize.bind(n),this.opts.deserialize=n.deserialize.bind(n)}typeof this.opts.store.on=="function"&&r&&this.opts.store.on("error",n=>this.emit("error",n)),this.opts.store.namespace=this.opts.namespace;let a=n=>async function*(){for await(let[c,f]of typeof n=="function"?n(this.opts.store.namespace):n){let p=await this.opts.deserialize(f);if(!(this.opts.store.namespace&&!c.includes(this.opts.store.namespace))){if(typeof p.expires=="number"&&Date.now()>p.expires){this.delete(c);continue}yield[this._getKeyUnprefix(c),p.value]}}};typeof this.opts.store[Symbol.iterator]=="function"&&this.opts.store instanceof Map?this.iterator=a(this.opts.store):typeof this.opts.store.iterator=="function"&&this.opts.store.opts&&this._checkIterableAdaptar()&&(this.iterator=a(this.opts.store.iterator.bind(this.opts.store)))}_checkIterableAdaptar(){return hfe.includes(this.opts.store.opts.dialect)||hfe.findIndex(e=>this.opts.store.opts.url.includes(e))>=0}_getKeyPrefix(e){return`${this.opts.namespace}:${e}`}_getKeyPrefixArray(e){return e.map(r=>`${this.opts.namespace}:${r}`)}_getKeyUnprefix(e){return e.split(":").splice(1).join(":")}get(e,r){let{store:s}=this.opts,a=Array.isArray(e),n=a?this._getKeyPrefixArray(e):this._getKeyPrefix(e);if(a&&s.getMany===void 0){let c=[];for(let f of n)c.push(Promise.resolve().then(()=>s.get(f)).then(p=>typeof p=="string"?this.opts.deserialize(p):this.opts.compression?this.opts.deserialize(p):p).then(p=>{if(p!=null)return typeof p.expires=="number"&&Date.now()>p.expires?this.delete(f).then(()=>{}):r&&r.raw?p:p.value}));return Promise.allSettled(c).then(f=>{let p=[];for(let h of f)p.push(h.value);return p})}return Promise.resolve().then(()=>a?s.getMany(n):s.get(n)).then(c=>typeof c=="string"?this.opts.deserialize(c):this.opts.compression?this.opts.deserialize(c):c).then(c=>{if(c!=null)return a?c.map((f,p)=>{if(typeof f=="string"&&(f=this.opts.deserialize(f)),f!=null){if(typeof f.expires=="number"&&Date.now()>f.expires){this.delete(e[p]).then(()=>{});return}return r&&r.raw?f:f.value}}):typeof c.expires=="number"&&Date.now()>c.expires?this.delete(e).then(()=>{}):r&&r.raw?c:c.value})}set(e,r,s){let a=this._getKeyPrefix(e);typeof s>"u"&&(s=this.opts.ttl),s===0&&(s=void 0);let{store:n}=this.opts;return Promise.resolve().then(()=>{let c=typeof s=="number"?Date.now()+s:null;return typeof r=="symbol"&&this.emit("error","symbol cannot be serialized"),r={value:r,expires:c},this.opts.serialize(r)}).then(c=>n.set(a,c,s)).then(()=>!0)}delete(e){let{store:r}=this.opts;if(Array.isArray(e)){let a=this._getKeyPrefixArray(e);if(r.deleteMany===void 0){let n=[];for(let c of a)n.push(r.delete(c));return Promise.allSettled(n).then(c=>c.every(f=>f.value===!0))}return Promise.resolve().then(()=>r.deleteMany(a))}let s=this._getKeyPrefix(e);return Promise.resolve().then(()=>r.delete(s))}clear(){let{store:e}=this.opts;return Promise.resolve().then(()=>e.clear())}has(e){let r=this._getKeyPrefix(e),{store:s}=this.opts;return Promise.resolve().then(async()=>typeof s.has=="function"?s.has(r):await s.get(r)!==void 0)}disconnect(){let{store:e}=this.opts;if(typeof e.disconnect=="function")return e.disconnect()}};gfe.exports=hH});var Efe=_((UMt,yfe)=>{"use strict";var Itt=Ie("events"),VQ=Ie("url"),Ctt=Gue(),wtt=rfe(),gH=ife(),mfe=afe(),Btt=YQ(),vtt=ffe(),Stt=dfe(),KB=class t{constructor(e,r){if(typeof e!="function")throw new TypeError("Parameter `request` must be a function");return this.cache=new Stt({uri:typeof r=="string"&&r,store:typeof r!="string"&&r,namespace:"cacheable-request"}),this.createCacheableRequest(e)}createCacheableRequest(e){return(r,s)=>{let a;if(typeof r=="string")a=dH(VQ.parse(r)),r={};else if(r instanceof VQ.URL)a=dH(VQ.parse(r.toString())),r={};else{let[C,...S]=(r.path||"").split("?"),P=S.length>0?`?${S.join("?")}`:"";a=dH({...r,pathname:C,search:P})}r={headers:{},method:"GET",cache:!0,strictTtl:!1,automaticFailover:!1,...r,...Dtt(a)},r.headers=Btt(r.headers);let n=new Itt,c=Ctt(VQ.format(a),{stripWWW:!1,removeTrailingSlash:!1,stripAuthentication:!1}),f=`${r.method}:${c}`,p=!1,h=!1,E=C=>{h=!0;let S=!1,P,I=new Promise(N=>{P=()=>{S||(S=!0,N())}}),R=N=>{if(p&&!C.forceRefresh){N.status=N.statusCode;let W=gH.fromObject(p.cachePolicy).revalidatedPolicy(C,N);if(!W.modified){let ee=W.policy.responseHeaders();N=new mfe(p.statusCode,ee,p.body,p.url),N.cachePolicy=W.policy,N.fromCache=!0}}N.fromCache||(N.cachePolicy=new gH(C,N,C),N.fromCache=!1);let U;C.cache&&N.cachePolicy.storable()?(U=vtt(N),(async()=>{try{let W=wtt.buffer(N);if(await Promise.race([I,new Promise(le=>N.once("end",le))]),S)return;let ee=await W,ie={cachePolicy:N.cachePolicy.toObject(),url:N.url,statusCode:N.fromCache?p.statusCode:N.statusCode,body:ee},ue=C.strictTtl?N.cachePolicy.timeToLive():void 0;C.maxTtl&&(ue=ue?Math.min(ue,C.maxTtl):C.maxTtl),await this.cache.set(f,ie,ue)}catch(W){n.emit("error",new t.CacheError(W))}})()):C.cache&&p&&(async()=>{try{await this.cache.delete(f)}catch(W){n.emit("error",new t.CacheError(W))}})(),n.emit("response",U||N),typeof s=="function"&&s(U||N)};try{let N=e(C,R);N.once("error",P),N.once("abort",P),n.emit("request",N)}catch(N){n.emit("error",new t.RequestError(N))}};return(async()=>{let C=async P=>{await Promise.resolve();let I=P.cache?await this.cache.get(f):void 0;if(typeof I>"u")return E(P);let R=gH.fromObject(I.cachePolicy);if(R.satisfiesWithoutRevalidation(P)&&!P.forceRefresh){let N=R.responseHeaders(),U=new mfe(I.statusCode,N,I.body,I.url);U.cachePolicy=R,U.fromCache=!0,n.emit("response",U),typeof s=="function"&&s(U)}else p=I,P.headers=R.revalidationHeaders(P),E(P)},S=P=>n.emit("error",new t.CacheError(P));this.cache.once("error",S),n.on("response",()=>this.cache.removeListener("error",S));try{await C(r)}catch(P){r.automaticFailover&&!h&&E(r),n.emit("error",new t.CacheError(P))}})(),n}}};function Dtt(t){let e={...t};return e.path=`${t.pathname||"/"}${t.search||""}`,delete e.pathname,delete e.search,e}function dH(t){return{protocol:t.protocol,auth:t.auth,hostname:t.hostname||t.host||"localhost",port:t.port,pathname:t.pathname,search:t.search}}KB.RequestError=class extends Error{constructor(t){super(t.message),this.name="RequestError",Object.assign(this,t)}};KB.CacheError=class extends Error{constructor(t){super(t.message),this.name="CacheError",Object.assign(this,t)}};yfe.exports=KB});var Cfe=_((jMt,Ife)=>{"use strict";var btt=["aborted","complete","headers","httpVersion","httpVersionMinor","httpVersionMajor","method","rawHeaders","rawTrailers","setTimeout","socket","statusCode","statusMessage","trailers","url"];Ife.exports=(t,e)=>{if(e._readableState.autoDestroy)throw new Error("The second stream must have the `autoDestroy` option set to `false`");let r=new Set(Object.keys(t).concat(btt)),s={};for(let a of r)a in e||(s[a]={get(){let n=t[a];return typeof n=="function"?n.bind(t):n},set(n){t[a]=n},enumerable:!0,configurable:!1});return Object.defineProperties(e,s),t.once("aborted",()=>{e.destroy(),e.emit("aborted")}),t.once("close",()=>{t.complete&&e.readable?e.once("end",()=>{e.emit("close")}):e.emit("close")}),e}});var Bfe=_((GMt,wfe)=>{"use strict";var{Transform:Ptt,PassThrough:xtt}=Ie("stream"),mH=Ie("zlib"),ktt=Cfe();wfe.exports=t=>{let e=(t.headers["content-encoding"]||"").toLowerCase();if(!["gzip","deflate","br"].includes(e))return t;let r=e==="br";if(r&&typeof mH.createBrotliDecompress!="function")return t.destroy(new Error("Brotli is not supported on Node.js < 12")),t;let s=!0,a=new Ptt({transform(f,p,h){s=!1,h(null,f)},flush(f){f()}}),n=new xtt({autoDestroy:!1,destroy(f,p){t.destroy(),p(f)}}),c=r?mH.createBrotliDecompress():mH.createUnzip();return c.once("error",f=>{if(s&&!t.readable){n.end();return}n.destroy(f)}),ktt(t,n),t.pipe(a).pipe(c).pipe(n),n}});var EH=_((qMt,vfe)=>{"use strict";var yH=class{constructor(e={}){if(!(e.maxSize&&e.maxSize>0))throw new TypeError("`maxSize` must be a number greater than 0");this.maxSize=e.maxSize,this.onEviction=e.onEviction,this.cache=new Map,this.oldCache=new Map,this._size=0}_set(e,r){if(this.cache.set(e,r),this._size++,this._size>=this.maxSize){if(this._size=0,typeof this.onEviction=="function")for(let[s,a]of this.oldCache.entries())this.onEviction(s,a);this.oldCache=this.cache,this.cache=new Map}}get(e){if(this.cache.has(e))return this.cache.get(e);if(this.oldCache.has(e)){let r=this.oldCache.get(e);return this.oldCache.delete(e),this._set(e,r),r}}set(e,r){return this.cache.has(e)?this.cache.set(e,r):this._set(e,r),this}has(e){return this.cache.has(e)||this.oldCache.has(e)}peek(e){if(this.cache.has(e))return this.cache.get(e);if(this.oldCache.has(e))return this.oldCache.get(e)}delete(e){let r=this.cache.delete(e);return r&&this._size--,this.oldCache.delete(e)||r}clear(){this.cache.clear(),this.oldCache.clear(),this._size=0}*keys(){for(let[e]of this)yield e}*values(){for(let[,e]of this)yield e}*[Symbol.iterator](){for(let e of this.cache)yield e;for(let e of this.oldCache){let[r]=e;this.cache.has(r)||(yield e)}}get size(){let e=0;for(let r of this.oldCache.keys())this.cache.has(r)||e++;return Math.min(this._size+e,this.maxSize)}};vfe.exports=yH});var CH=_((WMt,Pfe)=>{"use strict";var Qtt=Ie("events"),Ttt=Ie("tls"),Rtt=Ie("http2"),Ftt=EH(),Pa=Symbol("currentStreamsCount"),Sfe=Symbol("request"),Rc=Symbol("cachedOriginSet"),gI=Symbol("gracefullyClosing"),Ntt=["maxDeflateDynamicTableSize","maxSessionMemory","maxHeaderListPairs","maxOutstandingPings","maxReservedRemoteStreams","maxSendHeaderBlockLength","paddingStrategy","localAddress","path","rejectUnauthorized","minDHSize","ca","cert","clientCertEngine","ciphers","key","pfx","servername","minVersion","maxVersion","secureProtocol","crl","honorCipherOrder","ecdhCurve","dhparam","secureOptions","sessionIdContext"],Ott=(t,e,r)=>{let s=0,a=t.length;for(;s>>1;r(t[n],e)?s=n+1:a=n}return s},Ltt=(t,e)=>t.remoteSettings.maxConcurrentStreams>e.remoteSettings.maxConcurrentStreams,IH=(t,e)=>{for(let r of t)r[Rc].lengthe[Rc].includes(s))&&r[Pa]+e[Pa]<=e.remoteSettings.maxConcurrentStreams&&bfe(r)},Mtt=(t,e)=>{for(let r of t)e[Rc].lengthr[Rc].includes(s))&&e[Pa]+r[Pa]<=r.remoteSettings.maxConcurrentStreams&&bfe(e)},Dfe=({agent:t,isFree:e})=>{let r={};for(let s in t.sessions){let n=t.sessions[s].filter(c=>{let f=c[im.kCurrentStreamsCount]{t[gI]=!0,t[Pa]===0&&t.close()},im=class t extends Qtt{constructor({timeout:e=6e4,maxSessions:r=1/0,maxFreeSessions:s=10,maxCachedTlsSessions:a=100}={}){super(),this.sessions={},this.queue={},this.timeout=e,this.maxSessions=r,this.maxFreeSessions=s,this._freeSessionsCount=0,this._sessionsCount=0,this.settings={enablePush:!1},this.tlsSessionCache=new Ftt({maxSize:a})}static normalizeOrigin(e,r){return typeof e=="string"&&(e=new URL(e)),r&&e.hostname!==r&&(e.hostname=r),e.origin}normalizeOptions(e){let r="";if(e)for(let s of Ntt)e[s]&&(r+=`:${e[s]}`);return r}_tryToCreateNewSession(e,r){if(!(e in this.queue)||!(r in this.queue[e]))return;let s=this.queue[e][r];this._sessionsCount{Array.isArray(s)?(s=[...s],a()):s=[{resolve:a,reject:n}];let c=this.normalizeOptions(r),f=t.normalizeOrigin(e,r&&r.servername);if(f===void 0){for(let{reject:E}of s)E(new TypeError("The `origin` argument needs to be a string or an URL object"));return}if(c in this.sessions){let E=this.sessions[c],C=-1,S=-1,P;for(let I of E){let R=I.remoteSettings.maxConcurrentStreams;if(R=R||I[gI]||I.destroyed)continue;P||(C=R),N>S&&(P=I,S=N)}}if(P){if(s.length!==1){for(let{reject:I}of s){let R=new Error(`Expected the length of listeners to be 1, got ${s.length}. +Please report this to https://github.com/szmarczak/http2-wrapper/`);I(R)}return}s[0].resolve(P);return}}if(c in this.queue){if(f in this.queue[c]){this.queue[c][f].listeners.push(...s),this._tryToCreateNewSession(c,f);return}}else this.queue[c]={};let p=()=>{c in this.queue&&this.queue[c][f]===h&&(delete this.queue[c][f],Object.keys(this.queue[c]).length===0&&delete this.queue[c])},h=()=>{let E=`${f}:${c}`,C=!1;try{let S=Rtt.connect(e,{createConnection:this.createConnection,settings:this.settings,session:this.tlsSessionCache.get(E),...r});S[Pa]=0,S[gI]=!1;let P=()=>S[Pa]{this.tlsSessionCache.set(E,N)}),S.once("error",N=>{for(let{reject:U}of s)U(N);this.tlsSessionCache.delete(E)}),S.setTimeout(this.timeout,()=>{S.destroy()}),S.once("close",()=>{if(C){I&&this._freeSessionsCount--,this._sessionsCount--;let N=this.sessions[c];N.splice(N.indexOf(S),1),N.length===0&&delete this.sessions[c]}else{let N=new Error("Session closed without receiving a SETTINGS frame");N.code="HTTP2WRAPPER_NOSETTINGS";for(let{reject:U}of s)U(N);p()}this._tryToCreateNewSession(c,f)});let R=()=>{if(!(!(c in this.queue)||!P())){for(let N of S[Rc])if(N in this.queue[c]){let{listeners:U}=this.queue[c][N];for(;U.length!==0&&P();)U.shift().resolve(S);let W=this.queue[c];if(W[N].listeners.length===0&&(delete W[N],Object.keys(W).length===0)){delete this.queue[c];break}if(!P())break}}};S.on("origin",()=>{S[Rc]=S.originSet,P()&&(R(),IH(this.sessions[c],S))}),S.once("remoteSettings",()=>{if(S.ref(),S.unref(),this._sessionsCount++,h.destroyed){let N=new Error("Agent has been destroyed");for(let U of s)U.reject(N);S.destroy();return}S[Rc]=S.originSet;{let N=this.sessions;if(c in N){let U=N[c];U.splice(Ott(U,S,Ltt),0,S)}else N[c]=[S]}this._freeSessionsCount+=1,C=!0,this.emit("session",S),R(),p(),S[Pa]===0&&this._freeSessionsCount>this.maxFreeSessions&&S.close(),s.length!==0&&(this.getSession(f,r,s),s.length=0),S.on("remoteSettings",()=>{R(),IH(this.sessions[c],S)})}),S[Sfe]=S.request,S.request=(N,U)=>{if(S[gI])throw new Error("The session is gracefully closing. No new streams are allowed.");let W=S[Sfe](N,U);return S.ref(),++S[Pa],S[Pa]===S.remoteSettings.maxConcurrentStreams&&this._freeSessionsCount--,W.once("close",()=>{if(I=P(),--S[Pa],!S.destroyed&&!S.closed&&(Mtt(this.sessions[c],S),P()&&!S.closed)){I||(this._freeSessionsCount++,I=!0);let ee=S[Pa]===0;ee&&S.unref(),ee&&(this._freeSessionsCount>this.maxFreeSessions||S[gI])?S.close():(IH(this.sessions[c],S),R())}}),W}}catch(S){for(let P of s)P.reject(S);p()}};h.listeners=s,h.completed=!1,h.destroyed=!1,this.queue[c][f]=h,this._tryToCreateNewSession(c,f)})}request(e,r,s,a){return new Promise((n,c)=>{this.getSession(e,r,[{reject:c,resolve:f=>{try{n(f.request(s,a))}catch(p){c(p)}}}])})}createConnection(e,r){return t.connect(e,r)}static connect(e,r){r.ALPNProtocols=["h2"];let s=e.port||443,a=e.hostname||e.host;return typeof r.servername>"u"&&(r.servername=a),Ttt.connect(s,a,r)}closeFreeSessions(){for(let e of Object.values(this.sessions))for(let r of e)r[Pa]===0&&r.close()}destroy(e){for(let r of Object.values(this.sessions))for(let s of r)s.destroy(e);for(let r of Object.values(this.queue))for(let s of Object.values(r))s.destroyed=!0;this.queue={}}get freeSessions(){return Dfe({agent:this,isFree:!0})}get busySessions(){return Dfe({agent:this,isFree:!1})}};im.kCurrentStreamsCount=Pa;im.kGracefullyClosing=gI;Pfe.exports={Agent:im,globalAgent:new im}});var BH=_((YMt,xfe)=>{"use strict";var{Readable:Utt}=Ie("stream"),wH=class extends Utt{constructor(e,r){super({highWaterMark:r,autoDestroy:!1}),this.statusCode=null,this.statusMessage="",this.httpVersion="2.0",this.httpVersionMajor=2,this.httpVersionMinor=0,this.headers={},this.trailers={},this.req=null,this.aborted=!1,this.complete=!1,this.upgrade=null,this.rawHeaders=[],this.rawTrailers=[],this.socket=e,this.connection=e,this._dumped=!1}_destroy(e){this.req._request.destroy(e)}setTimeout(e,r){return this.req.setTimeout(e,r),this}_dump(){this._dumped||(this._dumped=!0,this.removeAllListeners("data"),this.resume())}_read(){this.req&&this.req._request.resume()}};xfe.exports=wH});var vH=_((VMt,kfe)=>{"use strict";kfe.exports=t=>{let e={protocol:t.protocol,hostname:typeof t.hostname=="string"&&t.hostname.startsWith("[")?t.hostname.slice(1,-1):t.hostname,host:t.host,hash:t.hash,search:t.search,pathname:t.pathname,href:t.href,path:`${t.pathname||""}${t.search||""}`};return typeof t.port=="string"&&t.port.length!==0&&(e.port=Number(t.port)),(t.username||t.password)&&(e.auth=`${t.username||""}:${t.password||""}`),e}});var Tfe=_((JMt,Qfe)=>{"use strict";Qfe.exports=(t,e,r)=>{for(let s of r)t.on(s,(...a)=>e.emit(s,...a))}});var Ffe=_((KMt,Rfe)=>{"use strict";Rfe.exports=t=>{switch(t){case":method":case":scheme":case":authority":case":path":return!0;default:return!1}}});var Ofe=_((XMt,Nfe)=>{"use strict";var dI=(t,e,r)=>{Nfe.exports[e]=class extends t{constructor(...a){super(typeof r=="string"?r:r(a)),this.name=`${super.name} [${e}]`,this.code=e}}};dI(TypeError,"ERR_INVALID_ARG_TYPE",t=>{let e=t[0].includes(".")?"property":"argument",r=t[1],s=Array.isArray(r);return s&&(r=`${r.slice(0,-1).join(", ")} or ${r.slice(-1)}`),`The "${t[0]}" ${e} must be ${s?"one of":"of"} type ${r}. Received ${typeof t[2]}`});dI(TypeError,"ERR_INVALID_PROTOCOL",t=>`Protocol "${t[0]}" not supported. Expected "${t[1]}"`);dI(Error,"ERR_HTTP_HEADERS_SENT",t=>`Cannot ${t[0]} headers after they are sent to the client`);dI(TypeError,"ERR_INVALID_HTTP_TOKEN",t=>`${t[0]} must be a valid HTTP token [${t[1]}]`);dI(TypeError,"ERR_HTTP_INVALID_HEADER_VALUE",t=>`Invalid value "${t[0]} for header "${t[1]}"`);dI(TypeError,"ERR_INVALID_CHAR",t=>`Invalid character in ${t[0]} [${t[1]}]`)});var xH=_((ZMt,Gfe)=>{"use strict";var _tt=Ie("http2"),{Writable:Htt}=Ie("stream"),{Agent:Lfe,globalAgent:jtt}=CH(),Gtt=BH(),qtt=vH(),Wtt=Tfe(),Ytt=Ffe(),{ERR_INVALID_ARG_TYPE:SH,ERR_INVALID_PROTOCOL:Vtt,ERR_HTTP_HEADERS_SENT:Mfe,ERR_INVALID_HTTP_TOKEN:Jtt,ERR_HTTP_INVALID_HEADER_VALUE:Ktt,ERR_INVALID_CHAR:ztt}=Ofe(),{HTTP2_HEADER_STATUS:Ufe,HTTP2_HEADER_METHOD:_fe,HTTP2_HEADER_PATH:Hfe,HTTP2_METHOD_CONNECT:Xtt}=_tt.constants,Jo=Symbol("headers"),DH=Symbol("origin"),bH=Symbol("session"),jfe=Symbol("options"),JQ=Symbol("flushedHeaders"),zB=Symbol("jobs"),Ztt=/^[\^`\-\w!#$%&*+.|~]+$/,$tt=/[^\t\u0020-\u007E\u0080-\u00FF]/,PH=class extends Htt{constructor(e,r,s){super({autoDestroy:!1});let a=typeof e=="string"||e instanceof URL;if(a&&(e=qtt(e instanceof URL?e:new URL(e))),typeof r=="function"||r===void 0?(s=r,r=a?e:{...e}):r={...e,...r},r.h2session)this[bH]=r.h2session;else if(r.agent===!1)this.agent=new Lfe({maxFreeSessions:0});else if(typeof r.agent>"u"||r.agent===null)typeof r.createConnection=="function"?(this.agent=new Lfe({maxFreeSessions:0}),this.agent.createConnection=r.createConnection):this.agent=jtt;else if(typeof r.agent.request=="function")this.agent=r.agent;else throw new SH("options.agent",["Agent-like Object","undefined","false"],r.agent);if(r.protocol&&r.protocol!=="https:")throw new Vtt(r.protocol,"https:");let n=r.port||r.defaultPort||this.agent&&this.agent.defaultPort||443,c=r.hostname||r.host||"localhost";delete r.hostname,delete r.host,delete r.port;let{timeout:f}=r;if(r.timeout=void 0,this[Jo]=Object.create(null),this[zB]=[],this.socket=null,this.connection=null,this.method=r.method||"GET",this.path=r.path,this.res=null,this.aborted=!1,this.reusedSocket=!1,r.headers)for(let[p,h]of Object.entries(r.headers))this.setHeader(p,h);r.auth&&!("authorization"in this[Jo])&&(this[Jo].authorization="Basic "+Buffer.from(r.auth).toString("base64")),r.session=r.tlsSession,r.path=r.socketPath,this[jfe]=r,n===443?(this[DH]=`https://${c}`,":authority"in this[Jo]||(this[Jo][":authority"]=c)):(this[DH]=`https://${c}:${n}`,":authority"in this[Jo]||(this[Jo][":authority"]=`${c}:${n}`)),f&&this.setTimeout(f),s&&this.once("response",s),this[JQ]=!1}get method(){return this[Jo][_fe]}set method(e){e&&(this[Jo][_fe]=e.toUpperCase())}get path(){return this[Jo][Hfe]}set path(e){e&&(this[Jo][Hfe]=e)}get _mustNotHaveABody(){return this.method==="GET"||this.method==="HEAD"||this.method==="DELETE"}_write(e,r,s){if(this._mustNotHaveABody){s(new Error("The GET, HEAD and DELETE methods must NOT have a body"));return}this.flushHeaders();let a=()=>this._request.write(e,r,s);this._request?a():this[zB].push(a)}_final(e){if(this.destroyed)return;this.flushHeaders();let r=()=>{if(this._mustNotHaveABody){e();return}this._request.end(e)};this._request?r():this[zB].push(r)}abort(){this.res&&this.res.complete||(this.aborted||process.nextTick(()=>this.emit("abort")),this.aborted=!0,this.destroy())}_destroy(e,r){this.res&&this.res._dump(),this._request&&this._request.destroy(),r(e)}async flushHeaders(){if(this[JQ]||this.destroyed)return;this[JQ]=!0;let e=this.method===Xtt,r=s=>{if(this._request=s,this.destroyed){s.destroy();return}e||Wtt(s,this,["timeout","continue","close","error"]);let a=c=>(...f)=>{!this.writable&&!this.destroyed?c(...f):this.once("finish",()=>{c(...f)})};s.once("response",a((c,f,p)=>{let h=new Gtt(this.socket,s.readableHighWaterMark);this.res=h,h.req=this,h.statusCode=c[Ufe],h.headers=c,h.rawHeaders=p,h.once("end",()=>{this.aborted?(h.aborted=!0,h.emit("aborted")):(h.complete=!0,h.socket=null,h.connection=null)}),e?(h.upgrade=!0,this.emit("connect",h,s,Buffer.alloc(0))?this.emit("close"):s.destroy()):(s.on("data",E=>{!h._dumped&&!h.push(E)&&s.pause()}),s.once("end",()=>{h.push(null)}),this.emit("response",h)||h._dump())})),s.once("headers",a(c=>this.emit("information",{statusCode:c[Ufe]}))),s.once("trailers",a((c,f,p)=>{let{res:h}=this;h.trailers=c,h.rawTrailers=p}));let{socket:n}=s.session;this.socket=n,this.connection=n;for(let c of this[zB])c();this.emit("socket",this.socket)};if(this[bH])try{r(this[bH].request(this[Jo]))}catch(s){this.emit("error",s)}else{this.reusedSocket=!0;try{r(await this.agent.request(this[DH],this[jfe],this[Jo]))}catch(s){this.emit("error",s)}}}getHeader(e){if(typeof e!="string")throw new SH("name","string",e);return this[Jo][e.toLowerCase()]}get headersSent(){return this[JQ]}removeHeader(e){if(typeof e!="string")throw new SH("name","string",e);if(this.headersSent)throw new Mfe("remove");delete this[Jo][e.toLowerCase()]}setHeader(e,r){if(this.headersSent)throw new Mfe("set");if(typeof e!="string"||!Ztt.test(e)&&!Ytt(e))throw new Jtt("Header name",e);if(typeof r>"u")throw new Ktt(r,e);if($tt.test(r))throw new ztt("header content",e);this[Jo][e.toLowerCase()]=r}setNoDelay(){}setSocketKeepAlive(){}setTimeout(e,r){let s=()=>this._request.setTimeout(e,r);return this._request?s():this[zB].push(s),this}get maxHeadersCount(){if(!this.destroyed&&this._request)return this._request.session.localSettings.maxHeaderListSize}set maxHeadersCount(e){}};Gfe.exports=PH});var Wfe=_(($Mt,qfe)=>{"use strict";var ert=Ie("tls");qfe.exports=(t={},e=ert.connect)=>new Promise((r,s)=>{let a=!1,n,c=async()=>{await p,n.off("timeout",f),n.off("error",s),t.resolveSocket?(r({alpnProtocol:n.alpnProtocol,socket:n,timeout:a}),a&&(await Promise.resolve(),n.emit("timeout"))):(n.destroy(),r({alpnProtocol:n.alpnProtocol,timeout:a}))},f=async()=>{a=!0,c()},p=(async()=>{try{n=await e(t,c),n.on("error",s),n.once("timeout",f)}catch(h){s(h)}})()})});var Vfe=_((eUt,Yfe)=>{"use strict";var trt=Ie("net");Yfe.exports=t=>{let e=t.host,r=t.headers&&t.headers.host;return r&&(r.startsWith("[")?r.indexOf("]")===-1?e=r:e=r.slice(1,-1):e=r.split(":",1)[0]),trt.isIP(e)?"":e}});var zfe=_((tUt,QH)=>{"use strict";var Jfe=Ie("http"),kH=Ie("https"),rrt=Wfe(),nrt=EH(),irt=xH(),srt=Vfe(),ort=vH(),KQ=new nrt({maxSize:100}),XB=new Map,Kfe=(t,e,r)=>{e._httpMessage={shouldKeepAlive:!0};let s=()=>{t.emit("free",e,r)};e.on("free",s);let a=()=>{t.removeSocket(e,r)};e.on("close",a);let n=()=>{t.removeSocket(e,r),e.off("close",a),e.off("free",s),e.off("agentRemove",n)};e.on("agentRemove",n),t.emit("free",e,r)},art=async t=>{let e=`${t.host}:${t.port}:${t.ALPNProtocols.sort()}`;if(!KQ.has(e)){if(XB.has(e))return(await XB.get(e)).alpnProtocol;let{path:r,agent:s}=t;t.path=t.socketPath;let a=rrt(t);XB.set(e,a);try{let{socket:n,alpnProtocol:c}=await a;if(KQ.set(e,c),t.path=r,c==="h2")n.destroy();else{let{globalAgent:f}=kH,p=kH.Agent.prototype.createConnection;s?s.createConnection===p?Kfe(s,n,t):n.destroy():f.createConnection===p?Kfe(f,n,t):n.destroy()}return XB.delete(e),c}catch(n){throw XB.delete(e),n}}return KQ.get(e)};QH.exports=async(t,e,r)=>{if((typeof t=="string"||t instanceof URL)&&(t=ort(new URL(t))),typeof e=="function"&&(r=e,e=void 0),e={ALPNProtocols:["h2","http/1.1"],...t,...e,resolveSocket:!0},!Array.isArray(e.ALPNProtocols)||e.ALPNProtocols.length===0)throw new Error("The `ALPNProtocols` option must be an Array with at least one entry");e.protocol=e.protocol||"https:";let s=e.protocol==="https:";e.host=e.hostname||e.host||"localhost",e.session=e.tlsSession,e.servername=e.servername||srt(e),e.port=e.port||(s?443:80),e._defaultAgent=s?kH.globalAgent:Jfe.globalAgent;let a=e.agent;if(a){if(a.addRequest)throw new Error("The `options.agent` object can contain only `http`, `https` or `http2` properties");e.agent=a[s?"https":"http"]}return s&&await art(e)==="h2"?(a&&(e.agent=a.http2),new irt(e,r)):Jfe.request(e,r)};QH.exports.protocolCache=KQ});var Zfe=_((rUt,Xfe)=>{"use strict";var lrt=Ie("http2"),crt=CH(),TH=xH(),urt=BH(),frt=zfe(),Art=(t,e,r)=>new TH(t,e,r),prt=(t,e,r)=>{let s=new TH(t,e,r);return s.end(),s};Xfe.exports={...lrt,ClientRequest:TH,IncomingMessage:urt,...crt,request:Art,get:prt,auto:frt}});var FH=_(RH=>{"use strict";Object.defineProperty(RH,"__esModule",{value:!0});var $fe=Np();RH.default=t=>$fe.default.nodeStream(t)&&$fe.default.function_(t.getBoundary)});var nAe=_(NH=>{"use strict";Object.defineProperty(NH,"__esModule",{value:!0});var tAe=Ie("fs"),rAe=Ie("util"),eAe=Np(),hrt=FH(),grt=rAe.promisify(tAe.stat);NH.default=async(t,e)=>{if(e&&"content-length"in e)return Number(e["content-length"]);if(!t)return 0;if(eAe.default.string(t))return Buffer.byteLength(t);if(eAe.default.buffer(t))return t.length;if(hrt.default(t))return rAe.promisify(t.getLength.bind(t))();if(t instanceof tAe.ReadStream){let{size:r}=await grt(t.path);return r===0?void 0:r}}});var LH=_(OH=>{"use strict";Object.defineProperty(OH,"__esModule",{value:!0});function drt(t,e,r){let s={};for(let a of r)s[a]=(...n)=>{e.emit(a,...n)},t.on(a,s[a]);return()=>{for(let a of r)t.off(a,s[a])}}OH.default=drt});var iAe=_(MH=>{"use strict";Object.defineProperty(MH,"__esModule",{value:!0});MH.default=()=>{let t=[];return{once(e,r,s){e.once(r,s),t.push({origin:e,event:r,fn:s})},unhandleAll(){for(let e of t){let{origin:r,event:s,fn:a}=e;r.removeListener(s,a)}t.length=0}}}});var oAe=_(ZB=>{"use strict";Object.defineProperty(ZB,"__esModule",{value:!0});ZB.TimeoutError=void 0;var mrt=Ie("net"),yrt=iAe(),sAe=Symbol("reentry"),Ert=()=>{},zQ=class extends Error{constructor(e,r){super(`Timeout awaiting '${r}' for ${e}ms`),this.event=r,this.name="TimeoutError",this.code="ETIMEDOUT"}};ZB.TimeoutError=zQ;ZB.default=(t,e,r)=>{if(sAe in t)return Ert;t[sAe]=!0;let s=[],{once:a,unhandleAll:n}=yrt.default(),c=(C,S,P)=>{var I;let R=setTimeout(S,C,C,P);(I=R.unref)===null||I===void 0||I.call(R);let N=()=>{clearTimeout(R)};return s.push(N),N},{host:f,hostname:p}=r,h=(C,S)=>{t.destroy(new zQ(C,S))},E=()=>{for(let C of s)C();n()};if(t.once("error",C=>{if(E(),t.listenerCount("error")===0)throw C}),t.once("close",E),a(t,"response",C=>{a(C,"end",E)}),typeof e.request<"u"&&c(e.request,h,"request"),typeof e.socket<"u"){let C=()=>{h(e.socket,"socket")};t.setTimeout(e.socket,C),s.push(()=>{t.removeListener("timeout",C)})}return a(t,"socket",C=>{var S;let{socketPath:P}=t;if(C.connecting){let I=!!(P??mrt.isIP((S=p??f)!==null&&S!==void 0?S:"")!==0);if(typeof e.lookup<"u"&&!I&&typeof C.address().address>"u"){let R=c(e.lookup,h,"lookup");a(C,"lookup",R)}if(typeof e.connect<"u"){let R=()=>c(e.connect,h,"connect");I?a(C,"connect",R()):a(C,"lookup",N=>{N===null&&a(C,"connect",R())})}typeof e.secureConnect<"u"&&r.protocol==="https:"&&a(C,"connect",()=>{let R=c(e.secureConnect,h,"secureConnect");a(C,"secureConnect",R)})}if(typeof e.send<"u"){let I=()=>c(e.send,h,"send");C.connecting?a(C,"connect",()=>{a(t,"upload-complete",I())}):a(t,"upload-complete",I())}}),typeof e.response<"u"&&a(t,"upload-complete",()=>{let C=c(e.response,h,"response");a(t,"response",C)}),E}});var lAe=_(UH=>{"use strict";Object.defineProperty(UH,"__esModule",{value:!0});var aAe=Np();UH.default=t=>{t=t;let e={protocol:t.protocol,hostname:aAe.default.string(t.hostname)&&t.hostname.startsWith("[")?t.hostname.slice(1,-1):t.hostname,host:t.host,hash:t.hash,search:t.search,pathname:t.pathname,href:t.href,path:`${t.pathname||""}${t.search||""}`};return aAe.default.string(t.port)&&t.port.length>0&&(e.port=Number(t.port)),(t.username||t.password)&&(e.auth=`${t.username||""}:${t.password||""}`),e}});var cAe=_(_H=>{"use strict";Object.defineProperty(_H,"__esModule",{value:!0});var Irt=Ie("url"),Crt=["protocol","host","hostname","port","pathname","search"];_H.default=(t,e)=>{var r,s;if(e.path){if(e.pathname)throw new TypeError("Parameters `path` and `pathname` are mutually exclusive.");if(e.search)throw new TypeError("Parameters `path` and `search` are mutually exclusive.");if(e.searchParams)throw new TypeError("Parameters `path` and `searchParams` are mutually exclusive.")}if(e.search&&e.searchParams)throw new TypeError("Parameters `search` and `searchParams` are mutually exclusive.");if(!t){if(!e.protocol)throw new TypeError("No URL protocol specified");t=`${e.protocol}//${(s=(r=e.hostname)!==null&&r!==void 0?r:e.host)!==null&&s!==void 0?s:""}`}let a=new Irt.URL(t);if(e.path){let n=e.path.indexOf("?");n===-1?e.pathname=e.path:(e.pathname=e.path.slice(0,n),e.search=e.path.slice(n+1)),delete e.path}for(let n of Crt)e[n]&&(a[n]=e[n].toString());return a}});var uAe=_(jH=>{"use strict";Object.defineProperty(jH,"__esModule",{value:!0});var HH=class{constructor(){this.weakMap=new WeakMap,this.map=new Map}set(e,r){typeof e=="object"?this.weakMap.set(e,r):this.map.set(e,r)}get(e){return typeof e=="object"?this.weakMap.get(e):this.map.get(e)}has(e){return typeof e=="object"?this.weakMap.has(e):this.map.has(e)}};jH.default=HH});var qH=_(GH=>{"use strict";Object.defineProperty(GH,"__esModule",{value:!0});var wrt=async t=>{let e=[],r=0;for await(let s of t)e.push(s),r+=Buffer.byteLength(s);return Buffer.isBuffer(e[0])?Buffer.concat(e,r):Buffer.from(e.join(""))};GH.default=wrt});var AAe=_(sm=>{"use strict";Object.defineProperty(sm,"__esModule",{value:!0});sm.dnsLookupIpVersionToFamily=sm.isDnsLookupIpVersion=void 0;var fAe={auto:0,ipv4:4,ipv6:6};sm.isDnsLookupIpVersion=t=>t in fAe;sm.dnsLookupIpVersionToFamily=t=>{if(sm.isDnsLookupIpVersion(t))return fAe[t];throw new Error("Invalid DNS lookup IP version")}});var WH=_(XQ=>{"use strict";Object.defineProperty(XQ,"__esModule",{value:!0});XQ.isResponseOk=void 0;XQ.isResponseOk=t=>{let{statusCode:e}=t,r=t.request.options.followRedirect?299:399;return e>=200&&e<=r||e===304}});var hAe=_(YH=>{"use strict";Object.defineProperty(YH,"__esModule",{value:!0});var pAe=new Set;YH.default=t=>{pAe.has(t)||(pAe.add(t),process.emitWarning(`Got: ${t}`,{type:"DeprecationWarning"}))}});var gAe=_(VH=>{"use strict";Object.defineProperty(VH,"__esModule",{value:!0});var Si=Np(),Brt=(t,e)=>{if(Si.default.null_(t.encoding))throw new TypeError("To get a Buffer, set `options.responseType` to `buffer` instead");Si.assert.any([Si.default.string,Si.default.undefined],t.encoding),Si.assert.any([Si.default.boolean,Si.default.undefined],t.resolveBodyOnly),Si.assert.any([Si.default.boolean,Si.default.undefined],t.methodRewriting),Si.assert.any([Si.default.boolean,Si.default.undefined],t.isStream),Si.assert.any([Si.default.string,Si.default.undefined],t.responseType),t.responseType===void 0&&(t.responseType="text");let{retry:r}=t;if(e?t.retry={...e.retry}:t.retry={calculateDelay:s=>s.computedValue,limit:0,methods:[],statusCodes:[],errorCodes:[],maxRetryAfter:void 0},Si.default.object(r)?(t.retry={...t.retry,...r},t.retry.methods=[...new Set(t.retry.methods.map(s=>s.toUpperCase()))],t.retry.statusCodes=[...new Set(t.retry.statusCodes)],t.retry.errorCodes=[...new Set(t.retry.errorCodes)]):Si.default.number(r)&&(t.retry.limit=r),Si.default.undefined(t.retry.maxRetryAfter)&&(t.retry.maxRetryAfter=Math.min(...[t.timeout.request,t.timeout.connect].filter(Si.default.number))),Si.default.object(t.pagination)){e&&(t.pagination={...e.pagination,...t.pagination});let{pagination:s}=t;if(!Si.default.function_(s.transform))throw new Error("`options.pagination.transform` must be implemented");if(!Si.default.function_(s.shouldContinue))throw new Error("`options.pagination.shouldContinue` must be implemented");if(!Si.default.function_(s.filter))throw new TypeError("`options.pagination.filter` must be implemented");if(!Si.default.function_(s.paginate))throw new Error("`options.pagination.paginate` must be implemented")}return t.responseType==="json"&&t.headers.accept===void 0&&(t.headers.accept="application/json"),t};VH.default=Brt});var dAe=_($B=>{"use strict";Object.defineProperty($B,"__esModule",{value:!0});$B.retryAfterStatusCodes=void 0;$B.retryAfterStatusCodes=new Set([413,429,503]);var vrt=({attemptCount:t,retryOptions:e,error:r,retryAfter:s})=>{if(t>e.limit)return 0;let a=e.methods.includes(r.options.method),n=e.errorCodes.includes(r.code),c=r.response&&e.statusCodes.includes(r.response.statusCode);if(!a||!n&&!c)return 0;if(r.response){if(s)return e.maxRetryAfter===void 0||s>e.maxRetryAfter?0:s;if(r.response.statusCode===413)return 0}let f=Math.random()*100;return 2**(t-1)*1e3+f};$B.default=vrt});var rv=_(Ln=>{"use strict";Object.defineProperty(Ln,"__esModule",{value:!0});Ln.UnsupportedProtocolError=Ln.ReadError=Ln.TimeoutError=Ln.UploadError=Ln.CacheError=Ln.HTTPError=Ln.MaxRedirectsError=Ln.RequestError=Ln.setNonEnumerableProperties=Ln.knownHookEvents=Ln.withoutBody=Ln.kIsNormalizedAlready=void 0;var mAe=Ie("util"),yAe=Ie("stream"),Srt=Ie("fs"),w0=Ie("url"),EAe=Ie("http"),JH=Ie("http"),Drt=Ie("https"),brt=Rue(),Prt=_ue(),IAe=Efe(),xrt=Bfe(),krt=Zfe(),Qrt=YQ(),at=Np(),Trt=nAe(),CAe=FH(),Rrt=LH(),wAe=oAe(),Frt=lAe(),BAe=cAe(),Nrt=uAe(),Ort=qH(),vAe=AAe(),Lrt=WH(),B0=hAe(),Mrt=gAe(),Urt=dAe(),KH,po=Symbol("request"),eT=Symbol("response"),mI=Symbol("responseSize"),yI=Symbol("downloadedSize"),EI=Symbol("bodySize"),II=Symbol("uploadedSize"),ZQ=Symbol("serverResponsesPiped"),SAe=Symbol("unproxyEvents"),DAe=Symbol("isFromCache"),zH=Symbol("cancelTimeouts"),bAe=Symbol("startedReading"),CI=Symbol("stopReading"),$Q=Symbol("triggerRead"),v0=Symbol("body"),ev=Symbol("jobs"),PAe=Symbol("originalResponse"),xAe=Symbol("retryTimeout");Ln.kIsNormalizedAlready=Symbol("isNormalizedAlready");var _rt=at.default.string(process.versions.brotli);Ln.withoutBody=new Set(["GET","HEAD"]);Ln.knownHookEvents=["init","beforeRequest","beforeRedirect","beforeError","beforeRetry","afterResponse"];function Hrt(t){for(let e in t){let r=t[e];if(!at.default.string(r)&&!at.default.number(r)&&!at.default.boolean(r)&&!at.default.null_(r)&&!at.default.undefined(r))throw new TypeError(`The \`searchParams\` value '${String(r)}' must be a string, number, boolean or null`)}}function jrt(t){return at.default.object(t)&&!("statusCode"in t)}var XH=new Nrt.default,Grt=async t=>new Promise((e,r)=>{let s=a=>{r(a)};t.pending||e(),t.once("error",s),t.once("ready",()=>{t.off("error",s),e()})}),qrt=new Set([300,301,302,303,304,307,308]),Wrt=["context","body","json","form"];Ln.setNonEnumerableProperties=(t,e)=>{let r={};for(let s of t)if(s)for(let a of Wrt)a in s&&(r[a]={writable:!0,configurable:!0,enumerable:!1,value:s[a]});Object.defineProperties(e,r)};var fs=class extends Error{constructor(e,r,s){var a;if(super(e),Error.captureStackTrace(this,this.constructor),this.name="RequestError",this.code=r.code,s instanceof aT?(Object.defineProperty(this,"request",{enumerable:!1,value:s}),Object.defineProperty(this,"response",{enumerable:!1,value:s[eT]}),Object.defineProperty(this,"options",{enumerable:!1,value:s.options})):Object.defineProperty(this,"options",{enumerable:!1,value:s}),this.timings=(a=this.request)===null||a===void 0?void 0:a.timings,at.default.string(r.stack)&&at.default.string(this.stack)){let n=this.stack.indexOf(this.message)+this.message.length,c=this.stack.slice(n).split(` +`).reverse(),f=r.stack.slice(r.stack.indexOf(r.message)+r.message.length).split(` +`).reverse();for(;f.length!==0&&f[0]===c[0];)c.shift();this.stack=`${this.stack.slice(0,n)}${c.reverse().join(` +`)}${f.reverse().join(` +`)}`}}};Ln.RequestError=fs;var tT=class extends fs{constructor(e){super(`Redirected ${e.options.maxRedirects} times. Aborting.`,{},e),this.name="MaxRedirectsError"}};Ln.MaxRedirectsError=tT;var rT=class extends fs{constructor(e){super(`Response code ${e.statusCode} (${e.statusMessage})`,{},e.request),this.name="HTTPError"}};Ln.HTTPError=rT;var nT=class extends fs{constructor(e,r){super(e.message,e,r),this.name="CacheError"}};Ln.CacheError=nT;var iT=class extends fs{constructor(e,r){super(e.message,e,r),this.name="UploadError"}};Ln.UploadError=iT;var sT=class extends fs{constructor(e,r,s){super(e.message,e,s),this.name="TimeoutError",this.event=e.event,this.timings=r}};Ln.TimeoutError=sT;var tv=class extends fs{constructor(e,r){super(e.message,e,r),this.name="ReadError"}};Ln.ReadError=tv;var oT=class extends fs{constructor(e){super(`Unsupported protocol "${e.url.protocol}"`,{},e),this.name="UnsupportedProtocolError"}};Ln.UnsupportedProtocolError=oT;var Yrt=["socket","connect","continue","information","upgrade","timeout"],aT=class extends yAe.Duplex{constructor(e,r={},s){super({autoDestroy:!1,highWaterMark:0}),this[yI]=0,this[II]=0,this.requestInitialized=!1,this[ZQ]=new Set,this.redirects=[],this[CI]=!1,this[$Q]=!1,this[ev]=[],this.retryCount=0,this._progressCallbacks=[];let a=()=>this._unlockWrite(),n=()=>this._lockWrite();this.on("pipe",h=>{h.prependListener("data",a),h.on("data",n),h.prependListener("end",a),h.on("end",n)}),this.on("unpipe",h=>{h.off("data",a),h.off("data",n),h.off("end",a),h.off("end",n)}),this.on("pipe",h=>{h instanceof JH.IncomingMessage&&(this.options.headers={...h.headers,...this.options.headers})});let{json:c,body:f,form:p}=r;if((c||f||p)&&this._lockWrite(),Ln.kIsNormalizedAlready in r)this.options=r;else try{this.options=this.constructor.normalizeArguments(e,r,s)}catch(h){at.default.nodeStream(r.body)&&r.body.destroy(),this.destroy(h);return}(async()=>{var h;try{this.options.body instanceof Srt.ReadStream&&await Grt(this.options.body);let{url:E}=this.options;if(!E)throw new TypeError("Missing `url` property");if(this.requestUrl=E.toString(),decodeURI(this.requestUrl),await this._finalizeBody(),await this._makeRequest(),this.destroyed){(h=this[po])===null||h===void 0||h.destroy();return}for(let C of this[ev])C();this[ev].length=0,this.requestInitialized=!0}catch(E){if(E instanceof fs){this._beforeError(E);return}this.destroyed||this.destroy(E)}})()}static normalizeArguments(e,r,s){var a,n,c,f,p;let h=r;if(at.default.object(e)&&!at.default.urlInstance(e))r={...s,...e,...r};else{if(e&&r&&r.url!==void 0)throw new TypeError("The `url` option is mutually exclusive with the `input` argument");r={...s,...r},e!==void 0&&(r.url=e),at.default.urlInstance(r.url)&&(r.url=new w0.URL(r.url.toString()))}if(r.cache===!1&&(r.cache=void 0),r.dnsCache===!1&&(r.dnsCache=void 0),at.assert.any([at.default.string,at.default.undefined],r.method),at.assert.any([at.default.object,at.default.undefined],r.headers),at.assert.any([at.default.string,at.default.urlInstance,at.default.undefined],r.prefixUrl),at.assert.any([at.default.object,at.default.undefined],r.cookieJar),at.assert.any([at.default.object,at.default.string,at.default.undefined],r.searchParams),at.assert.any([at.default.object,at.default.string,at.default.undefined],r.cache),at.assert.any([at.default.object,at.default.number,at.default.undefined],r.timeout),at.assert.any([at.default.object,at.default.undefined],r.context),at.assert.any([at.default.object,at.default.undefined],r.hooks),at.assert.any([at.default.boolean,at.default.undefined],r.decompress),at.assert.any([at.default.boolean,at.default.undefined],r.ignoreInvalidCookies),at.assert.any([at.default.boolean,at.default.undefined],r.followRedirect),at.assert.any([at.default.number,at.default.undefined],r.maxRedirects),at.assert.any([at.default.boolean,at.default.undefined],r.throwHttpErrors),at.assert.any([at.default.boolean,at.default.undefined],r.http2),at.assert.any([at.default.boolean,at.default.undefined],r.allowGetBody),at.assert.any([at.default.string,at.default.undefined],r.localAddress),at.assert.any([vAe.isDnsLookupIpVersion,at.default.undefined],r.dnsLookupIpVersion),at.assert.any([at.default.object,at.default.undefined],r.https),at.assert.any([at.default.boolean,at.default.undefined],r.rejectUnauthorized),r.https&&(at.assert.any([at.default.boolean,at.default.undefined],r.https.rejectUnauthorized),at.assert.any([at.default.function_,at.default.undefined],r.https.checkServerIdentity),at.assert.any([at.default.string,at.default.object,at.default.array,at.default.undefined],r.https.certificateAuthority),at.assert.any([at.default.string,at.default.object,at.default.array,at.default.undefined],r.https.key),at.assert.any([at.default.string,at.default.object,at.default.array,at.default.undefined],r.https.certificate),at.assert.any([at.default.string,at.default.undefined],r.https.passphrase),at.assert.any([at.default.string,at.default.buffer,at.default.array,at.default.undefined],r.https.pfx)),at.assert.any([at.default.object,at.default.undefined],r.cacheOptions),at.default.string(r.method)?r.method=r.method.toUpperCase():r.method="GET",r.headers===s?.headers?r.headers={...r.headers}:r.headers=Qrt({...s?.headers,...r.headers}),"slashes"in r)throw new TypeError("The legacy `url.Url` has been deprecated. Use `URL` instead.");if("auth"in r)throw new TypeError("Parameter `auth` is deprecated. Use `username` / `password` instead.");if("searchParams"in r&&r.searchParams&&r.searchParams!==s?.searchParams){let P;if(at.default.string(r.searchParams)||r.searchParams instanceof w0.URLSearchParams)P=new w0.URLSearchParams(r.searchParams);else{Hrt(r.searchParams),P=new w0.URLSearchParams;for(let I in r.searchParams){let R=r.searchParams[I];R===null?P.append(I,""):R!==void 0&&P.append(I,R)}}(a=s?.searchParams)===null||a===void 0||a.forEach((I,R)=>{P.has(R)||P.append(R,I)}),r.searchParams=P}if(r.username=(n=r.username)!==null&&n!==void 0?n:"",r.password=(c=r.password)!==null&&c!==void 0?c:"",at.default.undefined(r.prefixUrl)?r.prefixUrl=(f=s?.prefixUrl)!==null&&f!==void 0?f:"":(r.prefixUrl=r.prefixUrl.toString(),r.prefixUrl!==""&&!r.prefixUrl.endsWith("/")&&(r.prefixUrl+="/")),at.default.string(r.url)){if(r.url.startsWith("/"))throw new Error("`input` must not start with a slash when using `prefixUrl`");r.url=BAe.default(r.prefixUrl+r.url,r)}else(at.default.undefined(r.url)&&r.prefixUrl!==""||r.protocol)&&(r.url=BAe.default(r.prefixUrl,r));if(r.url){"port"in r&&delete r.port;let{prefixUrl:P}=r;Object.defineProperty(r,"prefixUrl",{set:R=>{let N=r.url;if(!N.href.startsWith(R))throw new Error(`Cannot change \`prefixUrl\` from ${P} to ${R}: ${N.href}`);r.url=new w0.URL(R+N.href.slice(P.length)),P=R},get:()=>P});let{protocol:I}=r.url;if(I==="unix:"&&(I="http:",r.url=new w0.URL(`http://unix${r.url.pathname}${r.url.search}`)),r.searchParams&&(r.url.search=r.searchParams.toString()),I!=="http:"&&I!=="https:")throw new oT(r);r.username===""?r.username=r.url.username:r.url.username=r.username,r.password===""?r.password=r.url.password:r.url.password=r.password}let{cookieJar:E}=r;if(E){let{setCookie:P,getCookieString:I}=E;at.assert.function_(P),at.assert.function_(I),P.length===4&&I.length===0&&(P=mAe.promisify(P.bind(r.cookieJar)),I=mAe.promisify(I.bind(r.cookieJar)),r.cookieJar={setCookie:P,getCookieString:I})}let{cache:C}=r;if(C&&(XH.has(C)||XH.set(C,new IAe((P,I)=>{let R=P[po](P,I);return at.default.promise(R)&&(R.once=(N,U)=>{if(N==="error")R.catch(U);else if(N==="abort")(async()=>{try{(await R).once("abort",U)}catch{}})();else throw new Error(`Unknown HTTP2 promise event: ${N}`);return R}),R},C))),r.cacheOptions={...r.cacheOptions},r.dnsCache===!0)KH||(KH=new Prt.default),r.dnsCache=KH;else if(!at.default.undefined(r.dnsCache)&&!r.dnsCache.lookup)throw new TypeError(`Parameter \`dnsCache\` must be a CacheableLookup instance or a boolean, got ${at.default(r.dnsCache)}`);at.default.number(r.timeout)?r.timeout={request:r.timeout}:s&&r.timeout!==s.timeout?r.timeout={...s.timeout,...r.timeout}:r.timeout={...r.timeout},r.context||(r.context={});let S=r.hooks===s?.hooks;r.hooks={...r.hooks};for(let P of Ln.knownHookEvents)if(P in r.hooks)if(at.default.array(r.hooks[P]))r.hooks[P]=[...r.hooks[P]];else throw new TypeError(`Parameter \`${P}\` must be an Array, got ${at.default(r.hooks[P])}`);else r.hooks[P]=[];if(s&&!S)for(let P of Ln.knownHookEvents)s.hooks[P].length>0&&(r.hooks[P]=[...s.hooks[P],...r.hooks[P]]);if("family"in r&&B0.default('"options.family" was never documented, please use "options.dnsLookupIpVersion"'),s?.https&&(r.https={...s.https,...r.https}),"rejectUnauthorized"in r&&B0.default('"options.rejectUnauthorized" is now deprecated, please use "options.https.rejectUnauthorized"'),"checkServerIdentity"in r&&B0.default('"options.checkServerIdentity" was never documented, please use "options.https.checkServerIdentity"'),"ca"in r&&B0.default('"options.ca" was never documented, please use "options.https.certificateAuthority"'),"key"in r&&B0.default('"options.key" was never documented, please use "options.https.key"'),"cert"in r&&B0.default('"options.cert" was never documented, please use "options.https.certificate"'),"passphrase"in r&&B0.default('"options.passphrase" was never documented, please use "options.https.passphrase"'),"pfx"in r&&B0.default('"options.pfx" was never documented, please use "options.https.pfx"'),"followRedirects"in r)throw new TypeError("The `followRedirects` option does not exist. Use `followRedirect` instead.");if(r.agent){for(let P in r.agent)if(P!=="http"&&P!=="https"&&P!=="http2")throw new TypeError(`Expected the \`options.agent\` properties to be \`http\`, \`https\` or \`http2\`, got \`${P}\``)}return r.maxRedirects=(p=r.maxRedirects)!==null&&p!==void 0?p:0,Ln.setNonEnumerableProperties([s,h],r),Mrt.default(r,s)}_lockWrite(){let e=()=>{throw new TypeError("The payload has been already provided")};this.write=e,this.end=e}_unlockWrite(){this.write=super.write,this.end=super.end}async _finalizeBody(){let{options:e}=this,{headers:r}=e,s=!at.default.undefined(e.form),a=!at.default.undefined(e.json),n=!at.default.undefined(e.body),c=s||a||n,f=Ln.withoutBody.has(e.method)&&!(e.method==="GET"&&e.allowGetBody);if(this._cannotHaveBody=f,c){if(f)throw new TypeError(`The \`${e.method}\` method cannot be used with a body`);if([n,s,a].filter(p=>p).length>1)throw new TypeError("The `body`, `json` and `form` options are mutually exclusive");if(n&&!(e.body instanceof yAe.Readable)&&!at.default.string(e.body)&&!at.default.buffer(e.body)&&!CAe.default(e.body))throw new TypeError("The `body` option must be a stream.Readable, string or Buffer");if(s&&!at.default.object(e.form))throw new TypeError("The `form` option must be an Object");{let p=!at.default.string(r["content-type"]);n?(CAe.default(e.body)&&p&&(r["content-type"]=`multipart/form-data; boundary=${e.body.getBoundary()}`),this[v0]=e.body):s?(p&&(r["content-type"]="application/x-www-form-urlencoded"),this[v0]=new w0.URLSearchParams(e.form).toString()):(p&&(r["content-type"]="application/json"),this[v0]=e.stringifyJson(e.json));let h=await Trt.default(this[v0],e.headers);at.default.undefined(r["content-length"])&&at.default.undefined(r["transfer-encoding"])&&!f&&!at.default.undefined(h)&&(r["content-length"]=String(h))}}else f?this._lockWrite():this._unlockWrite();this[EI]=Number(r["content-length"])||void 0}async _onResponseBase(e){let{options:r}=this,{url:s}=r;this[PAe]=e,r.decompress&&(e=xrt(e));let a=e.statusCode,n=e;n.statusMessage=n.statusMessage?n.statusMessage:EAe.STATUS_CODES[a],n.url=r.url.toString(),n.requestUrl=this.requestUrl,n.redirectUrls=this.redirects,n.request=this,n.isFromCache=e.fromCache||!1,n.ip=this.ip,n.retryCount=this.retryCount,this[DAe]=n.isFromCache,this[mI]=Number(e.headers["content-length"])||void 0,this[eT]=e,e.once("end",()=>{this[mI]=this[yI],this.emit("downloadProgress",this.downloadProgress)}),e.once("error",f=>{e.destroy(),this._beforeError(new tv(f,this))}),e.once("aborted",()=>{this._beforeError(new tv({name:"Error",message:"The server aborted pending request",code:"ECONNRESET"},this))}),this.emit("downloadProgress",this.downloadProgress);let c=e.headers["set-cookie"];if(at.default.object(r.cookieJar)&&c){let f=c.map(async p=>r.cookieJar.setCookie(p,s.toString()));r.ignoreInvalidCookies&&(f=f.map(async p=>p.catch(()=>{})));try{await Promise.all(f)}catch(p){this._beforeError(p);return}}if(r.followRedirect&&e.headers.location&&qrt.has(a)){if(e.resume(),this[po]&&(this[zH](),delete this[po],this[SAe]()),(a===303&&r.method!=="GET"&&r.method!=="HEAD"||!r.methodRewriting)&&(r.method="GET","body"in r&&delete r.body,"json"in r&&delete r.json,"form"in r&&delete r.form,this[v0]=void 0,delete r.headers["content-length"]),this.redirects.length>=r.maxRedirects){this._beforeError(new tT(this));return}try{let p=Buffer.from(e.headers.location,"binary").toString(),h=new w0.URL(p,s),E=h.toString();decodeURI(E),h.hostname!==s.hostname||h.port!==s.port?("host"in r.headers&&delete r.headers.host,"cookie"in r.headers&&delete r.headers.cookie,"authorization"in r.headers&&delete r.headers.authorization,(r.username||r.password)&&(r.username="",r.password="")):(h.username=r.username,h.password=r.password),this.redirects.push(E),r.url=h;for(let C of r.hooks.beforeRedirect)await C(r,n);this.emit("redirect",n,r),await this._makeRequest()}catch(p){this._beforeError(p);return}return}if(r.isStream&&r.throwHttpErrors&&!Lrt.isResponseOk(n)){this._beforeError(new rT(n));return}e.on("readable",()=>{this[$Q]&&this._read()}),this.on("resume",()=>{e.resume()}),this.on("pause",()=>{e.pause()}),e.once("end",()=>{this.push(null)}),this.emit("response",e);for(let f of this[ZQ])if(!f.headersSent){for(let p in e.headers){let h=r.decompress?p!=="content-encoding":!0,E=e.headers[p];h&&f.setHeader(p,E)}f.statusCode=a}}async _onResponse(e){try{await this._onResponseBase(e)}catch(r){this._beforeError(r)}}_onRequest(e){let{options:r}=this,{timeout:s,url:a}=r;brt.default(e),this[zH]=wAe.default(e,s,a);let n=r.cache?"cacheableResponse":"response";e.once(n,p=>{this._onResponse(p)}),e.once("error",p=>{var h;e.destroy(),(h=e.res)===null||h===void 0||h.removeAllListeners("end"),p=p instanceof wAe.TimeoutError?new sT(p,this.timings,this):new fs(p.message,p,this),this._beforeError(p)}),this[SAe]=Rrt.default(e,this,Yrt),this[po]=e,this.emit("uploadProgress",this.uploadProgress);let c=this[v0],f=this.redirects.length===0?this:e;at.default.nodeStream(c)?(c.pipe(f),c.once("error",p=>{this._beforeError(new iT(p,this))})):(this._unlockWrite(),at.default.undefined(c)?(this._cannotHaveBody||this._noPipe)&&(f.end(),this._lockWrite()):(this._writeRequest(c,void 0,()=>{}),f.end(),this._lockWrite())),this.emit("request",e)}async _createCacheableRequest(e,r){return new Promise((s,a)=>{Object.assign(r,Frt.default(e)),delete r.url;let n,c=XH.get(r.cache)(r,async f=>{f._readableState.autoDestroy=!1,n&&(await n).emit("cacheableResponse",f),s(f)});r.url=e,c.once("error",a),c.once("request",async f=>{n=f,s(n)})})}async _makeRequest(){var e,r,s,a,n;let{options:c}=this,{headers:f}=c;for(let U in f)if(at.default.undefined(f[U]))delete f[U];else if(at.default.null_(f[U]))throw new TypeError(`Use \`undefined\` instead of \`null\` to delete the \`${U}\` header`);if(c.decompress&&at.default.undefined(f["accept-encoding"])&&(f["accept-encoding"]=_rt?"gzip, deflate, br":"gzip, deflate"),c.cookieJar){let U=await c.cookieJar.getCookieString(c.url.toString());at.default.nonEmptyString(U)&&(c.headers.cookie=U)}for(let U of c.hooks.beforeRequest){let W=await U(c);if(!at.default.undefined(W)){c.request=()=>W;break}}c.body&&this[v0]!==c.body&&(this[v0]=c.body);let{agent:p,request:h,timeout:E,url:C}=c;if(c.dnsCache&&!("lookup"in c)&&(c.lookup=c.dnsCache.lookup),C.hostname==="unix"){let U=/(?.+?):(?.+)/.exec(`${C.pathname}${C.search}`);if(U?.groups){let{socketPath:W,path:ee}=U.groups;Object.assign(c,{socketPath:W,path:ee,host:""})}}let S=C.protocol==="https:",P;c.http2?P=krt.auto:P=S?Drt.request:EAe.request;let I=(e=c.request)!==null&&e!==void 0?e:P,R=c.cache?this._createCacheableRequest:I;p&&!c.http2&&(c.agent=p[S?"https":"http"]),c[po]=I,delete c.request,delete c.timeout;let N=c;if(N.shared=(r=c.cacheOptions)===null||r===void 0?void 0:r.shared,N.cacheHeuristic=(s=c.cacheOptions)===null||s===void 0?void 0:s.cacheHeuristic,N.immutableMinTimeToLive=(a=c.cacheOptions)===null||a===void 0?void 0:a.immutableMinTimeToLive,N.ignoreCargoCult=(n=c.cacheOptions)===null||n===void 0?void 0:n.ignoreCargoCult,c.dnsLookupIpVersion!==void 0)try{N.family=vAe.dnsLookupIpVersionToFamily(c.dnsLookupIpVersion)}catch{throw new Error("Invalid `dnsLookupIpVersion` option value")}c.https&&("rejectUnauthorized"in c.https&&(N.rejectUnauthorized=c.https.rejectUnauthorized),c.https.checkServerIdentity&&(N.checkServerIdentity=c.https.checkServerIdentity),c.https.certificateAuthority&&(N.ca=c.https.certificateAuthority),c.https.certificate&&(N.cert=c.https.certificate),c.https.key&&(N.key=c.https.key),c.https.passphrase&&(N.passphrase=c.https.passphrase),c.https.pfx&&(N.pfx=c.https.pfx));try{let U=await R(C,N);at.default.undefined(U)&&(U=P(C,N)),c.request=h,c.timeout=E,c.agent=p,c.https&&("rejectUnauthorized"in c.https&&delete N.rejectUnauthorized,c.https.checkServerIdentity&&delete N.checkServerIdentity,c.https.certificateAuthority&&delete N.ca,c.https.certificate&&delete N.cert,c.https.key&&delete N.key,c.https.passphrase&&delete N.passphrase,c.https.pfx&&delete N.pfx),jrt(U)?this._onRequest(U):this.writable?(this.once("finish",()=>{this._onResponse(U)}),this._unlockWrite(),this.end(),this._lockWrite()):this._onResponse(U)}catch(U){throw U instanceof IAe.CacheError?new nT(U,this):new fs(U.message,U,this)}}async _error(e){try{for(let r of this.options.hooks.beforeError)e=await r(e)}catch(r){e=new fs(r.message,r,this)}this.destroy(e)}_beforeError(e){if(this[CI])return;let{options:r}=this,s=this.retryCount+1;this[CI]=!0,e instanceof fs||(e=new fs(e.message,e,this));let a=e,{response:n}=a;(async()=>{if(n&&!n.body){n.setEncoding(this._readableState.encoding);try{n.rawBody=await Ort.default(n),n.body=n.rawBody.toString()}catch{}}if(this.listenerCount("retry")!==0){let c;try{let f;n&&"retry-after"in n.headers&&(f=Number(n.headers["retry-after"]),Number.isNaN(f)?(f=Date.parse(n.headers["retry-after"])-Date.now(),f<=0&&(f=1)):f*=1e3),c=await r.retry.calculateDelay({attemptCount:s,retryOptions:r.retry,error:a,retryAfter:f,computedValue:Urt.default({attemptCount:s,retryOptions:r.retry,error:a,retryAfter:f,computedValue:0})})}catch(f){this._error(new fs(f.message,f,this));return}if(c){let f=async()=>{try{for(let p of this.options.hooks.beforeRetry)await p(this.options,a,s)}catch(p){this._error(new fs(p.message,e,this));return}this.destroyed||(this.destroy(),this.emit("retry",s,e))};this[xAe]=setTimeout(f,c);return}}this._error(a)})()}_read(){this[$Q]=!0;let e=this[eT];if(e&&!this[CI]){e.readableLength&&(this[$Q]=!1);let r;for(;(r=e.read())!==null;){this[yI]+=r.length,this[bAe]=!0;let s=this.downloadProgress;s.percent<1&&this.emit("downloadProgress",s),this.push(r)}}}_write(e,r,s){let a=()=>{this._writeRequest(e,r,s)};this.requestInitialized?a():this[ev].push(a)}_writeRequest(e,r,s){this[po].destroyed||(this._progressCallbacks.push(()=>{this[II]+=Buffer.byteLength(e,r);let a=this.uploadProgress;a.percent<1&&this.emit("uploadProgress",a)}),this[po].write(e,r,a=>{!a&&this._progressCallbacks.length>0&&this._progressCallbacks.shift()(),s(a)}))}_final(e){let r=()=>{for(;this._progressCallbacks.length!==0;)this._progressCallbacks.shift()();if(!(po in this)){e();return}if(this[po].destroyed){e();return}this[po].end(s=>{s||(this[EI]=this[II],this.emit("uploadProgress",this.uploadProgress),this[po].emit("upload-complete")),e(s)})};this.requestInitialized?r():this[ev].push(r)}_destroy(e,r){var s;this[CI]=!0,clearTimeout(this[xAe]),po in this&&(this[zH](),!((s=this[eT])===null||s===void 0)&&s.complete||this[po].destroy()),e!==null&&!at.default.undefined(e)&&!(e instanceof fs)&&(e=new fs(e.message,e,this)),r(e)}get _isAboutToError(){return this[CI]}get ip(){var e;return(e=this.socket)===null||e===void 0?void 0:e.remoteAddress}get aborted(){var e,r,s;return((r=(e=this[po])===null||e===void 0?void 0:e.destroyed)!==null&&r!==void 0?r:this.destroyed)&&!(!((s=this[PAe])===null||s===void 0)&&s.complete)}get socket(){var e,r;return(r=(e=this[po])===null||e===void 0?void 0:e.socket)!==null&&r!==void 0?r:void 0}get downloadProgress(){let e;return this[mI]?e=this[yI]/this[mI]:this[mI]===this[yI]?e=1:e=0,{percent:e,transferred:this[yI],total:this[mI]}}get uploadProgress(){let e;return this[EI]?e=this[II]/this[EI]:this[EI]===this[II]?e=1:e=0,{percent:e,transferred:this[II],total:this[EI]}}get timings(){var e;return(e=this[po])===null||e===void 0?void 0:e.timings}get isFromCache(){return this[DAe]}pipe(e,r){if(this[bAe])throw new Error("Failed to pipe. The response has been emitted already.");return e instanceof JH.ServerResponse&&this[ZQ].add(e),super.pipe(e,r)}unpipe(e){return e instanceof JH.ServerResponse&&this[ZQ].delete(e),super.unpipe(e),this}};Ln.default=aT});var nv=_(qu=>{"use strict";var Vrt=qu&&qu.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r),Object.defineProperty(t,s,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),Jrt=qu&&qu.__exportStar||function(t,e){for(var r in t)r!=="default"&&!Object.prototype.hasOwnProperty.call(e,r)&&Vrt(e,t,r)};Object.defineProperty(qu,"__esModule",{value:!0});qu.CancelError=qu.ParseError=void 0;var kAe=rv(),ZH=class extends kAe.RequestError{constructor(e,r){let{options:s}=r.request;super(`${e.message} in "${s.url.toString()}"`,e,r.request),this.name="ParseError"}};qu.ParseError=ZH;var $H=class extends kAe.RequestError{constructor(e){super("Promise was canceled",{},e),this.name="CancelError"}get isCanceled(){return!0}};qu.CancelError=$H;Jrt(rv(),qu)});var TAe=_(ej=>{"use strict";Object.defineProperty(ej,"__esModule",{value:!0});var QAe=nv(),Krt=(t,e,r,s)=>{let{rawBody:a}=t;try{if(e==="text")return a.toString(s);if(e==="json")return a.length===0?"":r(a.toString());if(e==="buffer")return a;throw new QAe.ParseError({message:`Unknown body type '${e}'`,name:"Error"},t)}catch(n){throw new QAe.ParseError(n,t)}};ej.default=Krt});var tj=_(S0=>{"use strict";var zrt=S0&&S0.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r),Object.defineProperty(t,s,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),Xrt=S0&&S0.__exportStar||function(t,e){for(var r in t)r!=="default"&&!Object.prototype.hasOwnProperty.call(e,r)&&zrt(e,t,r)};Object.defineProperty(S0,"__esModule",{value:!0});var Zrt=Ie("events"),$rt=Np(),ent=Que(),lT=nv(),RAe=TAe(),FAe=rv(),tnt=LH(),rnt=qH(),NAe=WH(),nnt=["request","response","redirect","uploadProgress","downloadProgress"];function OAe(t){let e,r,s=new Zrt.EventEmitter,a=new ent((c,f,p)=>{let h=E=>{let C=new FAe.default(void 0,t);C.retryCount=E,C._noPipe=!0,p(()=>C.destroy()),p.shouldReject=!1,p(()=>f(new lT.CancelError(C))),e=C,C.once("response",async I=>{var R;if(I.retryCount=E,I.request.aborted)return;let N;try{N=await rnt.default(C),I.rawBody=N}catch{return}if(C._isAboutToError)return;let U=((R=I.headers["content-encoding"])!==null&&R!==void 0?R:"").toLowerCase(),W=["gzip","deflate","br"].includes(U),{options:ee}=C;if(W&&!ee.decompress)I.body=N;else try{I.body=RAe.default(I,ee.responseType,ee.parseJson,ee.encoding)}catch(ie){if(I.body=N.toString(),NAe.isResponseOk(I)){C._beforeError(ie);return}}try{for(let[ie,ue]of ee.hooks.afterResponse.entries())I=await ue(I,async le=>{let me=FAe.default.normalizeArguments(void 0,{...le,retry:{calculateDelay:()=>0},throwHttpErrors:!1,resolveBodyOnly:!1},ee);me.hooks.afterResponse=me.hooks.afterResponse.slice(0,ie);for(let Be of me.hooks.beforeRetry)await Be(me);let pe=OAe(me);return p(()=>{pe.catch(()=>{}),pe.cancel()}),pe})}catch(ie){C._beforeError(new lT.RequestError(ie.message,ie,C));return}if(!NAe.isResponseOk(I)){C._beforeError(new lT.HTTPError(I));return}r=I,c(C.options.resolveBodyOnly?I.body:I)});let S=I=>{if(a.isCanceled)return;let{options:R}=C;if(I instanceof lT.HTTPError&&!R.throwHttpErrors){let{response:N}=I;c(C.options.resolveBodyOnly?N.body:N);return}f(I)};C.once("error",S);let P=C.options.body;C.once("retry",(I,R)=>{var N,U;if(P===((N=R.request)===null||N===void 0?void 0:N.options.body)&&$rt.default.nodeStream((U=R.request)===null||U===void 0?void 0:U.options.body)){S(R);return}h(I)}),tnt.default(C,s,nnt)};h(0)});a.on=(c,f)=>(s.on(c,f),a);let n=c=>{let f=(async()=>{await a;let{options:p}=r.request;return RAe.default(r,c,p.parseJson,p.encoding)})();return Object.defineProperties(f,Object.getOwnPropertyDescriptors(a)),f};return a.json=()=>{let{headers:c}=e.options;return!e.writableFinished&&c.accept===void 0&&(c.accept="application/json"),n("json")},a.buffer=()=>n("buffer"),a.text=()=>n("text"),a}S0.default=OAe;Xrt(nv(),S0)});var LAe=_(rj=>{"use strict";Object.defineProperty(rj,"__esModule",{value:!0});var int=nv();function snt(t,...e){let r=(async()=>{if(t instanceof int.RequestError)try{for(let a of e)if(a)for(let n of a)t=await n(t)}catch(a){t=a}throw t})(),s=()=>r;return r.json=s,r.text=s,r.buffer=s,r.on=s,r}rj.default=snt});var _Ae=_(nj=>{"use strict";Object.defineProperty(nj,"__esModule",{value:!0});var MAe=Np();function UAe(t){for(let e of Object.values(t))(MAe.default.plainObject(e)||MAe.default.array(e))&&UAe(e);return Object.freeze(t)}nj.default=UAe});var jAe=_(HAe=>{"use strict";Object.defineProperty(HAe,"__esModule",{value:!0})});var ij=_(Nc=>{"use strict";var ont=Nc&&Nc.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r),Object.defineProperty(t,s,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),ant=Nc&&Nc.__exportStar||function(t,e){for(var r in t)r!=="default"&&!Object.prototype.hasOwnProperty.call(e,r)&&ont(e,t,r)};Object.defineProperty(Nc,"__esModule",{value:!0});Nc.defaultHandler=void 0;var GAe=Np(),Fc=tj(),lnt=LAe(),uT=rv(),cnt=_Ae(),unt={RequestError:Fc.RequestError,CacheError:Fc.CacheError,ReadError:Fc.ReadError,HTTPError:Fc.HTTPError,MaxRedirectsError:Fc.MaxRedirectsError,TimeoutError:Fc.TimeoutError,ParseError:Fc.ParseError,CancelError:Fc.CancelError,UnsupportedProtocolError:Fc.UnsupportedProtocolError,UploadError:Fc.UploadError},fnt=async t=>new Promise(e=>{setTimeout(e,t)}),{normalizeArguments:cT}=uT.default,qAe=(...t)=>{let e;for(let r of t)e=cT(void 0,r,e);return e},Ant=t=>t.isStream?new uT.default(void 0,t):Fc.default(t),pnt=t=>"defaults"in t&&"options"in t.defaults,hnt=["get","post","put","patch","head","delete"];Nc.defaultHandler=(t,e)=>e(t);var WAe=(t,e)=>{if(t)for(let r of t)r(e)},YAe=t=>{t._rawHandlers=t.handlers,t.handlers=t.handlers.map(s=>(a,n)=>{let c,f=s(a,p=>(c=n(p),c));if(f!==c&&!a.isStream&&c){let p=f,{then:h,catch:E,finally:C}=p;Object.setPrototypeOf(p,Object.getPrototypeOf(c)),Object.defineProperties(p,Object.getOwnPropertyDescriptors(c)),p.then=h,p.catch=E,p.finally=C}return f});let e=(s,a={},n)=>{var c,f;let p=0,h=E=>t.handlers[p++](E,p===t.handlers.length?Ant:h);if(GAe.default.plainObject(s)){let E={...s,...a};uT.setNonEnumerableProperties([s,a],E),a=E,s=void 0}try{let E;try{WAe(t.options.hooks.init,a),WAe((c=a.hooks)===null||c===void 0?void 0:c.init,a)}catch(S){E=S}let C=cT(s,a,n??t.options);if(C[uT.kIsNormalizedAlready]=!0,E)throw new Fc.RequestError(E.message,E,C);return h(C)}catch(E){if(a.isStream)throw E;return lnt.default(E,t.options.hooks.beforeError,(f=a.hooks)===null||f===void 0?void 0:f.beforeError)}};e.extend=(...s)=>{let a=[t.options],n=[...t._rawHandlers],c;for(let f of s)pnt(f)?(a.push(f.defaults.options),n.push(...f.defaults._rawHandlers),c=f.defaults.mutableDefaults):(a.push(f),"handlers"in f&&n.push(...f.handlers),c=f.mutableDefaults);return n=n.filter(f=>f!==Nc.defaultHandler),n.length===0&&n.push(Nc.defaultHandler),YAe({options:qAe(...a),handlers:n,mutableDefaults:!!c})};let r=async function*(s,a){let n=cT(s,a,t.options);n.resolveBodyOnly=!1;let c=n.pagination;if(!GAe.default.object(c))throw new TypeError("`options.pagination` must be implemented");let f=[],{countLimit:p}=c,h=0;for(;h{let n=[];for await(let c of r(s,a))n.push(c);return n},e.paginate.each=r,e.stream=(s,a)=>e(s,{...a,isStream:!0});for(let s of hnt)e[s]=(a,n)=>e(a,{...n,method:s}),e.stream[s]=(a,n)=>e(a,{...n,method:s,isStream:!0});return Object.assign(e,unt),Object.defineProperty(e,"defaults",{value:t.mutableDefaults?t:cnt.default(t),writable:t.mutableDefaults,configurable:t.mutableDefaults,enumerable:!0}),e.mergeOptions=qAe,e};Nc.default=YAe;ant(jAe(),Nc)});var KAe=_((Op,fT)=>{"use strict";var gnt=Op&&Op.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r),Object.defineProperty(t,s,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),VAe=Op&&Op.__exportStar||function(t,e){for(var r in t)r!=="default"&&!Object.prototype.hasOwnProperty.call(e,r)&&gnt(e,t,r)};Object.defineProperty(Op,"__esModule",{value:!0});var dnt=Ie("url"),JAe=ij(),mnt={options:{method:"GET",retry:{limit:2,methods:["GET","PUT","HEAD","DELETE","OPTIONS","TRACE"],statusCodes:[408,413,429,500,502,503,504,521,522,524],errorCodes:["ETIMEDOUT","ECONNRESET","EADDRINUSE","ECONNREFUSED","EPIPE","ENOTFOUND","ENETUNREACH","EAI_AGAIN"],maxRetryAfter:void 0,calculateDelay:({computedValue:t})=>t},timeout:{},headers:{"user-agent":"got (https://github.com/sindresorhus/got)"},hooks:{init:[],beforeRequest:[],beforeRedirect:[],beforeRetry:[],beforeError:[],afterResponse:[]},cache:void 0,dnsCache:void 0,decompress:!0,throwHttpErrors:!0,followRedirect:!0,isStream:!1,responseType:"text",resolveBodyOnly:!1,maxRedirects:10,prefixUrl:"",methodRewriting:!0,ignoreInvalidCookies:!1,context:{},http2:!1,allowGetBody:!1,https:void 0,pagination:{transform:t=>t.request.options.responseType==="json"?t.body:JSON.parse(t.body),paginate:t=>{if(!Reflect.has(t.headers,"link"))return!1;let e=t.headers.link.split(","),r;for(let s of e){let a=s.split(";");if(a[1].includes("next")){r=a[0].trimStart().trim(),r=r.slice(1,-1);break}}return r?{url:new dnt.URL(r)}:!1},filter:()=>!0,shouldContinue:()=>!0,countLimit:1/0,backoff:0,requestLimit:1e4,stackAllItems:!0},parseJson:t=>JSON.parse(t),stringifyJson:t=>JSON.stringify(t),cacheOptions:{}},handlers:[JAe.defaultHandler],mutableDefaults:!1},sj=JAe.default(mnt);Op.default=sj;fT.exports=sj;fT.exports.default=sj;fT.exports.__esModule=!0;VAe(ij(),Op);VAe(tj(),Op)});var nn={};Vt(nn,{Method:()=>tpe,del:()=>wnt,get:()=>lj,getNetworkSettings:()=>epe,post:()=>cj,put:()=>Cnt,request:()=>iv});async function oj(t){return Yl(XAe,t,()=>ce.readFilePromise(t).then(e=>(XAe.set(t,e),e)))}function Int({statusCode:t,statusMessage:e},r){let s=Ht(r,t,ht.NUMBER),a=`https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/${t}`;return KE(r,`${s}${e?` (${e})`:""}`,a)}async function AT(t,{configuration:e,customErrorMessage:r}){try{return await t}catch(s){if(s.name!=="HTTPError")throw s;let a=r?.(s,e)??s.response.body?.error;a==null&&(s.message.startsWith("Response code")?a="The remote server failed to provide the requested resource":a=s.message),s.code==="ETIMEDOUT"&&s.event==="socket"&&(a+=`(can be increased via ${Ht(e,"httpTimeout",ht.SETTING)})`);let n=new jt(35,a,c=>{s.response&&c.reportError(35,` ${Kf(e,{label:"Response Code",value:_u(ht.NO_HINT,Int(s.response,e))})}`),s.request&&(c.reportError(35,` ${Kf(e,{label:"Request Method",value:_u(ht.NO_HINT,s.request.options.method)})}`),c.reportError(35,` ${Kf(e,{label:"Request URL",value:_u(ht.URL,s.request.requestUrl)})}`)),s.request.redirects.length>0&&c.reportError(35,` ${Kf(e,{label:"Request Redirects",value:_u(ht.NO_HINT,Z4(e,s.request.redirects,ht.URL))})}`),s.request.retryCount===s.request.options.retry.limit&&c.reportError(35,` ${Kf(e,{label:"Request Retry Count",value:_u(ht.NO_HINT,`${Ht(e,s.request.retryCount,ht.NUMBER)} (can be increased via ${Ht(e,"httpRetry",ht.SETTING)})`)})}`)});throw n.originalError=s,n}}function epe(t,e){let r=[...e.configuration.get("networkSettings")].sort(([c],[f])=>f.length-c.length),s={enableNetwork:void 0,httpsCaFilePath:void 0,httpProxy:void 0,httpsProxy:void 0,httpsKeyFilePath:void 0,httpsCertFilePath:void 0},a=Object.keys(s),n=typeof t=="string"?new URL(t):t;for(let[c,f]of r)if(aj.default.isMatch(n.hostname,c))for(let p of a){let h=f.get(p);h!==null&&typeof s[p]>"u"&&(s[p]=h)}for(let c of a)typeof s[c]>"u"&&(s[c]=e.configuration.get(c));return s}async function iv(t,e,{configuration:r,headers:s,jsonRequest:a,jsonResponse:n,method:c="GET",wrapNetworkRequest:f}){let p={target:t,body:e,configuration:r,headers:s,jsonRequest:a,jsonResponse:n,method:c},h=async()=>await Bnt(t,e,p),E=typeof f<"u"?await f(h,p):h;return await(await r.reduceHook(S=>S.wrapNetworkRequest,E,p))()}async function lj(t,{configuration:e,jsonResponse:r,customErrorMessage:s,wrapNetworkRequest:a,...n}){let c=()=>AT(iv(t,null,{configuration:e,wrapNetworkRequest:a,...n}),{configuration:e,customErrorMessage:s}).then(p=>p.body),f=await(typeof a<"u"?c():Yl(zAe,t,()=>c().then(p=>(zAe.set(t,p),p))));return r?JSON.parse(f.toString()):f}async function Cnt(t,e,{customErrorMessage:r,...s}){return(await AT(iv(t,e,{...s,method:"PUT"}),{customErrorMessage:r,configuration:s.configuration})).body}async function cj(t,e,{customErrorMessage:r,...s}){return(await AT(iv(t,e,{...s,method:"POST"}),{customErrorMessage:r,configuration:s.configuration})).body}async function wnt(t,{customErrorMessage:e,...r}){return(await AT(iv(t,null,{...r,method:"DELETE"}),{customErrorMessage:e,configuration:r.configuration})).body}async function Bnt(t,e,{configuration:r,headers:s,jsonRequest:a,jsonResponse:n,method:c="GET"}){let f=typeof t=="string"?new URL(t):t,p=epe(f,{configuration:r});if(p.enableNetwork===!1)throw new jt(80,`Request to '${f.href}' has been blocked because of your configuration settings`);if(f.protocol==="http:"&&!aj.default.isMatch(f.hostname,r.get("unsafeHttpWhitelist")))throw new jt(81,`Unsafe http requests must be explicitly whitelisted in your configuration (${f.hostname})`);let h={headers:s,method:c};h.responseType=n?"json":"buffer",e!==null&&(Buffer.isBuffer(e)||!a&&typeof e=="string"?h.body=e:h.json=e);let E=r.get("httpTimeout"),C=r.get("httpRetry"),S=r.get("enableStrictSsl"),P=p.httpsCaFilePath,I=p.httpsCertFilePath,R=p.httpsKeyFilePath,{default:N}=await Promise.resolve().then(()=>ut(KAe())),U=P?await oj(P):void 0,W=I?await oj(I):void 0,ee=R?await oj(R):void 0,ie={rejectUnauthorized:S,ca:U,cert:W,key:ee},ue={http:p.httpProxy?new vue({proxy:p.httpProxy,proxyRequestOptions:ie}):ynt,https:p.httpsProxy?new Sue({proxy:p.httpsProxy,proxyRequestOptions:ie}):Ent},le=N.extend({timeout:{socket:E},retry:C,agent:ue,https:{rejectUnauthorized:S,certificateAuthority:U,certificate:W,key:ee},...h});return r.getLimit("networkConcurrency")(()=>le(f))}var ZAe,$Ae,aj,zAe,XAe,ynt,Ent,tpe,pT=Xe(()=>{Dt();Due();ZAe=Ie("https"),$Ae=Ie("http"),aj=ut(Go());Tc();xc();Pc();zAe=new Map,XAe=new Map,ynt=new $Ae.Agent({keepAlive:!0}),Ent=new ZAe.Agent({keepAlive:!0});tpe=(a=>(a.GET="GET",a.PUT="PUT",a.POST="POST",a.DELETE="DELETE",a))(tpe||{})});var Ui={};Vt(Ui,{availableParallelism:()=>fj,getArchitecture:()=>sv,getArchitectureName:()=>Pnt,getArchitectureSet:()=>uj,getCaller:()=>Tnt,major:()=>vnt,openUrl:()=>Snt});function bnt(){if(process.platform!=="linux")return null;let t;try{t=ce.readFileSync(Dnt)}catch{}if(typeof t<"u"){if(t&&(t.includes("GLIBC")||t.includes("GNU libc")||t.includes("GNU C Library")))return"glibc";if(t&&t.includes("musl"))return"musl"}let r=(process.report?.getReport()??{}).sharedObjects??[],s=/\/(?:(ld-linux-|[^/]+-linux-gnu\/)|(libc.musl-|ld-musl-))/;return p0(r,a=>{let n=a.match(s);if(!n)return p0.skip;if(n[1])return"glibc";if(n[2])return"musl";throw new Error("Assertion failed: Expected the libc variant to have been detected")})??null}function sv(){return npe=npe??{os:(process.env.YARN_IS_TEST_ENV?process.env.YARN_OS_OVERRIDE:void 0)??process.platform,cpu:(process.env.YARN_IS_TEST_ENV?process.env.YARN_CPU_OVERRIDE:void 0)??process.arch,libc:(process.env.YARN_IS_TEST_ENV?process.env.YARN_LIBC_OVERRIDE:void 0)??bnt()}}function Pnt(t=sv()){return t.libc?`${t.os}-${t.cpu}-${t.libc}`:`${t.os}-${t.cpu}`}function uj(){let t=sv();return ipe=ipe??{os:[t.os],cpu:[t.cpu],libc:t.libc?[t.libc]:[]}}function Qnt(t){let e=xnt.exec(t);if(!e)return null;let r=e[2]&&e[2].indexOf("native")===0,s=e[2]&&e[2].indexOf("eval")===0,a=knt.exec(e[2]);return s&&a!=null&&(e[2]=a[1],e[3]=a[2],e[4]=a[3]),{file:r?null:e[2],methodName:e[1]||"",arguments:r?[e[2]]:[],line:e[3]?+e[3]:null,column:e[4]?+e[4]:null}}function Tnt(){let e=new Error().stack.split(` +`)[3];return Qnt(e)}function fj(){return typeof hT.default.availableParallelism<"u"?hT.default.availableParallelism():Math.max(1,hT.default.cpus().length)}var hT,vnt,rpe,Snt,Dnt,npe,ipe,xnt,knt,gT=Xe(()=>{Dt();hT=ut(Ie("os"));dT();Pc();vnt=Number(process.versions.node.split(".")[0]),rpe=new Map([["darwin","open"],["linux","xdg-open"],["win32","explorer.exe"]]).get(process.platform),Snt=typeof rpe<"u"?async t=>{try{return await Aj(rpe,[t],{cwd:J.cwd()}),!0}catch{return!1}}:void 0,Dnt="/usr/bin/ldd";xnt=/^\s*at (.*?) ?\(((?:file|https?|blob|chrome-extension|native|eval|webpack||\/|[a-z]:\\|\\\\).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i,knt=/\((\S*)(?::(\d+))(?::(\d+))\)/});function yj(t,e,r,s,a){let n=YB(r);if(s.isArray||s.type==="ANY"&&Array.isArray(n))return Array.isArray(n)?n.map((c,f)=>pj(t,`${e}[${f}]`,c,s,a)):String(n).split(/,/).map(c=>pj(t,e,c,s,a));if(Array.isArray(n))throw new Error(`Non-array configuration settings "${e}" cannot be an array`);return pj(t,e,r,s,a)}function pj(t,e,r,s,a){let n=YB(r);switch(s.type){case"ANY":return NQ(n);case"SHAPE":return Ont(t,e,r,s,a);case"MAP":return Lnt(t,e,r,s,a)}if(n===null&&!s.isNullable&&s.default!==null)throw new Error(`Non-nullable configuration settings "${e}" cannot be set to null`);if("values"in s&&s.values?.includes(n))return n;let f=(()=>{if(s.type==="BOOLEAN"&&typeof n!="string")return kB(n);if(typeof n!="string")throw new Error(`Expected configuration setting "${e}" to be a string, got ${typeof n}`);let p=Vk(n,{env:t.env});switch(s.type){case"ABSOLUTE_PATH":{let h=a,E=H8(r);return E&&E[0]!=="<"&&(h=J.dirname(E)),J.resolve(h,fe.toPortablePath(p))}case"LOCATOR_LOOSE":return Qp(p,!1);case"NUMBER":return parseInt(p);case"LOCATOR":return Qp(p);case"BOOLEAN":return kB(p);case"DURATION":return Jk(p,s.unit);default:return p}})();if("values"in s&&s.values&&!s.values.includes(f))throw new Error(`Invalid value, expected one of ${s.values.join(", ")}`);return f}function Ont(t,e,r,s,a){let n=YB(r);if(typeof n!="object"||Array.isArray(n))throw new nt(`Object configuration settings "${e}" must be an object`);let c=Ej(t,s,{ignoreArrays:!0});if(n===null)return c;for(let[f,p]of Object.entries(n)){let h=`${e}.${f}`;if(!s.properties[f])throw new nt(`Unrecognized configuration settings found: ${e}.${f} - run "yarn config" to see the list of settings supported in Yarn`);c.set(f,yj(t,h,p,s.properties[f],a))}return c}function Lnt(t,e,r,s,a){let n=YB(r),c=new Map;if(typeof n!="object"||Array.isArray(n))throw new nt(`Map configuration settings "${e}" must be an object`);if(n===null)return c;for(let[f,p]of Object.entries(n)){let h=s.normalizeKeys?s.normalizeKeys(f):f,E=`${e}['${h}']`,C=s.valueDefinition;c.set(h,yj(t,E,p,C,a))}return c}function Ej(t,e,{ignoreArrays:r=!1}={}){switch(e.type){case"SHAPE":{if(e.isArray&&!r)return[];let s=new Map;for(let[a,n]of Object.entries(e.properties))s.set(a,Ej(t,n));return s}case"MAP":return e.isArray&&!r?[]:new Map;case"ABSOLUTE_PATH":return e.default===null?null:t.projectCwd===null?Array.isArray(e.default)?e.default.map(s=>J.normalize(s)):J.isAbsolute(e.default)?J.normalize(e.default):e.isNullable?null:void 0:Array.isArray(e.default)?e.default.map(s=>J.resolve(t.projectCwd,s)):J.resolve(t.projectCwd,e.default);case"DURATION":return Jk(e.default,e.unit);default:return e.default}}function yT(t,e,r){if(e.type==="SECRET"&&typeof t=="string"&&r.hideSecrets)return Nnt;if(e.type==="ABSOLUTE_PATH"&&typeof t=="string"&&r.getNativePaths)return fe.fromPortablePath(t);if(e.isArray&&Array.isArray(t)){let s=[];for(let a of t)s.push(yT(a,e,r));return s}if(e.type==="MAP"&&t instanceof Map){if(t.size===0)return;let s=new Map;for(let[a,n]of t.entries()){let c=yT(n,e.valueDefinition,r);typeof c<"u"&&s.set(a,c)}return s}if(e.type==="SHAPE"&&t instanceof Map){if(t.size===0)return;let s=new Map;for(let[a,n]of t.entries()){let c=e.properties[a],f=yT(n,c,r);typeof f<"u"&&s.set(a,f)}return s}return t}function Mnt(){let t={};for(let[e,r]of Object.entries(process.env))e=e.toLowerCase(),e.startsWith(ET)&&(e=(0,ope.default)(e.slice(ET.length)),t[e]=r);return t}function gj(){let t=`${ET}rc_filename`;for(let[e,r]of Object.entries(process.env))if(e.toLowerCase()===t&&typeof r=="string")return r;return dj}async function spe(t){try{return await ce.readFilePromise(t)}catch{return Buffer.of()}}async function Unt(t,e){return Buffer.compare(...await Promise.all([spe(t),spe(e)]))===0}async function _nt(t,e){let[r,s]=await Promise.all([ce.statPromise(t),ce.statPromise(e)]);return r.dev===s.dev&&r.ino===s.ino}async function jnt({configuration:t,selfPath:e}){let r=t.get("yarnPath");return t.get("ignorePath")||r===null||r===e||await Hnt(r,e)?null:r}var ope,Lp,ape,lpe,cpe,hj,Rnt,ov,Fnt,Mp,ET,dj,Nnt,wI,upe,mj,IT,mT,Hnt,ze,av=Xe(()=>{Dt();wc();ope=ut(Sre()),Lp=ut(Fd());Yt();ape=ut(yne()),lpe=Ie("module"),cpe=ut(Ld()),hj=Ie("stream");nue();oI();R8();F8();N8();gue();O8();tm();Iue();LQ();xc();I0();pT();Pc();gT();Rp();Wo();Rnt=function(){if(!Lp.GITHUB_ACTIONS||!process.env.GITHUB_EVENT_PATH)return!1;let t=fe.toPortablePath(process.env.GITHUB_EVENT_PATH),e;try{e=ce.readJsonSync(t)}catch{return!1}return!(!("repository"in e)||!e.repository||(e.repository.private??!0))}(),ov=new Set(["@yarnpkg/plugin-constraints","@yarnpkg/plugin-exec","@yarnpkg/plugin-interactive-tools","@yarnpkg/plugin-stage","@yarnpkg/plugin-typescript","@yarnpkg/plugin-version","@yarnpkg/plugin-workspace-tools"]),Fnt=new Set(["isTestEnv","injectNpmUser","injectNpmPassword","injectNpm2FaToken","zipDataEpilogue","cacheCheckpointOverride","cacheVersionOverride","lockfileVersionOverride","osOverride","cpuOverride","libcOverride","binFolder","version","flags","profile","gpg","ignoreNode","wrapOutput","home","confDir","registry","ignoreCwd"]),Mp=/^(?!v)[a-z0-9._-]+$/i,ET="yarn_",dj=".yarnrc.yml",Nnt="********",wI=(C=>(C.ANY="ANY",C.BOOLEAN="BOOLEAN",C.ABSOLUTE_PATH="ABSOLUTE_PATH",C.LOCATOR="LOCATOR",C.LOCATOR_LOOSE="LOCATOR_LOOSE",C.NUMBER="NUMBER",C.STRING="STRING",C.DURATION="DURATION",C.SECRET="SECRET",C.SHAPE="SHAPE",C.MAP="MAP",C))(wI||{}),upe=ht,mj=(c=>(c.MILLISECONDS="ms",c.SECONDS="s",c.MINUTES="m",c.HOURS="h",c.DAYS="d",c.WEEKS="w",c))(mj||{}),IT=(r=>(r.JUNCTIONS="junctions",r.SYMLINKS="symlinks",r))(IT||{}),mT={lastUpdateCheck:{description:"Last timestamp we checked whether new Yarn versions were available",type:"STRING",default:null},yarnPath:{description:"Path to the local executable that must be used over the global one",type:"ABSOLUTE_PATH",default:null},ignorePath:{description:"If true, the local executable will be ignored when using the global one",type:"BOOLEAN",default:!1},globalFolder:{description:"Folder where all system-global files are stored",type:"ABSOLUTE_PATH",default:G8()},cacheFolder:{description:"Folder where the cache files must be written",type:"ABSOLUTE_PATH",default:"./.yarn/cache"},compressionLevel:{description:"Zip files compression level, from 0 to 9 or mixed (a variant of 9, which stores some files uncompressed, when compression doesn't yield good results)",type:"NUMBER",values:["mixed",0,1,2,3,4,5,6,7,8,9],default:0},virtualFolder:{description:"Folder where the virtual packages (cf doc) will be mapped on the disk (must be named __virtual__)",type:"ABSOLUTE_PATH",default:"./.yarn/__virtual__"},installStatePath:{description:"Path of the file where the install state will be persisted",type:"ABSOLUTE_PATH",default:"./.yarn/install-state.gz"},immutablePatterns:{description:"Array of glob patterns; files matching them won't be allowed to change during immutable installs",type:"STRING",default:[],isArray:!0},rcFilename:{description:"Name of the files where the configuration can be found",type:"STRING",default:gj()},enableGlobalCache:{description:"If true, the system-wide cache folder will be used regardless of `cache-folder`",type:"BOOLEAN",default:!0},cacheMigrationMode:{description:"Defines the conditions under which Yarn upgrades should cause the cache archives to be regenerated.",type:"STRING",values:["always","match-spec","required-only"],default:"always"},enableColors:{description:"If true, the CLI is allowed to use colors in its output",type:"BOOLEAN",default:Zk,defaultText:""},enableHyperlinks:{description:"If true, the CLI is allowed to use hyperlinks in its output",type:"BOOLEAN",default:X4,defaultText:""},enableInlineBuilds:{description:"If true, the CLI will print the build output on the command line",type:"BOOLEAN",default:Lp.isCI,defaultText:""},enableMessageNames:{description:"If true, the CLI will prefix most messages with codes suitable for search engines",type:"BOOLEAN",default:!0},enableProgressBars:{description:"If true, the CLI is allowed to show a progress bar for long-running events",type:"BOOLEAN",default:!Lp.isCI,defaultText:""},enableTimers:{description:"If true, the CLI is allowed to print the time spent executing commands",type:"BOOLEAN",default:!0},enableTips:{description:"If true, installs will print a helpful message every day of the week",type:"BOOLEAN",default:!Lp.isCI,defaultText:""},preferInteractive:{description:"If true, the CLI will automatically use the interactive mode when called from a TTY",type:"BOOLEAN",default:!1},preferTruncatedLines:{description:"If true, the CLI will truncate lines that would go beyond the size of the terminal",type:"BOOLEAN",default:!1},progressBarStyle:{description:"Which style of progress bar should be used (only when progress bars are enabled)",type:"STRING",default:void 0,defaultText:""},defaultLanguageName:{description:"Default language mode that should be used when a package doesn't offer any insight",type:"STRING",default:"node"},defaultProtocol:{description:"Default resolution protocol used when resolving pure semver and tag ranges",type:"STRING",default:"npm:"},enableTransparentWorkspaces:{description:"If false, Yarn won't automatically resolve workspace dependencies unless they use the `workspace:` protocol",type:"BOOLEAN",default:!0},supportedArchitectures:{description:"Architectures that Yarn will fetch and inject into the resolver",type:"SHAPE",properties:{os:{description:"Array of supported process.platform strings, or null to target them all",type:"STRING",isArray:!0,isNullable:!0,default:["current"]},cpu:{description:"Array of supported process.arch strings, or null to target them all",type:"STRING",isArray:!0,isNullable:!0,default:["current"]},libc:{description:"Array of supported libc libraries, or null to target them all",type:"STRING",isArray:!0,isNullable:!0,default:["current"]}}},enableMirror:{description:"If true, the downloaded packages will be retrieved and stored in both the local and global folders",type:"BOOLEAN",default:!0},enableNetwork:{description:"If false, Yarn will refuse to use the network if required to",type:"BOOLEAN",default:!0},enableOfflineMode:{description:"If true, Yarn will attempt to retrieve files and metadata from the global cache rather than the network",type:"BOOLEAN",default:!1},httpProxy:{description:"URL of the http proxy that must be used for outgoing http requests",type:"STRING",default:null},httpsProxy:{description:"URL of the http proxy that must be used for outgoing https requests",type:"STRING",default:null},unsafeHttpWhitelist:{description:"List of the hostnames for which http queries are allowed (glob patterns are supported)",type:"STRING",default:[],isArray:!0},httpTimeout:{description:"Timeout of each http request",type:"DURATION",unit:"ms",default:"1m"},httpRetry:{description:"Retry times on http failure",type:"NUMBER",default:3},networkConcurrency:{description:"Maximal number of concurrent requests",type:"NUMBER",default:50},taskPoolConcurrency:{description:"Maximal amount of concurrent heavy task processing",type:"NUMBER",default:fj()},taskPoolMode:{description:"Execution strategy for heavy tasks",type:"STRING",values:["async","workers"],default:"workers"},networkSettings:{description:"Network settings per hostname (glob patterns are supported)",type:"MAP",valueDefinition:{description:"",type:"SHAPE",properties:{httpsCaFilePath:{description:"Path to file containing one or multiple Certificate Authority signing certificates",type:"ABSOLUTE_PATH",default:null},enableNetwork:{description:"If false, the package manager will refuse to use the network if required to",type:"BOOLEAN",default:null},httpProxy:{description:"URL of the http proxy that must be used for outgoing http requests",type:"STRING",default:null},httpsProxy:{description:"URL of the http proxy that must be used for outgoing https requests",type:"STRING",default:null},httpsKeyFilePath:{description:"Path to file containing private key in PEM format",type:"ABSOLUTE_PATH",default:null},httpsCertFilePath:{description:"Path to file containing certificate chain in PEM format",type:"ABSOLUTE_PATH",default:null}}}},httpsCaFilePath:{description:"A path to a file containing one or multiple Certificate Authority signing certificates",type:"ABSOLUTE_PATH",default:null},httpsKeyFilePath:{description:"Path to file containing private key in PEM format",type:"ABSOLUTE_PATH",default:null},httpsCertFilePath:{description:"Path to file containing certificate chain in PEM format",type:"ABSOLUTE_PATH",default:null},enableStrictSsl:{description:"If false, SSL certificate errors will be ignored",type:"BOOLEAN",default:!0},logFilters:{description:"Overrides for log levels",type:"SHAPE",isArray:!0,concatenateValues:!0,properties:{code:{description:"Code of the messages covered by this override",type:"STRING",default:void 0},text:{description:"Code of the texts covered by this override",type:"STRING",default:void 0},pattern:{description:"Code of the patterns covered by this override",type:"STRING",default:void 0},level:{description:"Log level override, set to null to remove override",type:"STRING",values:Object.values(eQ),isNullable:!0,default:void 0}}},enableTelemetry:{description:"If true, telemetry will be periodically sent, following the rules in https://yarnpkg.com/advanced/telemetry",type:"BOOLEAN",default:!0},telemetryInterval:{description:"Minimal amount of time between two telemetry uploads",type:"DURATION",unit:"d",default:"7d"},telemetryUserId:{description:"If you desire to tell us which project you are, you can set this field. Completely optional and opt-in.",type:"STRING",default:null},enableHardenedMode:{description:"If true, automatically enable --check-resolutions --refresh-lockfile on installs",type:"BOOLEAN",default:Lp.isPR&&Rnt,defaultText:""},enableScripts:{description:"If true, packages are allowed to have install scripts by default",type:"BOOLEAN",default:!0},enableStrictSettings:{description:"If true, unknown settings will cause Yarn to abort",type:"BOOLEAN",default:!0},enableImmutableCache:{description:"If true, the cache is reputed immutable and actions that would modify it will throw",type:"BOOLEAN",default:!1},enableCacheClean:{description:"If false, disallows the `cache clean` command",type:"BOOLEAN",default:!0},checksumBehavior:{description:"Enumeration defining what to do when a checksum doesn't match expectations",type:"STRING",default:"throw"},injectEnvironmentFiles:{description:"List of all the environment files that Yarn should inject inside the process when it starts",type:"ABSOLUTE_PATH",default:[".env.yarn?"],isArray:!0},packageExtensions:{description:"Map of package corrections to apply on the dependency tree",type:"MAP",valueDefinition:{description:"The extension that will be applied to any package whose version matches the specified range",type:"SHAPE",properties:{dependencies:{description:"The set of dependencies that must be made available to the current package in order for it to work properly",type:"MAP",valueDefinition:{description:"A range",type:"STRING"}},peerDependencies:{description:"Inherited dependencies - the consumer of the package will be tasked to provide them",type:"MAP",valueDefinition:{description:"A semver range",type:"STRING"}},peerDependenciesMeta:{description:"Extra information related to the dependencies listed in the peerDependencies field",type:"MAP",valueDefinition:{description:"The peerDependency meta",type:"SHAPE",properties:{optional:{description:"If true, the selected peer dependency will be marked as optional by the package manager and the consumer omitting it won't be reported as an error",type:"BOOLEAN",default:!1}}}}}}}};Hnt=process.platform==="win32"?Unt:_nt;ze=class t{constructor(e){this.isCI=Lp.isCI;this.projectCwd=null;this.plugins=new Map;this.settings=new Map;this.values=new Map;this.sources=new Map;this.invalid=new Map;this.env={};this.limits=new Map;this.packageExtensions=null;this.startingCwd=e}static{this.deleteProperty=Symbol()}static{this.telemetry=null}static create(e,r,s){let a=new t(e);typeof r<"u"&&!(r instanceof Map)&&(a.projectCwd=r),a.importSettings(mT);let n=typeof s<"u"?s:r instanceof Map?r:new Map;for(let[c,f]of n)a.activatePlugin(c,f);return a}static async find(e,r,{strict:s=!0,usePathCheck:a=null,useRc:n=!0}={}){let c=Mnt();delete c.rcFilename;let f=new t(e),p=await t.findRcFiles(e),h=await t.findFolderRcFile(fI());h&&(p.find(me=>me.path===h.path)||p.unshift(h));let E=Eue(p.map(le=>[le.path,le.data])),C=vt.dot,S=new Set(Object.keys(mT)),P=({yarnPath:le,ignorePath:me,injectEnvironmentFiles:pe})=>({yarnPath:le,ignorePath:me,injectEnvironmentFiles:pe}),I=({yarnPath:le,ignorePath:me,injectEnvironmentFiles:pe,...Be})=>{let Ce={};for(let[g,we]of Object.entries(Be))S.has(g)&&(Ce[g]=we);return Ce},R=({yarnPath:le,ignorePath:me,...pe})=>{let Be={};for(let[Ce,g]of Object.entries(pe))S.has(Ce)||(Be[Ce]=g);return Be};if(f.importSettings(P(mT)),f.useWithSource("",P(c),e,{strict:!1}),E){let[le,me]=E;f.useWithSource(le,P(me),C,{strict:!1})}if(a){if(await jnt({configuration:f,selfPath:a})!==null)return f;f.useWithSource("",{ignorePath:!0},e,{strict:!1,overwrite:!0})}let N=await t.findProjectCwd(e);f.startingCwd=e,f.projectCwd=N;let U=Object.assign(Object.create(null),process.env);f.env=U;let W=await Promise.all(f.get("injectEnvironmentFiles").map(async le=>{let me=le.endsWith("?")?await ce.readFilePromise(le.slice(0,-1),"utf8").catch(()=>""):await ce.readFilePromise(le,"utf8");return(0,ape.parse)(me)}));for(let le of W)for(let[me,pe]of Object.entries(le))f.env[me]=Vk(pe,{env:U});if(f.importSettings(I(mT)),f.useWithSource("",I(c),e,{strict:s}),E){let[le,me]=E;f.useWithSource(le,I(me),C,{strict:s})}let ee=le=>"default"in le?le.default:le,ie=new Map([["@@core",rue]]);if(r!==null)for(let le of r.plugins.keys())ie.set(le,ee(r.modules.get(le)));for(let[le,me]of ie)f.activatePlugin(le,me);let ue=new Map([]);if(r!==null){let le=new Map;for(let[Be,Ce]of r.modules)le.set(Be,()=>Ce);let me=new Set,pe=async(Be,Ce)=>{let{factory:g,name:we}=Pp(Be);if(!g||me.has(we))return;let ye=new Map(le),Ae=Z=>{if((0,lpe.isBuiltin)(Z))return Pp(Z);if(ye.has(Z))return ye.get(Z)();throw new nt(`This plugin cannot access the package referenced via ${Z} which is neither a builtin, nor an exposed entry`)},se=await qE(async()=>ee(await g(Ae)),Z=>`${Z} (when initializing ${we}, defined in ${Ce})`);le.set(we,()=>se),me.add(we),ue.set(we,se)};if(c.plugins)for(let Be of c.plugins.split(";")){let Ce=J.resolve(e,fe.toPortablePath(Be));await pe(Ce,"")}for(let{path:Be,cwd:Ce,data:g}of p)if(n&&Array.isArray(g.plugins))for(let we of g.plugins){let ye=typeof we!="string"?we.path:we,Ae=we?.spec??"",se=we?.checksum??"";if(ov.has(Ae))continue;let Z=J.resolve(Ce,fe.toPortablePath(ye));if(!await ce.existsPromise(Z)){if(!Ae){let mt=Ht(f,J.basename(Z,".cjs"),ht.NAME),j=Ht(f,".gitignore",ht.NAME),rt=Ht(f,f.values.get("rcFilename"),ht.NAME),Fe=Ht(f,"https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored",ht.URL);throw new nt(`Missing source for the ${mt} plugin - please try to remove the plugin from ${rt} then reinstall it manually. This error usually occurs because ${j} is incorrect, check ${Fe} to make sure your plugin folder isn't gitignored.`)}if(!Ae.match(/^https?:/)){let mt=Ht(f,J.basename(Z,".cjs"),ht.NAME),j=Ht(f,f.values.get("rcFilename"),ht.NAME);throw new nt(`Failed to recognize the source for the ${mt} plugin - please try to delete the plugin from ${j} then reinstall it manually.`)}let De=await lj(Ae,{configuration:f}),Re=us(De);if(se&&se!==Re){let mt=Ht(f,J.basename(Z,".cjs"),ht.NAME),j=Ht(f,f.values.get("rcFilename"),ht.NAME),rt=Ht(f,`yarn plugin import ${Ae}`,ht.CODE);throw new nt(`Failed to fetch the ${mt} plugin from its remote location: its checksum seems to have changed. If this is expected, please remove the plugin from ${j} then run ${rt} to reimport it.`)}await ce.mkdirPromise(J.dirname(Z),{recursive:!0}),await ce.writeFilePromise(Z,De)}await pe(Z,Be)}}for(let[le,me]of ue)f.activatePlugin(le,me);if(f.useWithSource("",R(c),e,{strict:s}),E){let[le,me]=E;f.useWithSource(le,R(me),C,{strict:s})}return f.get("enableGlobalCache")&&(f.values.set("cacheFolder",`${f.get("globalFolder")}/cache`),f.sources.set("cacheFolder","")),f}static async findRcFiles(e){let r=gj(),s=[],a=e,n=null;for(;a!==n;){n=a;let c=J.join(n,r);if(ce.existsSync(c)){let f,p;try{p=await ce.readFilePromise(c,"utf8"),f=ls(p)}catch{let h="";throw p?.match(/^\s+(?!-)[^:]+\s+\S+/m)&&(h=" (in particular, make sure you list the colons after each key name)"),new nt(`Parse error when loading ${c}; please check it's proper Yaml${h}`)}s.unshift({path:c,cwd:n,data:f})}a=J.dirname(n)}return s}static async findFolderRcFile(e){let r=J.join(e,Er.rc),s;try{s=await ce.readFilePromise(r,"utf8")}catch(n){if(n.code==="ENOENT")return null;throw n}let a=ls(s);return{path:r,cwd:e,data:a}}static async findProjectCwd(e){let r=null,s=e,a=null;for(;s!==a;){if(a=s,ce.existsSync(J.join(a,Er.lockfile)))return a;ce.existsSync(J.join(a,Er.manifest))&&(r=a),s=J.dirname(a)}return r}static async updateConfiguration(e,r,s={}){let a=gj(),n=J.join(e,a),c=ce.existsSync(n)?ls(await ce.readFilePromise(n,"utf8")):{},f=!1,p;if(typeof r=="function"){try{p=r(c)}catch{p=r({})}if(p===c)return!1}else{p=c;for(let h of Object.keys(r)){let E=c[h],C=r[h],S;if(typeof C=="function")try{S=C(E)}catch{S=C(void 0)}else S=C;E!==S&&(S===t.deleteProperty?delete p[h]:p[h]=S,f=!0)}if(!f)return!1}return await ce.changeFilePromise(n,nl(p),{automaticNewlines:!0}),!0}static async addPlugin(e,r){r.length!==0&&await t.updateConfiguration(e,s=>{let a=s.plugins??[];if(a.length===0)return{...s,plugins:r};let n=[],c=[...r];for(let f of a){let p=typeof f!="string"?f.path:f,h=c.find(E=>E.path===p);h?(n.push(h),c=c.filter(E=>E!==h)):n.push(f)}return n.push(...c),{...s,plugins:n}})}static async updateHomeConfiguration(e){let r=fI();return await t.updateConfiguration(r,e)}activatePlugin(e,r){this.plugins.set(e,r),typeof r.configuration<"u"&&this.importSettings(r.configuration)}importSettings(e){for(let[r,s]of Object.entries(e))if(s!=null){if(this.settings.has(r))throw new Error(`Cannot redefine settings "${r}"`);this.settings.set(r,s),this.values.set(r,Ej(this,s))}}useWithSource(e,r,s,a){try{this.use(e,r,s,a)}catch(n){throw n.message+=` (in ${Ht(this,e,ht.PATH)})`,n}}use(e,r,s,{strict:a=!0,overwrite:n=!1}={}){a=a&&this.get("enableStrictSettings");for(let c of["enableStrictSettings",...Object.keys(r)]){let f=r[c],p=H8(f);if(p&&(e=p),typeof f>"u"||c==="plugins"||e===""&&Fnt.has(c))continue;if(c==="rcFilename")throw new nt(`The rcFilename settings can only be set via ${`${ET}RC_FILENAME`.toUpperCase()}, not via a rc file`);let h=this.settings.get(c);if(!h){let C=fI(),S=e[0]!=="<"?J.dirname(e):null;if(a&&!(S!==null?C===S:!1))throw new nt(`Unrecognized or legacy configuration settings found: ${c} - run "yarn config" to see the list of settings supported in Yarn`);this.invalid.set(c,e);continue}if(this.sources.has(c)&&!(n||h.type==="MAP"||h.isArray&&h.concatenateValues))continue;let E;try{E=yj(this,c,f,h,s)}catch(C){throw C.message+=` in ${Ht(this,e,ht.PATH)}`,C}if(c==="enableStrictSettings"&&e!==""){a=E;continue}if(h.type==="MAP"){let C=this.values.get(c);this.values.set(c,new Map(n?[...C,...E]:[...E,...C])),this.sources.set(c,`${this.sources.get(c)}, ${e}`)}else if(h.isArray&&h.concatenateValues){let C=this.values.get(c);this.values.set(c,n?[...C,...E]:[...E,...C]),this.sources.set(c,`${this.sources.get(c)}, ${e}`)}else this.values.set(c,E),this.sources.set(c,e)}}get(e){if(!this.values.has(e))throw new Error(`Invalid configuration key "${e}"`);return this.values.get(e)}getSpecial(e,{hideSecrets:r=!1,getNativePaths:s=!1}){let a=this.get(e),n=this.settings.get(e);if(typeof n>"u")throw new nt(`Couldn't find a configuration settings named "${e}"`);return yT(a,n,{hideSecrets:r,getNativePaths:s})}getSubprocessStreams(e,{header:r,prefix:s,report:a}){let n,c,f=ce.createWriteStream(e);if(this.get("enableInlineBuilds")){let p=a.createStreamReporter(`${s} ${Ht(this,"STDOUT","green")}`),h=a.createStreamReporter(`${s} ${Ht(this,"STDERR","red")}`);n=new hj.PassThrough,n.pipe(p),n.pipe(f),c=new hj.PassThrough,c.pipe(h),c.pipe(f)}else n=f,c=f,typeof r<"u"&&n.write(`${r} +`);return{stdout:n,stderr:c}}makeResolver(){let e=[];for(let r of this.plugins.values())for(let s of r.resolvers||[])e.push(new s);return new rm([new FQ,new Ei,...e])}makeFetcher(){let e=[];for(let r of this.plugins.values())for(let s of r.fetchers||[])e.push(new s);return new aI([new lI,new cI,...e])}getLinkers(){let e=[];for(let r of this.plugins.values())for(let s of r.linkers||[])e.push(new s);return e}getSupportedArchitectures(){let e=sv(),r=this.get("supportedArchitectures"),s=r.get("os");s!==null&&(s=s.map(c=>c==="current"?e.os:c));let a=r.get("cpu");a!==null&&(a=a.map(c=>c==="current"?e.cpu:c));let n=r.get("libc");return n!==null&&(n=Wl(n,c=>c==="current"?e.libc??Wl.skip:c)),{os:s,cpu:a,libc:n}}isInteractive({interactive:e,stdout:r}){return r.isTTY?e??this.get("preferInteractive"):!1}async getPackageExtensions(){if(this.packageExtensions!==null)return this.packageExtensions;this.packageExtensions=new Map;let e=this.packageExtensions,r=(s,a,{userProvided:n=!1}={})=>{if(!cl(s.range))throw new Error("Only semver ranges are allowed as keys for the packageExtensions setting");let c=new Ut;c.load(a,{yamlCompatibilityMode:!0});let f=xB(e,s.identHash),p=[];f.push([s.range,p]);let h={status:"inactive",userProvided:n,parentDescriptor:s};for(let E of c.dependencies.values())p.push({...h,type:"Dependency",descriptor:E});for(let E of c.peerDependencies.values())p.push({...h,type:"PeerDependency",descriptor:E});for(let[E,C]of c.peerDependenciesMeta)for(let[S,P]of Object.entries(C))p.push({...h,type:"PeerDependencyMeta",selector:E,key:S,value:P})};await this.triggerHook(s=>s.registerPackageExtensions,this,r);for(let[s,a]of this.get("packageExtensions"))r(C0(s,!0),Yk(a),{userProvided:!0});return e}normalizeLocator(e){return cl(e.reference)?Ws(e,`${this.get("defaultProtocol")}${e.reference}`):Mp.test(e.reference)?Ws(e,`${this.get("defaultProtocol")}${e.reference}`):e}normalizeDependency(e){return cl(e.range)?On(e,`${this.get("defaultProtocol")}${e.range}`):Mp.test(e.range)?On(e,`${this.get("defaultProtocol")}${e.range}`):e}normalizeDependencyMap(e){return new Map([...e].map(([r,s])=>[r,this.normalizeDependency(s)]))}normalizePackage(e,{packageExtensions:r}){let s=LB(e),a=r.get(e.identHash);if(typeof a<"u"){let c=e.version;if(c!==null){for(let[f,p]of a)if(Zf(c,f))for(let h of p)switch(h.status==="inactive"&&(h.status="redundant"),h.type){case"Dependency":typeof s.dependencies.get(h.descriptor.identHash)>"u"&&(h.status="active",s.dependencies.set(h.descriptor.identHash,this.normalizeDependency(h.descriptor)));break;case"PeerDependency":typeof s.peerDependencies.get(h.descriptor.identHash)>"u"&&(h.status="active",s.peerDependencies.set(h.descriptor.identHash,h.descriptor));break;case"PeerDependencyMeta":{let E=s.peerDependenciesMeta.get(h.selector);(typeof E>"u"||!Object.hasOwn(E,h.key)||E[h.key]!==h.value)&&(h.status="active",Yl(s.peerDependenciesMeta,h.selector,()=>({}))[h.key]=h.value)}break;default:G4(h)}}}let n=c=>c.scope?`${c.scope}__${c.name}`:`${c.name}`;for(let c of s.peerDependenciesMeta.keys()){let f=Sa(c);s.peerDependencies.has(f.identHash)||s.peerDependencies.set(f.identHash,On(f,"*"))}for(let c of s.peerDependencies.values()){if(c.scope==="types")continue;let f=n(c),p=Da("types",f),h=un(p);s.peerDependencies.has(p.identHash)||s.peerDependenciesMeta.has(h)||s.dependencies.has(p.identHash)||(s.peerDependencies.set(p.identHash,On(p,"*")),s.peerDependenciesMeta.set(h,{optional:!0}))}return s.dependencies=new Map(qs(s.dependencies,([,c])=>al(c))),s.peerDependencies=new Map(qs(s.peerDependencies,([,c])=>al(c))),s}getLimit(e){return Yl(this.limits,e,()=>(0,cpe.default)(this.get(e)))}async triggerHook(e,...r){for(let s of this.plugins.values()){let a=s.hooks;if(!a)continue;let n=e(a);n&&await n(...r)}}async triggerMultipleHooks(e,r){for(let s of r)await this.triggerHook(e,...s)}async reduceHook(e,r,...s){let a=r;for(let n of this.plugins.values()){let c=n.hooks;if(!c)continue;let f=e(c);f&&(a=await f(a,...s))}return a}async firstHook(e,...r){for(let s of this.plugins.values()){let a=s.hooks;if(!a)continue;let n=e(a);if(!n)continue;let c=await n(...r);if(typeof c<"u")return c}return null}}});var qr={};Vt(qr,{EndStrategy:()=>Bj,ExecError:()=>CT,PipeError:()=>lv,execvp:()=>Aj,pipevp:()=>Wu});function om(t){return t!==null&&typeof t.fd=="number"}function Ij(){}function Cj(){for(let t of am)t.kill()}async function Wu(t,e,{cwd:r,env:s=process.env,strict:a=!1,stdin:n=null,stdout:c,stderr:f,end:p=2}){let h=["pipe","pipe","pipe"];n===null?h[0]="ignore":om(n)&&(h[0]=n),om(c)&&(h[1]=c),om(f)&&(h[2]=f);let E=(0,wj.default)(t,e,{cwd:fe.fromPortablePath(r),env:{...s,PWD:fe.fromPortablePath(r)},stdio:h});am.add(E),am.size===1&&(process.on("SIGINT",Ij),process.on("SIGTERM",Cj)),!om(n)&&n!==null&&n.pipe(E.stdin),om(c)||E.stdout.pipe(c,{end:!1}),om(f)||E.stderr.pipe(f,{end:!1});let C=()=>{for(let S of new Set([c,f]))om(S)||S.end()};return new Promise((S,P)=>{E.on("error",I=>{am.delete(E),am.size===0&&(process.off("SIGINT",Ij),process.off("SIGTERM",Cj)),(p===2||p===1)&&C(),P(I)}),E.on("close",(I,R)=>{am.delete(E),am.size===0&&(process.off("SIGINT",Ij),process.off("SIGTERM",Cj)),(p===2||p===1&&I!==0)&&C(),I===0||!a?S({code:vj(I,R)}):P(new lv({fileName:t,code:I,signal:R}))})})}async function Aj(t,e,{cwd:r,env:s=process.env,encoding:a="utf8",strict:n=!1}){let c=["ignore","pipe","pipe"],f=[],p=[],h=fe.fromPortablePath(r);typeof s.PWD<"u"&&(s={...s,PWD:h});let E=(0,wj.default)(t,e,{cwd:h,env:s,stdio:c});return E.stdout.on("data",C=>{f.push(C)}),E.stderr.on("data",C=>{p.push(C)}),await new Promise((C,S)=>{E.on("error",P=>{let I=ze.create(r),R=Ht(I,t,ht.PATH);S(new jt(1,`Process ${R} failed to spawn`,N=>{N.reportError(1,` ${Kf(I,{label:"Thrown Error",value:_u(ht.NO_HINT,P.message)})}`)}))}),E.on("close",(P,I)=>{let R=a==="buffer"?Buffer.concat(f):Buffer.concat(f).toString(a),N=a==="buffer"?Buffer.concat(p):Buffer.concat(p).toString(a);P===0||!n?C({code:vj(P,I),stdout:R,stderr:N}):S(new CT({fileName:t,code:P,signal:I,stdout:R,stderr:N}))})})}function vj(t,e){let r=Gnt.get(e);return typeof r<"u"?128+r:t??1}function qnt(t,e,{configuration:r,report:s}){s.reportError(1,` ${Kf(r,t!==null?{label:"Exit Code",value:_u(ht.NUMBER,t)}:{label:"Exit Signal",value:_u(ht.CODE,e)})}`)}var wj,Bj,lv,CT,am,Gnt,dT=Xe(()=>{Dt();wj=ut(_U());av();Tc();xc();Bj=(s=>(s[s.Never=0]="Never",s[s.ErrorCode=1]="ErrorCode",s[s.Always=2]="Always",s))(Bj||{}),lv=class extends jt{constructor({fileName:e,code:r,signal:s}){let a=ze.create(J.cwd()),n=Ht(a,e,ht.PATH);super(1,`Child ${n} reported an error`,c=>{qnt(r,s,{configuration:a,report:c})}),this.code=vj(r,s)}},CT=class extends lv{constructor({fileName:e,code:r,signal:s,stdout:a,stderr:n}){super({fileName:e,code:r,signal:s}),this.stdout=a,this.stderr=n}};am=new Set;Gnt=new Map([["SIGINT",2],["SIGQUIT",3],["SIGKILL",9],["SIGTERM",15]])});function Ape(t){fpe=t}function cv(){return typeof Sj>"u"&&(Sj=fpe()),Sj}var Sj,fpe,Dj=Xe(()=>{fpe=()=>{throw new Error("Assertion failed: No libzip instance is available, and no factory was configured")}});var ppe=_((wT,Pj)=>{var Wnt=Object.assign({},Ie("fs")),bj=function(){var t=typeof document<"u"&&document.currentScript?document.currentScript.src:void 0;return typeof __filename<"u"&&(t=t||__filename),function(e){e=e||{};var r=typeof e<"u"?e:{},s,a;r.ready=new Promise(function(Ke,st){s=Ke,a=st});var n={},c;for(c in r)r.hasOwnProperty(c)&&(n[c]=r[c]);var f=[],p="./this.program",h=function(Ke,st){throw st},E=!1,C=!0,S="";function P(Ke){return r.locateFile?r.locateFile(Ke,S):S+Ke}var I,R,N,U;C&&(E?S=Ie("path").dirname(S)+"/":S=__dirname+"/",I=function(st,St){var lr=Me(st);return lr?St?lr:lr.toString():(N||(N=Wnt),U||(U=Ie("path")),st=U.normalize(st),N.readFileSync(st,St?null:"utf8"))},R=function(st){var St=I(st,!0);return St.buffer||(St=new Uint8Array(St)),we(St.buffer),St},process.argv.length>1&&(p=process.argv[1].replace(/\\/g,"/")),f=process.argv.slice(2),h=function(Ke){process.exit(Ke)},r.inspect=function(){return"[Emscripten Module object]"});var W=r.print||console.log.bind(console),ee=r.printErr||console.warn.bind(console);for(c in n)n.hasOwnProperty(c)&&(r[c]=n[c]);n=null,r.arguments&&(f=r.arguments),r.thisProgram&&(p=r.thisProgram),r.quit&&(h=r.quit);var ie=0,ue=function(Ke){ie=Ke},le;r.wasmBinary&&(le=r.wasmBinary);var me=r.noExitRuntime||!0;typeof WebAssembly!="object"&&rs("no native wasm support detected");function pe(Ke,st,St){switch(st=st||"i8",st.charAt(st.length-1)==="*"&&(st="i32"),st){case"i1":return Ve[Ke>>0];case"i8":return Ve[Ke>>0];case"i16":return mh((Ke>>1)*2);case"i32":return to((Ke>>2)*4);case"i64":return to((Ke>>2)*4);case"float":return Af((Ke>>2)*4);case"double":return dh((Ke>>3)*8);default:rs("invalid type for getValue: "+st)}return null}var Be,Ce=!1,g;function we(Ke,st){Ke||rs("Assertion failed: "+st)}function ye(Ke){var st=r["_"+Ke];return we(st,"Cannot call unknown function "+Ke+", make sure it is exported"),st}function Ae(Ke,st,St,lr,te){var Ee={string:function(qi){var Tn=0;if(qi!=null&&qi!==0){var Ga=(qi.length<<2)+1;Tn=wi(Ga),mt(qi,Tn,Ga)}return Tn},array:function(qi){var Tn=wi(qi.length);return Fe(qi,Tn),Tn}};function Oe(qi){return st==="string"?De(qi):st==="boolean"?!!qi:qi}var dt=ye(Ke),Et=[],bt=0;if(lr)for(var tr=0;tr=St)&&ke[lr];)++lr;return Z.decode(ke.subarray(Ke,lr))}function Re(Ke,st,St,lr){if(!(lr>0))return 0;for(var te=St,Ee=St+lr-1,Oe=0;Oe=55296&&dt<=57343){var Et=Ke.charCodeAt(++Oe);dt=65536+((dt&1023)<<10)|Et&1023}if(dt<=127){if(St>=Ee)break;st[St++]=dt}else if(dt<=2047){if(St+1>=Ee)break;st[St++]=192|dt>>6,st[St++]=128|dt&63}else if(dt<=65535){if(St+2>=Ee)break;st[St++]=224|dt>>12,st[St++]=128|dt>>6&63,st[St++]=128|dt&63}else{if(St+3>=Ee)break;st[St++]=240|dt>>18,st[St++]=128|dt>>12&63,st[St++]=128|dt>>6&63,st[St++]=128|dt&63}}return st[St]=0,St-te}function mt(Ke,st,St){return Re(Ke,ke,st,St)}function j(Ke){for(var st=0,St=0;St=55296&&lr<=57343&&(lr=65536+((lr&1023)<<10)|Ke.charCodeAt(++St)&1023),lr<=127?++st:lr<=2047?st+=2:lr<=65535?st+=3:st+=4}return st}function rt(Ke){var st=j(Ke)+1,St=La(st);return St&&Re(Ke,Ve,St,st),St}function Fe(Ke,st){Ve.set(Ke,st)}function Ne(Ke,st){return Ke%st>0&&(Ke+=st-Ke%st),Ke}var Pe,Ve,ke,it,Ue,x,w,b,y,F;function z(Ke){Pe=Ke,r.HEAP_DATA_VIEW=F=new DataView(Ke),r.HEAP8=Ve=new Int8Array(Ke),r.HEAP16=it=new Int16Array(Ke),r.HEAP32=x=new Int32Array(Ke),r.HEAPU8=ke=new Uint8Array(Ke),r.HEAPU16=Ue=new Uint16Array(Ke),r.HEAPU32=w=new Uint32Array(Ke),r.HEAPF32=b=new Float32Array(Ke),r.HEAPF64=y=new Float64Array(Ke)}var X=r.INITIAL_MEMORY||16777216,$,oe=[],xe=[],Te=[],lt=!1;function Ct(){if(r.preRun)for(typeof r.preRun=="function"&&(r.preRun=[r.preRun]);r.preRun.length;)Pt(r.preRun.shift());Ts(oe)}function qt(){lt=!0,Ts(xe)}function ir(){if(r.postRun)for(typeof r.postRun=="function"&&(r.postRun=[r.postRun]);r.postRun.length;)Pr(r.postRun.shift());Ts(Te)}function Pt(Ke){oe.unshift(Ke)}function gn(Ke){xe.unshift(Ke)}function Pr(Ke){Te.unshift(Ke)}var Ir=0,Or=null,on=null;function ai(Ke){Ir++,r.monitorRunDependencies&&r.monitorRunDependencies(Ir)}function Io(Ke){if(Ir--,r.monitorRunDependencies&&r.monitorRunDependencies(Ir),Ir==0&&(Or!==null&&(clearInterval(Or),Or=null),on)){var st=on;on=null,st()}}r.preloadedImages={},r.preloadedAudios={};function rs(Ke){r.onAbort&&r.onAbort(Ke),Ke+="",ee(Ke),Ce=!0,g=1,Ke="abort("+Ke+"). Build with -s ASSERTIONS=1 for more info.";var st=new WebAssembly.RuntimeError(Ke);throw a(st),st}var $s="data:application/octet-stream;base64,";function Co(Ke){return Ke.startsWith($s)}var ji="data:application/octet-stream;base64,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QCAAKAJIIgEgASADaiADEAcaAkAgAyAAKAJsIgFNBEAgACABIANrNgJsDAELIABCADcCbAsgACAAKAJoIANrIgE2AmggACAAKAJYIANrNgJYIAEgACgChC5JBEAgACABNgKELgsgAEH8gAEoAgARAwAgAiADaiECCwJAIAAoAgAiASgCBCIERQ0AIAAoAjwhBSAAIAIgBCACIARJGyICBH8gACgCSCAAKAJoaiAFaiEFIAEgBCACazYCBAJAAkACQAJAIAEoAhwiBCgCFEEBaw4CAQACCyAEQaABaiAFIAEoAgAgAkHcgAEoAgARCAAMAgsgASABKAIwIAUgASgCACACQcSAASgCABEEADYCMAwBCyAFIAEoAgAgAhAHGgsgASABKAIAIAJqNgIAIAEgASgCCCACajYCCCAAKAI8BSAFCyACaiICNgI8AkAgACgChC4iASACakEDSQ0AIAAoAmggAWshAQJAIAAoAnRBgQhPBEAgACAAIAAoAkggAWoiAi0AACACLQABIAAoAnwRAAA2AlQMAQsgAUUNACAAIAFBAWsgACgChAERAgAaCyAAKAKELiAAKAI8IgJBAUZrIgRFDQAgACABIAQgACgCgAERBQAgACAAKAKELiAEazYChC4gACgCPCECCyACQYUCSw0AIAAoAgAoAgRFDQAgACgCMCEBDAELCwJAIAAoAkQiAiAAKAJAIgNNDQAgAAJ/IAAoAjwgACgCaGoiASADSwRAIAAoAkggAWpBACACIAFrIgNBggIgA0GCAkkbIgMQGSABIANqDAELIAFBggJqIgEgA00NASAAKAJIIANqQQAgAiADayICIAEgA2siAyACIANJGyIDEBkgACgCQCADags2AkALC50CAQF/AkAgAAJ/IAAoAqAuIgFBwABGBEAgACgCBCAAKAIQaiAAKQOYLjcAACAAQgA3A5guIAAgACgCEEEIajYCEEEADAELIAFBIE4EQCAAKAIEIAAoAhBqIAApA5guPgAAIAAgAEGcLmo1AgA3A5guIAAgACgCEEEEajYCECAAIAAoAqAuQSBrIgE2AqAuCyABQRBOBEAgACgCBCAAKAIQaiAAKQOYLj0AACAAIAAoAhBBAmo2AhAgACAAKQOYLkIQiDcDmC4gACAAKAKgLkEQayIBNgKgLgsgAUEISA0BIAAgACgCECIBQQFqNgIQ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KAJUIgEEfyABQQAgARAiEBkgACgCVAVBAAsQBiAAQQA2AlQLC9wMAgl/AX4jAEFAaiIGJAACQAJAAkACQAJAIAEoAjBBABAjIgVBAkZBACABKAI4QQAQIyIEQQFGGw0AIAVBAUZBACAEQQJGGw0AIAVBAkciAw0BIARBAkcNAQsgASABLwEMQYAQcjsBDEEAIQMMAQsgASABLwEMQf/vA3E7AQxBACEFIANFBEBB9eABIAEoAjAgAEEIahBpIgVFDQILIAJBgAJxBEAgBSEDDAELIARBAkcEQCAFIQMMAQtB9cYBIAEoAjggAEEIahBpIgNFBEAgBRAcDAILIAMgBTYCAAsgASABLwEMQf7/A3EgAS8BUiIFQQBHcjsBDAJAAkACQAJAAn8CQAJAIAEpAyhC/v///w9WDQAgASkDIEL+////D1YNACACQYAEcUUNASABKQNIQv////8PVA0BCyAFQYECa0H//wNxQQNJIQdBAQwBCyAFQYECa0H//wNxIQQgAkGACnFBgApHDQEgBEEDSSEHQQALIQkgBkIcEBciBEUEQCAAQQhqIgAEQCAAQQA2AgQgAEEONgIACyADEBwMBQsgAkGACHEhBQJAAkAgAkGAAnEEQAJAIAUNACABKQMgQv////8PVg0AIAEpAyhCgICAgBBUDQMLIAQgASkDKBAYIAEpAyAhDAwBCwJAAkACQCAFDQAgASkDIEL/////D1YNACABKQMoIgxC/////w9WDQEgASkDSEKAgICAEFQNBAsgASkDKCIMQv////8PVA0BCyAEIAwQGAsgASkDICIMQv////8PWgRAIAQgDBAYCyABKQNIIgxC/////w9UDQELIAQgDBAYCyAELQAARQRAIABBCGoiAARAIABBADYCBCAAQRQ2AgALIAQQCCADEBwMBQtBASEKQQEgBC0AAAR+IAQpAxAFQgALp0H//wNxIAYQRyEFIAQQCCAFIAM2AgAgBw0BDAILIAMhBSAEQQJLDQELIAZCBxAXIgRFBEAgAEEIaiIABEAgAEEANgIEIABBDjYCAAsgBRAcDAMLIARBAhANIARBhxJBAhAsIAQgAS0AUhBwIAQgAS8BEBANIAQtAABFBEAgAEEIaiIABEAgAEEANgIEIABBFDYCAAsgBBAIDAILQYGyAkEHIAYQRyEDIAQQCCADIAU2AgBBASEL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NgIEIABB7A42AhggGiEdDAMLIARB/wFxIgJBwABxRQRAIAggDSADLwECQQJ0aiAdp0F/IAJ0QX9zcUECdGoiAy0AASICayEIIB0gAq2IIR0gAy0AACIERQ0HDAELCyAEQSBxBEAgB0G//gA2AgQgASECDAgLIAdB0f4ANgIEIABB0A42AhggASECDAcLIB1BfyAGdEF/c62DIBt8IhunIQUgCCAEQQ9xIgNrIQggGiAErUIPg4ghHSABIBdrIgYgAjMBAiAaQX8gA3RBf3Otg3ynIgRPDQIgBCAGayIGIBlNDQEgBygCjEdFDQEgB0HR/gA2AgQgAEG5DDYCGAsgASECIAshBQwFCwJAIA5FBEAgDCARIAZraiEDDAELIAYgDk0EQCAMIA4gBmtqIQMMAQsgDCARIAYgDmsiBmtqIQMgBSAGTQ0AIAUgBmshBQJAAkAgASADTSABIA8gAWusIhogBq0iGyAaIBtUGyIapyIGaiICIANLcQ0AIAMgBmogAUsgASADT3ENACABIAMgBhAHGiACIQEMAQsgASADIAMgAWsiASABQR91IgFqIAFzIgIQByACaiEBIBogAq0iHn0iHFANACACIANqIQIDQAJAIBwgHiAcIB5UGyIbQiBUBEAgGyEaDAELIBsiGkIgfSIgQgWIQgF8QgODIh9QRQRAA0AgASACKQAANwAAIAEgAikAGDcAGCABIAIpABA3ABAgASACKQAINwAIIBpCIH0hGiACQSBqIQIgAUEgaiEBIB9CAX0iH0IAUg0ACwsgIELgAFQNAANAIAEgAikAADcAACABIAIpABg3ABggASACKQAQNwAQIAEgAikACDcACCABIAIpADg3ADggASACKQAwNwAwIAEgAikAKDcAKCABIAIpACA3ACAgASACKQBYNwBYIAEgAikAUDcAUCABIAIpAEg3AEggASACKQBANwBAIAEgAikAYDcAYCABIAIpAGg3AGggASACKQBwNwBwIAEgAikAeDcAeCACQYABaiECIAFBgAFqIQEgGkKAAX0iGkIfVg0ACwsgGkIQWgRAIAEgAikAADcAACABIAIpAAg3AAggGkIQfSEaIAJBEGohAiABQRBqIQELIBpCCFoEQCABIAIpAAA3AAAgGkIIfSEaIAJBCGohAiABQQhqIQELIBpCBFoEQCABIAIoAAA2AAAgGkIEfSEaIAJBBGohAiABQQRqIQELIBpCAloEQCABIAIvAAA7AAAgGkICfSEaIAJBAmohAiABQQJqIQELIBwgG30hHCAaUEUEQCABIAItAAA6AAAgAkEBaiECIAFBAWohAQsgHEIAUg0ACwsgDiEGIAwhAwsgBSAGSwRAAkACQCABIANNIAEgDyABa6wiGiAGrSIbIBogG1QbIhqnIglqIgIgA0txDQAgAyAJaiABSyABIANPcQ0AIAEgAyAJEAcaDAELIAEgAyADIAFrIgEgAUEfdSIBaiABcyIBEAcgAWohAiAaIAGtIh59IhxQDQAgASADaiEBA0ACQCAcIB4gHCAeVBsiG0IgVARAIBshGgwBCyAbIhpCIH0iIEIFiEIBfEIDgyIfUEUEQANAIAIgASkAADcAACACIAEpABg3ABggAiABKQAQNwAQIAIgASkACDcACCAaQiB9IRogAUEgaiEBIAJBIGohAiAfQgF9Ih9CAFINAAsLICBC4ABUDQADQCACIAEpAAA3AAAgAiABKQAYNwAYIAIgASkAEDcAECACIAEpAAg3AAggAiABKQA4NwA4IAIgASkAMDcAMCACIAEpACg3ACggAiABKQAgNwAgIAIgASkAWDcAWCACIAEpAFA3AFAgAiABKQBINwBIIAIgASkAQDcAQCACIAEpAGA3AGAgAiABKQBoNwBoIAIgASkAcDcAcCACIAEpAHg3AHggAUGAAWohASACQYABaiECIBpCgAF9IhpCH1YNAAsLIBpCEFoEQCACIAEpAAA3AAAgAiABKQAINwAIIBpCEH0hGiACQRBqIQIgAUEQaiEBCyAaQghaBEAgAiABKQAANwAAIBpCCH0hGiACQQhqIQIgAUEIaiEBCyAaQgRaBEAgAiABKAAANgAAIBpCBH0hGiACQQRqIQIgAUEEaiEBCyAaQgJaBEAgAiABLwAAOwAAIBpCAn0hGiACQQJqIQIgAUECaiEBCyAcIBt9IRwgGlBFBEAgAiABLQAAOgAAIAJBAWohAiABQQFqIQELIBxCAFINAAsLIAUgBmshAUEAIARrIQUCQCAEQQdLBEAgBCEDDAELIAEgBE0EQCAEIQMMAQsgAiAEayEFA0ACQCACIAUpAAA3AAAgBEEBdCEDIAEgBGshASACIARqIQIgBEEDSw0AIAMhBCABIANLDQELC0EAIANrIQULIAIgBWohBAJAIAUgDyACa6wiGiABrSIbIBogG1QbIhqnIgFIIAVBf0pxDQAgBUEBSCABIARqIAJLcQ0AIAIgBCABEAcgAWohAgwDCyACIAQgAyADQR91IgFqIAFzIgEQByABaiECIBogAa0iHn0iHFANAiABIARqIQEDQAJAIBwgHiAcIB5UGyIbQiBUBEAgGyEaDAELIBsiGkIgfSIgQgWIQgF8QgODIh9QRQRAA0AgAiABKQAANwAAIAIgASkAGDcAGCACIAEpABA3ABAgAiABKQAINwAIIBpCIH0hGiABQSBqIQEgAkEgaiECIB9CAX0iH0IAUg0ACwsgIELgAFQNAANAIAIgASkAADcAACACIAEpABg3ABggAiABKQAQNwAQIAIgASkACDcACCACIAEpADg3ADggAiABKQAwNwAwIAIgASkAKDcAKCACIAEpACA3ACAgAiABKQBYNwBYIAIgASkAUDcAUCACIAEpAEg3AEggAiABKQBANwBAIAIgASkAYDcAYCACIAEpAGg3AGggAiABKQBwNwBwIAIgASkAeDcAeCABQYABaiEBIAJBgAFqIQIgGkKAAX0iGkIfVg0ACwsgGkIQWgRAIAIgASkAADcAACACIAEpAAg3AAggGkIQfSEaIAJBEGohAiABQRBqIQELIBpCCFoEQCACIAEpAAA3AAAgGkIIfSEaIAJBCGohAiABQQhqIQELIBpCBFoEQCACIAEoAAA2AAAgGkIEfSEaIAJBBGohAiABQQRqIQELIBpCAloEQCACIAEvAAA7AAAgGkICfSEaIAJBAmohAiABQQJqIQELIBwgG30hHCAaUEUEQCACIAEtAAA6AAAgAkEBaiECIAFBAWohAQsgHFBFDQALDAILAkAgASADTSABIA8gAWusIhogBa0iGyAaIBtUGyIapyIEaiICIANLcQ0AIAMgBGogAUsgASADT3ENACABIAMgBBAHGgwCCyABIAMgAyABayIBIAFBH3UiAWogAXMiARAHIAFqIQIgGiABrSIefSIcUA0BIAEgA2ohAQNAAkAgHCAeIBwgHlQbIhtCIFQEQCAbIRoMAQsgGyIaQiB9IiBCBYhCAXxCA4MiH1BFBEADQCACIAEpAAA3AAAgAiABKQAYNwAYIAIgASkAEDcAECACIAEpAAg3AAggGkIgfSEaIAFBIGohASACQSBqIQIgH0IBfSIfQgBSDQALCyAgQuAAVA0AA0AgAiABKQAANwAAIAIgASkAGDcAGCACIAEpABA3ABAgAiABKQAINwAIIAIgASkAODcAOCACIAEpADA3ADAgAiABKQAoNwAoIAIgASkAIDcAICACIAEpAFg3AFggAiABKQBQNwBQIAIgASkASDcASCACIAEpAEA3AEAgAiABKQBgNwBgIAIgASkAaDcAaCACIAEpAHA3AHAgAiABKQB4NwB4IAFBgAFqIQEgAkGAAWohAiAaQoABfSIaQh9WDQALCyAaQhBaBEAgAiABKQAANwAAIAIgASkACDcACCAaQhB9IRogAkEQaiECIAFBEGohAQsgGkIIWgRAIAIgASkAADcAACAaQgh9IRogAkEIaiECIAFBCGohAQsgGkIEWgRAIAIgASgAADYAACAaQgR9IRogAkEEaiECIAFBBGohAQsgGkICWgRAIAIgAS8AADsAACAaQgJ9IRogAkECaiECIAFBAmohAQsgHCAbfSEcIBpQRQRAIAIgAS0AADoAACACQQFqIQIgAUEBaiEBCyAcUEUNAAsMAQsCQAJAIBYEQAJAIAQgBUkEQCAHKAKYRyAESw0BCyABIARrIQMCQEEAIARrIgVBf0ogDyABa6wiGiAbIBogG1QbIhqnIgIgBUpxDQAgBUEBSCACIANqIAFLcQ0AIAEgAyACEAcgAmohAgwFCyABIAMgBCAEQR91IgFqIAFzIgEQByABaiECIBogAa0iHn0iHFANBCABIANqIQEDQAJAIBwgHiAcIB5UGyIbQiBUBEAgGyEaDAELIBsiGkIgfSIgQgWIQgF8QgODIh9QRQRAA0AgAiABKQAANwAAIAIgASkAGDcAGCACIAEpABA3ABAgAiABKQAINwAIIBpCIH0hGiABQSBqIQEgAkEgaiECIB9CAX0iH0IAUg0ACwsgIELgAFQNAANAIAIgASkAADcAACACIAEpABg3ABggAiABKQAQNwAQIAIgASkACDcACCACIAEpADg3ADggAiABKQAwNwAwIAIgASkAKDcAKCACIAEpACA3ACAgAiABKQBYNwBYIAIgASkAUDcAUCACIAEpAEg3AEggAiABKQBANwBAIAIgASkAYDcAYCACIAEpAGg3AGggAiABKQBwNwBwIAIgASkAeDcAeCABQYABaiEBIAJBgAFqIQIgGkKAAX0iGkIfVg0ACwsgGkIQWgRAIAIgASkAADcAACACIAEpAAg3AAggGkIQfSEaIAJBEGohAiABQRBqIQELIBpCCFoEQCACIAEpAAA3AAAgGkIIfSEaIAJBCGohAiABQQhqIQELIBpCBFoEQCACIAEoAAA2AAAgGkIEfSEaIAJBBGohAiABQQRqIQELIBpCAloEQCACIAEvAAA7AAAgGkICfSEaIAJBAmohAiABQQJqIQELIBwgG30hHCAaUEUEQCACIAEtAAA6AAAgAkEBaiECIAFBAWohAQsgHFBFDQALDAQLIBAgAWsiCUEBaiIGIAUgBSAGSxshAyABIARrIQIgAUEHcUUNAiADRQ0CIAEgAi0AADoAACACQQFqIQIgAUEBaiIGQQdxQQAgA0EBayIFGw0BIAYhASAFIQMgCSEGDAILAkAgBCAFSQRAIAcoAphHIARLDQELIAEgASAEayIGKQAANwAAIAEgBUEBa0EHcUEBaiIDaiECIAUgA2siBEUNAyADIAZqIQEDQCACIAEpAAA3AAAgAUEIaiEBIAJBCGohAiAEQQhrIgQNAAsMAwsgASAEIAUQPyECDAILIAEgAi0AADoAASAJQQFrIQYgA0ECayEFIAJBAWohAgJAIAFBAmoiCkEHcUUNACAFRQ0AIAEgAi0AADoAAiAJQQJrIQYgA0EDayEFIAJBAWohAgJAIAFBA2oiCkEHcUUNACAFRQ0AIAEgAi0AADoAAyAJQQNrIQYgA0EEayEFIAJBAWohAgJAIAFBBGoiCkEHcUUNACAFRQ0AIAEgAi0AADoABCAJQQRrIQYgA0EFayEFIAJBAWohAgJAIAFBBWoiCkEHcUUNACAFRQ0AIAEgAi0AADoABSAJQQVrIQYgA0EGayEFIAJBAWohAgJAIAFBBmoiCkEHcUUNACAFRQ0AIAEgAi0AADoABiAJQQZrIQYgA0EHayEFIAJBAWohAgJAIAFBB2oiCkEHcUUNACAFRQ0AIAEgAi0AADoAByAJQQdrIQYgA0EIayEDIAFBCGohASACQQFqIQIMBgsgCiEBIAUhAwwFCyAKIQEgBSEDDAQLIAohASAFIQMMAwsgCiEBIAUhAwwCCyAKIQEgBSEDDAELIAohASAFIQMLAkACQCAGQRdNBEAgA0UNASADQQFrIQUgA0EHcSIEBEADQCABIAItAAA6AAAgA0EBayEDIAFBAWohASACQQFqIQIgBEEBayIEDQALCyAFQQdJDQEDQCABIAItAAA6AAAgASACLQABOgABIAEgAi0AAjoAAiABIAItAAM6AAMgASACLQAEOgAEIAEgAi0ABToABSABIAItAAY6AAYgASACLQAHOgAHIAFBCGohASACQQhqIQIgA0EIayIDDQALDAELIAMNAQsgASECDAELIAEgBCADED8hAgsgCyEFDAELIAEgAy0AAjoAACABQQFqIQILIAUgFE8NACACIBNJDQELCyAAIAI2AgwgACAFIAhBA3ZrIgE2AgAgACATIAJrQYMCajYCECAAIBQgAWtBDmo2AgQgByAIQQdxIgA2AogBIAcgHUJ/IACthkJ/hYM+AoQBC+cFAQR/IAMgAiACIANLGyEEIAAgAWshAgJAIABBB3FFDQAgBEUNACAAIAItAAA6AAAgA0EBayEGIAJBAWohAiAAQQFqIgdBB3FBACAEQQFrIgUbRQRAIAchACAFIQQgBiEDDAELIAAgAi0AADoAASADQQJrIQYgBEECayEFIAJBAWohAgJAIABBAmoiB0EHcUUNACAFRQ0AIAAgAi0AADoAAiADQQNrIQYgBEEDayEFIAJBAWohAgJAIABBA2oiB0EHcUUNACAFRQ0AIAAgAi0AADoAAyADQQRrIQYgBEEEayEFIAJBAWohAgJAIABBBGoiB0EHcUUNACAFRQ0AIAAgAi0AADoABCADQQVrIQYgBEEFayEFIAJBAWohAgJAIABBBWoiB0EHcUUNACAFRQ0AIAAgAi0AADoABSADQQZrIQYgBEEGayEFIAJBAWohAgJAIABBBmoiB0EHcUUNACAFRQ0AIAAgAi0AADoABiADQQdrIQYgBEEHayEFIAJBAWohAgJAIABBB2oiB0EHcUUNACAFRQ0AIAAgAi0AADoAByADQQhrIQMgBEEIayEEIABBCGohACACQQFqIQIMBgsgByEAIAUhBCAGIQMMBQsgByEAIAUhBCAGIQMMBAsgByEAIAUhBCAGIQMMAwsgByEAIAUhBCAGIQMMAgsgByEAIAUhBCAGIQMMAQsgByEAIAUhBCAGIQMLAkAgA0EXTQRAIARFDQEgBEEBayEBIARBB3EiAwRAA0AgACACLQAAOgAAIARBAWshBCAAQQFqIQAgAkEBaiECIANBAWsi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CyAAIAMtAAAEfiADKQMQBUIAC6dB//8DcSADKAIEEEcLIQUgAxAICyAEQRBqJAAgBQvgAQICfwF+QTAQCSICRQRAIAEEQCABQQA2AgQgAUEONgIAC0EADwsgAkIANwMIIAJBADYCACACQgA3AxAgAkIANwMYIAJCADcDICACQgA3ACUgAFAEQCACDwsCQCAAQv////8AVg0AIACnQQR0EAkiA0UNACACIAM2AgBBACEBQgEhBANAIAMgAUEEdGoiAUIANwIAIAFCADcABSAAIARSBEAgBKchASAEQgF8IQQMAQsLIAIgADcDCCACIAA3AxAgAg8LIAEEQCABQQA2AgQgAUEONgIAC0EAEBAgAhAGQQAL7gECA38BfiMAQRBrIgQkAAJAIARBDGpCBBAXIgNFBEBBfyECDAELAkAgAQRAIAJBgAZxIQUDQAJAIAUgASgCBHFFDQACQCADKQMIQgBUBEAgA0EAOgAADAELIANCADcDECADQQE6AAALIAMgAS8BCBANIAMgAS8BChANIAMtAABFBEAgAEEIaiIABEAgAEEANgIEIABBFDYCAAtBfyECDAQLQX8hAiAAIARBDGpCBBAbQQBIDQMgATMBCiIGUA0AIAAgASgCDCAGEBtBAEgNAwsgASgCACIBDQALC0EAIQILIAMQCAsgBEEQaiQAIAILPAEBfyAABEAgAUGABnEhAQNAIAEgACgCBHEEQCACIAAvAQpqQQRqIQILIAAoAgAiAA0ACwsgAkH//wNxC5wBAQN/IABFBEBBAA8LIAAhAwNAAn8CQAJAIAAvAQgiAUH04AFNBEAgAUEBRg0BIAFB9cYBRg0BDAILIAFBgbICRg0AIAFB9eABRw0BCyAAKAIAIQEgAEEANgIAIAAoAgwQBiAAEAYgASADIAAgA0YbIQMCQCACRQRAQQAhAgwBCyACIAE2AgALIAEMAQsgACICKAIACyIADQALIAMLsgQCBX8BfgJAAkACQCAAIAGtEBciAQRAIAEtAAANAUEAIQAMAgsgBARAIARBADYCBCAEQQ42AgALQQAPC0EAIQADQCABLQAABH4gASkDCCABKQMQfQVCAAtCBFQNASABEAwhByABIAEQDCIGrRATIghFBEBBACECIAQEQCAEQQA2AgQgBEEVNgIACyABEAggAEUNAwNAIAAoAgAhASAAKAIMEAYg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DCAAQRg2AggLDAMLIAAgBiAFLwFqQQAgBCABEQYAIQEgBhALIAFFDQILAkAgDUUEQCABIQMMAQsgACABIAUvAWgQgQEhAyABEAsgA0UNAQsCQCAJRSAMckUEQCADIQEMAQsgACADQQEQgAEhASADEAsgAUUNAQsgASEDDAELQQAhAwsgBUHwAGokACADC4UBAQF/IAFFBEAgAEEIaiIABEAgAEEANgIEIABBEjYCAAtBAA8LQTgQCSIDRQRAIABBCGoiAARAIABBADYCBCAAQQ42AgALQQAPCyADQQA2AhAgA0IANwIIIANCADcDKCADQQA2AgQgAyACNgIAIANCADcDGCADQQA2AjAgACABQTsgAxBCCw8AIAAgASACQQBBABCCAQusAgECfyABRQRAIABBCGoiAARAIABBADYCBCAAQRI2AgALQQAPCwJAIAJBfUsNACACQf//A3FBCEYNACAAQQhqIgAEQCAAQQA2AgQgAEEQNgIAC0EADwsCQEGwwAAQCSIFBEAgBUEANgIIIAVCADcCACAFQYiBAUGogQEgAxs2AqhAIAUgAjYCFCAFIAM6ABAgBUEAOgAPIAVBADsBDCAFIAMgAkF9SyIGcToADiAFQQggAiAGG0H//wNxIAQgBUGIgQFBqIEBIAMbKAIAEQAAIgI2AqxAIAINASAFEDEgBRAGCyAAQQhqIgAEQCAAQQA2AgQgAEEONgIAC0EADwsgACABQTogBRBCIgAEfyAABSAFKAKsQCAFKAKoQCgCBBEDACAFEDEgBRAGQQALC6ABAQF/IAIgACgCBCIDIAIgA0kbIgIEQCAAIAMgAms2AgQCQAJAAkACQCAAKAIcIgMoAhRBAWsOAgEAAgsgA0GgAWogASAAKAIAIAJB3IABKAIAEQgADAILIAAgACgCMCABIAAoAgAgAkHEgAEoAgARBAA2AjAMAQsgASAAKAIAIAIQBxoLIAAgACgCACACajYCACAAIAAoAgggAmo2AggLC7cCAQR/QX4hAgJAIABFDQAgACgCIEUNACAAKAIkIgRFDQAgACgCHCIBRQ0AIAEoAgAgAEcNAAJAAkAgASgCICIDQTlrDjkBAgICAgICAgICAgIBAgICAQICAgICAgICAgICAgICAgICAQICAgICAgICAgICAQICAgICAgICAgEACyADQZoFRg0AIANBKkcN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DCABajYCDCAGIAYoAgggAWo2AgggBSAFKAIUIAFqNgIUIAUgBSgCECABazYCECAGIAYoAhAgAWsiATYCECABDQAgBiAGKAIENgIIC0EAIQRBACEJIAMoAhBFDQAMCgsgAygCHCgCJCEGIAMgAygCGCIBQQFqNgIYIAEgBmotAAAhASADIARBAWo2AhAgAygCBCAEaiABOgAAIAEEQCADKAIQIQQMAQsLIAMoAhwoAixFDQAgAygCECIGIAlNDQAgBQJ/IAUoAjAhBEEAIAMoAgQgCWoiAUUNABogBCABIAYgCWtB1IABKAIAEQAACzYCMAsgA0HnADYCIAsCQCADKAIcKAIsBEAgAygCDCADKAIQIgFBAmpJBH8gBRAKIAMoAhANAkEABSABCyADKAIEaiAFKAIwOwAAIAMgAygCEEECajYCECADQaABakHkgAEoAgARAQAaCyADQfEANgIgIAUQCiADKAIQRQ0BDAcLDAYLIAUoAgQNAQsgAygCPA0AIApFDQEgAygCIEGaBUYNAQsCfyADKAKIASIBRQRAIAMgChCFAQwBCwJAAkACQCADKAKMAUECaw4CAAECCwJ/AkADQAJAAkAgAygCPA0AIAMQLyADKAI8DQAgCg0BQQAMBAsgAygCSCADKAJoai0AACEEIAMgAygC8C0iAUEBajYC8C0gASADKALsLWpBADoAACADIAMoAvAtIgFBAWo2AvAtIAEgAygC7C1qQQA6AAAgAyADKALwLSIBQQFqNgLwLSABIAMoAuwtaiAEOgAAIAMgBEECdGoiASABLwHkAUEBajsB5AEgAyADKAI8QQFrNgI8IAMgAygCaEEBaiIBNgJoIAMoAvAtIAMoAvQtRw0BQQAhBCADIAMoAlgiBkEATgR/IAMoAkggBmoFQQALIAEgBmtBABAPIAMgAygCaDYCWCADKAIAEAogAygCACgCEA0BDAILCyADQQA2AoQuIApBBEYEQCADIAMoAlgiAUEATgR/IAMoAkggAWoFQQALIAMoAmggAWtBARAPIAMgAygCaDYCWCADKAIAEApBA0ECIAMoAgAoAhAbDAILIAMoAvAtBEBBACEEIAMgAygCWCIBQQBOBH8gAygCSCABagVBAAsgAygCaCABa0EAEA8gAyADKAJoNgJYIAMoAgAQCiADKAIAKAIQRQ0BC0EBIQQLIAQL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bGl0ZXJhbC9sZW5ndGhzIHNldABpbnZhbGlkIGNvZGUgbGVuZ3RocyBzZXQAdW5rbm93biBoZWFkZXIgZmxhZ3Mgc2V0AGludmFsaWQgZGlzdGFuY2VzIHNldABpbnZhbGlkIGJpdCBsZW5ndGggcmVwZWF0AEZpbGUgYWxyZWFkeSBleGlzdHMAdG9vIG1hbnkgbGVuZ3RoIG9yIGRpc3RhbmNlIHN5bWJvbHMAaW52YWxpZCBzdG9yZWQgYmxvY2sgbGVuZ3RocwAlcyVzJXMAYnVmZmVyIGVycm9yAE5vIGVycm9yAHN0cmVhbSBlcnJvcgBUZWxsIGVycm9yAEludGVybmFsIGVycm9yAFNlZWsgZXJyb3IAV3JpdGUgZXJyb3IAZmlsZSBlcnJvcgBSZWFkIGVycm9yAFpsaWIgZXJyb3IAZGF0YSBlcnJvcgBDUkMgZXJyb3IAaW5jb21wYXRpYmxlIHZlcnNpb24AaW52YWxpZCBjb2RlIC0tIG1pc3NpbmcgZW5kLW9mLWJsb2NrAGluY29ycmVjdCBoZWFkZXIgY2hlY2sAaW5jb3JyZWN0IGxlbmd0aCBjaGVjawBpbmNvcnJlY3QgZGF0YSBjaGVjawBpbnZhbGlkIGRpc3RhbmNlIHRvbyBmYXIgYmFjawBoZWFkZXIgY3JjIG1pc21hdGNoADEuMi4xMy56bGliLW5nAGludmFsaWQgd2luZG93IHNpemUAUmVhZC1vbmx5IGFyY2hpdmUATm90IGEgemlwIGFyY2hpdmUAUmVzb3VyY2Ugc3RpbGwgaW4gdXNlAE1hbGxvYyBmYWlsdXJlAGludmFsaWQgYmxvY2sgdHlwZQBGYWlsdXJlIHRvIGNyZWF0ZSB0ZW1wb3JhcnkgZmlsZQBDYW4ndCBvcGVuIGZpbGUATm8gc3VjaCBmaWxlAFByZW1hdHVyZSBlbmQgb2YgZmlsZQBDYW4ndCByZW1vdmUgZmlsZQBpbnZhbGlkIGxpdGVyYWwvbGVuZ3RoIGNvZGUAaW52YWxpZCBkaXN0YW5jZSBjb2RlAHVua25vd24gY29tcHJlc3Npb24gbWV0aG9kAHN0cmVhbSBlbmQAQ29tcHJlc3NlZCBkYXRhIGludmFsaWQATXVsdGktZGlzayB6aXAgYXJjaGl2ZXMgbm90IHN1cHBvcnRl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UgAIANIACAAyAAgAsgAIAHIACADyAAgACgAIAIoACABKAAgAygAIACoACACqAAgAagAIAOoACAAaAAgAmgAIAFoACADaAAgAOgAIALoACAB6AAgA+gAIAAYACACGAAgARgAIAMYACAAmAAgApgAIAGYACADmAAgAFgAIAJYACABWAAgA1gAIADYACAC2AAgAdgAIAPYACAAOAAgAjgAIAE4ACADOAAgALgAIAK4ACABuAAgA7gAIAB4ACACeAAgAXgAIAN4ACAA+AAgAvgAIAH4ACAD+AAgAAQAIAIEACABBAAgAwQAIACEACAChAAgAYQAIAOEACAARAAgAkQAIAFEACADRAAgAMQAIALEACABxAAgA8QAIAAkACACJAAgASQAIAMkACAApAAgAqQAIAGkACADpAAgAGQAIAJkACABZAAgA2QAIADkACAC5AAgAeQAIAPkACAAFAAgAhQAIAEUACADFAAgAJQAIAKUACABlAAgA5QAIABUACACVAAgAVQAIANUACAA1AAgAtQAIAHUACAD1AAgADQAIAI0ACABNAAgAzQAIAC0ACACtAAgAbQAIAO0ACAAdAAgAnQAIAF0ACADdAAgAPQAIAL0ACAB9AAgA/QAIABMACQATAQkAkwAJAJMBCQBTAAkAUwEJANMACQDTAQkAMwAJADMBCQCzAAkAswEJAHMACQBzAQkA8wAJAPMBCQALAAkACwEJAIsACQCLAQkASwAJAEsBCQDLAAkAywEJACsACQArAQkAqwAJAKsBCQBrAAkAawEJAOsACQDrAQkAGwAJABsBCQCbAAkAmwEJAFsACQBbAQkA2wAJANsBCQA7AAkAOwEJALsACQC7AQkAewAJAHsBCQD7AAkA+wEJAAcACQAHAQkAhwAJAIcBCQBHAAkARwEJAMcACQDHAQkAJwAJACcBCQCnAAkApwEJAGcACQBnAQkA5wAJAOcBCQAXAAkAFwEJAJcACQCXAQkAVwAJAFcBCQDXAAkA1wEJADcACQA3AQkAtwAJALcBCQB3AAkAdwEJAPcACQD3AQkADwAJAA8BCQCPAAkAjwEJAE8ACQBPAQkAzwAJAM8BCQAvAAkALwEJAK8ACQCvAQkAbwAJAG8BCQDvAAkA7wEJAB8ACQAfAQkAnwAJAJ8BCQBfAAkAXwEJAN8ACQDfAQkAPwAJAD8BCQC/AAkA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SXMgYSBkaXJlY3RvcnkAVGV4dCBmaWxlIGJ1c3kARXhlYyBmb3JtYXQgZXJyb3IASW52YWxpZCBhcmd1bWVudABBcmd1bWVudCBsaXN0IHRvbyBsb25nAFN5bWJvbGljIGxpbmsgbG9vcABGaWxlbmFtZSB0b28gbG9uZwBUb28gbWFueSBvcGVuIGZpbGVzIGluIHN5c3RlbQBObyBmaWxlIGRlc2NyaXB0b3JzIGF2YWlsYWJsZQBCYWQgZmlsZSBkZXNjcmlwdG9yAE5vIGNoaWxkIHByb2Nlc3MAQmFkIGFkZHJlc3MARmlsZSB0b28gbGFyZ2UAVG9vIG1hbnkgbGlua3MATm8gbG9ja3MgYXZhaWxhYmxlAFJlc291cmNlIGRlYWRsb2NrIHdvdWxkIG9jY3VyAFN0YXRlIG5vdCByZWNvdmVyYWJsZQBQcmV2aW91cyBvd25lciBkaWVkAE9wZXJhdGlvbiBjYW5jZWxlZABGdW5jdGlvbiBub3QgaW1wbGVtZW50ZWQATm8gbWVzc2FnZSBvZiBkZXNpcmVkIHR5cGUASWRlbnRpZmllciByZW1vdmVkAERldmljZSBub3QgYSBzdHJlYW0ATm8gZGF0YSBhdmFpbGFibGUARGV2aWNlIHRpbWVvdXQAT3V0IG9mIHN0cmVhbXMgcmVzb3VyY2VzAExpbmsgaGFzIGJlZW4gc2V2ZXJlZABQcm90b2NvbCBlcnJvcgBCYWQgbWVzc2FnZQBGaWxlIGRlc2NyaXB0b3IgaW4gYmFkIHN0YXRlAE5vdCBhIHNvY2tldABEZXN0aW5hdGlvbiBhZGRyZXNzIHJlcXVpcmVkAE1lc3NhZ2UgdG9vIGxhcmdlAFByb3RvY29sIHdyb25nIHR5cGUgZm9yIHNvY2tldABQcm90b2NvbCBub3QgYXZhaWxhYmxlAFByb3RvY29sIG5vdCBzdXBwb3J0ZWQAU29ja2V0IHR5cGUgbm90IHN1cHBvcnRlZABOb3Qgc3VwcG9ydGVkAFByb3RvY29sIGZhbWlseSBub3Qgc3VwcG9ydGVkAEFkZHJlc3MgZmFtaWx5IG5vdCBzdXBwb3J0ZWQgYnkgcHJvdG9jb2wAQWRkcmVzcyBub3QgYXZhaWxhYmxlAE5ldHdvcmsgaXMgZG93bgBOZXR3b3JrIHVucmVhY2hhYmxlAENvbm5lY3Rpb24gcmVzZXQgYnkgbmV0d29yawBDb25uZWN0aW9uIGFib3J0ZWQATm8gYnVmZmVyIHNwYWNlIGF2YWlsYWJsZQBTb2NrZXQgaXMgY29ubmVjdGVkAFNvY2tldCBub3QgY29ubmVjdGVkAENhbm5vdCBzZW5kIGFmdGVyIHNvY2tldCBzaHV0ZG93bgBPcGVyYXRpb24gYWxyZWFkeSBpbiBwcm9ncmVzcwBPcGVyYXRpb24gaW4gcHJvZ3Jlc3MAU3RhbGUgZmlsZSBoYW5kbGUAUmVtb3RlIEkvTyBlcnJvcgBRdW90YSBleGNlZWRlZABObyBtZWRpdW0gZm91bmQAV3JvbmcgbWVkaXVtIHR5cGUATm8gZXJyb3IgaW5mb3JtYXRpb24AQcCAAQuFARMAAAAUAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAGwAAABwAAAAdAAAAHgAAAB8AAAAgAAAAIQAAACIAAAAjAAAAgERQADEAAAAyAAAAMwAAADQAAAA1AAAANgAAADcAAAA4AAAAOQAAADIAAAAzAAAANAAAADUAAAA2AAAANwAAADgAQfSCAQsCXEQAQbCDAQsQ/////////////////////w==";Co(ji)||(ji=P(ji));function eo(Ke){try{if(Ke==ji&&le)return new Uint8Array(le);var st=Me(Ke);if(st)return st;if(R)return R(Ke);throw"sync fetching of the wasm failed: you can preload it to Module['wasmBinary'] manually, or emcc.py will do that for you when generating HTML (but not JS)"}catch(St){rs(St)}}function wo(Ke,st){var St,lr,te;try{te=eo(Ke),lr=new WebAssembly.Module(te),St=new WebAssembly.Instance(lr,st)}catch(Oe){var Ee=Oe.toString();throw ee("failed to compile wasm module: "+Ee),(Ee.includes("imported Memory")||Ee.includes("memory import"))&&ee("Memory size incompatibility issues may be due to changing INITIAL_MEMORY at runtime to something too large. Use ALLOW_MEMORY_GROWTH to allow any size memory (and also make sure not to set INITIAL_MEMORY at runtime to something smaller than it was at compile time)."),Oe}return[St,lr]}function QA(){var Ke={a:cu};function st(te,Ee){var Oe=te.exports;r.asm=Oe,Be=r.asm.g,z(Be.buffer),$=r.asm.W,gn(r.asm.h),Io("wasm-instantiate")}if(ai("wasm-instantiate"),r.instantiateWasm)try{var St=r.instantiateWasm(Ke,st);return St}catch(te){return ee("Module.instantiateWasm callback failed with error: "+te),!1}var lr=wo(ji,Ke);return st(lr[0]),r.asm}function Af(Ke){return F.getFloat32(Ke,!0)}function dh(Ke){return F.getFloat64(Ke,!0)}function mh(Ke){return F.getInt16(Ke,!0)}function to(Ke){return F.getInt32(Ke,!0)}function jn(Ke,st){F.setInt32(Ke,st,!0)}function Ts(Ke){for(;Ke.length>0;){var st=Ke.shift();if(typeof st=="function"){st(r);continue}var St=st.func;typeof St=="number"?st.arg===void 0?$.get(St)():$.get(St)(st.arg):St(st.arg===void 0?null:st.arg)}}function ro(Ke,st){var St=new Date(to((Ke>>2)*4)*1e3);jn((st>>2)*4,St.getUTCSeconds()),jn((st+4>>2)*4,St.getUTCMinutes()),jn((st+8>>2)*4,St.getUTCHours()),jn((st+12>>2)*4,St.getUTCDate()),jn((st+16>>2)*4,St.getUTCMonth()),jn((st+20>>2)*4,St.getUTCFullYear()-1900),jn((st+24>>2)*4,St.getUTCDay()),jn((st+36>>2)*4,0),jn((st+32>>2)*4,0);var lr=Date.UTC(St.getUTCFullYear(),0,1,0,0,0,0),te=(St.getTime()-lr)/(1e3*60*60*24)|0;return jn((st+28>>2)*4,te),ro.GMTString||(ro.GMTString=rt("GMT")),jn((st+40>>2)*4,ro.GMTString),st}function ou(Ke,st){return ro(Ke,st)}function au(Ke,st,St){ke.copyWithin(Ke,st,st+St)}function lu(Ke){try{return Be.grow(Ke-Pe.byteLength+65535>>>16),z(Be.buffer),1}catch{}}function TA(Ke){var st=ke.length;Ke=Ke>>>0;var St=2147483648;if(Ke>St)return!1;for(var lr=1;lr<=4;lr*=2){var te=st*(1+.2/lr);te=Math.min(te,Ke+100663296);var Ee=Math.min(St,Ne(Math.max(Ke,te),65536)),Oe=lu(Ee);if(Oe)return!0}return!1}function RA(Ke){ue(Ke)}function oa(Ke){var st=Date.now()/1e3|0;return Ke&&jn((Ke>>2)*4,st),st}function aa(){if(aa.called)return;aa.called=!0;var Ke=new Date().getFullYear(),st=new Date(Ke,0,1),St=new Date(Ke,6,1),lr=st.getTimezoneOffset(),te=St.getTimezoneOffset(),Ee=Math.max(lr,te);jn((vl()>>2)*4,Ee*60),jn((Is()>>2)*4,+(lr!=te));function Oe(An){var li=An.toTimeString().match(/\(([A-Za-z ]+)\)$/);return li?li[1]:"GMT"}var dt=Oe(st),Et=Oe(St),bt=rt(dt),tr=rt(Et);te>2)*4,bt),jn((Mi()+4>>2)*4,tr)):(jn((Mi()>>2)*4,tr),jn((Mi()+4>>2)*4,bt))}function FA(Ke){aa();var st=Date.UTC(to((Ke+20>>2)*4)+1900,to((Ke+16>>2)*4),to((Ke+12>>2)*4),to((Ke+8>>2)*4),to((Ke+4>>2)*4),to((Ke>>2)*4),0),St=new Date(st);jn((Ke+24>>2)*4,St.getUTCDay());var lr=Date.UTC(St.getUTCFullYear(),0,1,0,0,0,0),te=(St.getTime()-lr)/(1e3*60*60*24)|0;return jn((Ke+28>>2)*4,te),St.getTime()/1e3|0}var gr=typeof atob=="function"?atob:function(Ke){var st="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",St="",lr,te,Ee,Oe,dt,Et,bt,tr=0;Ke=Ke.replace(/[^A-Za-z0-9\+\/\=]/g,"");do Oe=st.indexOf(Ke.charAt(tr++)),dt=st.indexOf(Ke.charAt(tr++)),Et=st.indexOf(Ke.charAt(tr++)),bt=st.indexOf(Ke.charAt(tr++)),lr=Oe<<2|dt>>4,te=(dt&15)<<4|Et>>2,Ee=(Et&3)<<6|bt,St=St+String.fromCharCode(lr),Et!==64&&(St=St+String.fromCharCode(te)),bt!==64&&(St=St+String.fromCharCode(Ee));while(tr0||(Ct(),Ir>0))return;function st(){Qn||(Qn=!0,r.calledRun=!0,!Ce&&(qt(),s(r),r.onRuntimeInitialized&&r.onRuntimeInitialized(),ir()))}r.setStatus?(r.setStatus("Running..."),setTimeout(function(){setTimeout(function(){r.setStatus("")},1),st()},1)):st()}if(r.run=Ac,r.preInit)for(typeof r.preInit=="function"&&(r.preInit=[r.preInit]);r.preInit.length>0;)r.preInit.pop()();return Ac(),e}}();typeof wT=="object"&&typeof Pj=="object"?Pj.exports=bj:typeof define=="function"&&define.amd?define([],function(){return bj}):typeof wT=="object"&&(wT.createModule=bj)});var Up,hpe,gpe,dpe=Xe(()=>{Up=["number","number"],hpe=(Z=>(Z[Z.ZIP_ER_OK=0]="ZIP_ER_OK",Z[Z.ZIP_ER_MULTIDISK=1]="ZIP_ER_MULTIDISK",Z[Z.ZIP_ER_RENAME=2]="ZIP_ER_RENAME",Z[Z.ZIP_ER_CLOSE=3]="ZIP_ER_CLOSE",Z[Z.ZIP_ER_SEEK=4]="ZIP_ER_SEEK",Z[Z.ZIP_ER_READ=5]="ZIP_ER_READ",Z[Z.ZIP_ER_WRITE=6]="ZIP_ER_WRITE",Z[Z.ZIP_ER_CRC=7]="ZIP_ER_CRC",Z[Z.ZIP_ER_ZIPCLOSED=8]="ZIP_ER_ZIPCLOSED",Z[Z.ZIP_ER_NOENT=9]="ZIP_ER_NOENT",Z[Z.ZIP_ER_EXISTS=10]="ZIP_ER_EXISTS",Z[Z.ZIP_ER_OPEN=11]="ZIP_ER_OPEN",Z[Z.ZIP_ER_TMPOPEN=12]="ZIP_ER_TMPOPEN",Z[Z.ZIP_ER_ZLIB=13]="ZIP_ER_ZLIB",Z[Z.ZIP_ER_MEMORY=14]="ZIP_ER_MEMORY",Z[Z.ZIP_ER_CHANGED=15]="ZIP_ER_CHANGED",Z[Z.ZIP_ER_COMPNOTSUPP=16]="ZIP_ER_COMPNOTSUPP",Z[Z.ZIP_ER_EOF=17]="ZIP_ER_EOF",Z[Z.ZIP_ER_INVAL=18]="ZIP_ER_INVAL",Z[Z.ZIP_ER_NOZIP=19]="ZIP_ER_NOZIP",Z[Z.ZIP_ER_INTERNAL=20]="ZIP_ER_INTERNAL",Z[Z.ZIP_ER_INCONS=21]="ZIP_ER_INCONS",Z[Z.ZIP_ER_REMOVE=22]="ZIP_ER_REMOVE",Z[Z.ZIP_ER_DELETED=23]="ZIP_ER_DELETED",Z[Z.ZIP_ER_ENCRNOTSUPP=24]="ZIP_ER_ENCRNOTSUPP",Z[Z.ZIP_ER_RDONLY=25]="ZIP_ER_RDONLY",Z[Z.ZIP_ER_NOPASSWD=26]="ZIP_ER_NOPASSWD",Z[Z.ZIP_ER_WRONGPASSWD=27]="ZIP_ER_WRONGPASSWD",Z[Z.ZIP_ER_OPNOTSUPP=28]="ZIP_ER_OPNOTSUPP",Z[Z.ZIP_ER_INUSE=29]="ZIP_ER_INUSE",Z[Z.ZIP_ER_TELL=30]="ZIP_ER_TELL",Z[Z.ZIP_ER_COMPRESSED_DATA=31]="ZIP_ER_COMPRESSED_DATA",Z))(hpe||{}),gpe=t=>({get HEAPU8(){return t.HEAPU8},errors:hpe,SEEK_SET:0,SEEK_CUR:1,SEEK_END:2,ZIP_CHECKCONS:4,ZIP_EXCL:2,ZIP_RDONLY:16,ZIP_FL_OVERWRITE:8192,ZIP_FL_COMPRESSED:4,ZIP_OPSYS_DOS:0,ZIP_OPSYS_AMIGA:1,ZIP_OPSYS_OPENVMS:2,ZIP_OPSYS_UNIX:3,ZIP_OPSYS_VM_CMS:4,ZIP_OPSYS_ATARI_ST:5,ZIP_OPSYS_OS_2:6,ZIP_OPSYS_MACINTOSH:7,ZIP_OPSYS_Z_SYSTEM:8,ZIP_OPSYS_CPM:9,ZIP_OPSYS_WINDOWS_NTFS:10,ZIP_OPSYS_MVS:11,ZIP_OPSYS_VSE:12,ZIP_OPSYS_ACORN_RISC:13,ZIP_OPSYS_VFAT:14,ZIP_OPSYS_ALTERNATE_MVS:15,ZIP_OPSYS_BEOS:16,ZIP_OPSYS_TANDEM:17,ZIP_OPSYS_OS_400:18,ZIP_OPSYS_OS_X:19,ZIP_CM_DEFAULT:-1,ZIP_CM_STORE:0,ZIP_CM_DEFLATE:8,uint08S:t._malloc(1),uint32S:t._malloc(4),malloc:t._malloc,free:t._free,getValue:t.getValue,openFromSource:t.cwrap("zip_open_from_source","number",["number","number","number"]),close:t.cwrap("zip_close","number",["number"]),discard:t.cwrap("zip_discard",null,["number"]),getError:t.cwrap("zip_get_error","number",["number"]),getName:t.cwrap("zip_get_name","string",["number","number","number"]),getNumEntries:t.cwrap("zip_get_num_entries","number",["number","number"]),delete:t.cwrap("zip_delete","number",["number","number"]),statIndex:t.cwrap("zip_stat_index","number",["number",...Up,"number","number"]),fopenIndex:t.cwrap("zip_fopen_index","number",["number",...Up,"number"]),fread:t.cwrap("zip_fread","number",["number","number","number","number"]),fclose:t.cwrap("zip_fclose","number",["number"]),dir:{add:t.cwrap("zip_dir_add","number",["number","string"])},file:{add:t.cwrap("zip_file_add","number",["number","string","number","number"]),getError:t.cwrap("zip_file_get_error","number",["number"]),getExternalAttributes:t.cwrap("zip_file_get_external_attributes","number",["number",...Up,"number","number","number"]),setExternalAttributes:t.cwrap("zip_file_set_external_attributes","number",["number",...Up,"number","number","number"]),setMtime:t.cwrap("zip_file_set_mtime","number",["number",...Up,"number","number"]),setCompression:t.cwrap("zip_set_file_compression","number",["number",...Up,"number","number"])},ext:{countSymlinks:t.cwrap("zip_ext_count_symlinks","number",["number"])},error:{initWithCode:t.cwrap("zip_error_init_with_code",null,["number","number"]),strerror:t.cwrap("zip_error_strerror","string",["number"])},name:{locate:t.cwrap("zip_name_locate","number",["number","string","number"])},source:{fromUnattachedBuffer:t.cwrap("zip_source_buffer_create","number",["number",...Up,"number","number"]),fromBuffer:t.cwrap("zip_source_buffer","number",["number","number",...Up,"number"]),free:t.cwrap("zip_source_free",null,["number"]),keep:t.cwrap("zip_source_keep",null,["number"]),open:t.cwrap("zip_source_open","number",["number"]),close:t.cwrap("zip_source_close","number",["number"]),seek:t.cwrap("zip_source_seek","number",["number",...Up,"number"]),tell:t.cwrap("zip_source_tell","number",["number"]),read:t.cwrap("zip_source_read","number",["number","number","number"]),error:t.cwrap("zip_source_error","number",["number"])},struct:{statS:t.cwrap("zipstruct_statS","number",[]),statSize:t.cwrap("zipstruct_stat_size","number",["number"]),statCompSize:t.cwrap("zipstruct_stat_comp_size","number",["number"]),statCompMethod:t.cwrap("zipstruct_stat_comp_method","number",["number"]),statMtime:t.cwrap("zipstruct_stat_mtime","number",["number"]),statCrc:t.cwrap("zipstruct_stat_crc","number",["number"]),errorS:t.cwrap("zipstruct_errorS","number",[]),errorCodeZip:t.cwrap("zipstruct_error_code_zip","number",["number"])}})});function xj(t,e){let r=t.indexOf(e);if(r<=0)return null;let s=r;for(;r>=0&&(s=r+e.length,t[s]!==J.sep);){if(t[r-1]===J.sep)return null;r=t.indexOf(e,s)}return t.length>s&&t[s]!==J.sep?null:t.slice(0,s)}var $f,mpe=Xe(()=>{Dt();Dt();eA();$f=class t extends e0{static async openPromise(e,r){let s=new t(r);try{return await e(s)}finally{s.saveAndClose()}}constructor(e={}){let r=e.fileExtensions,s=e.readOnlyArchives,a=typeof r>"u"?f=>xj(f,".zip"):f=>{for(let p of r){let h=xj(f,p);if(h)return h}return null},n=(f,p)=>new As(p,{baseFs:f,readOnly:s,stats:f.statSync(p),customZipImplementation:e.customZipImplementation}),c=async(f,p)=>{let h={baseFs:f,readOnly:s,stats:await f.statPromise(p),customZipImplementation:e.customZipImplementation};return()=>new As(p,h)};super({...e,factorySync:n,factoryPromise:c,getMountPoint:a})}}});var kj,BI,Qj=Xe(()=>{Dj();kj=class extends Error{constructor(e,r){super(e),this.name="Libzip Error",this.code=r}},BI=class{constructor(e){this.filesShouldBeCached=!0;let r="buffer"in e?e.buffer:e.baseFs.readFileSync(e.path);this.libzip=cv();let s=this.libzip.malloc(4);try{let c=0;e.readOnly&&(c|=this.libzip.ZIP_RDONLY);let f=this.allocateUnattachedSource(r);try{this.zip=this.libzip.openFromSource(f,c,s),this.lzSource=f}catch(p){throw this.libzip.source.free(f),p}if(this.zip===0){let p=this.libzip.struct.errorS();throw this.libzip.error.initWithCode(p,this.libzip.getValue(s,"i32")),this.makeLibzipError(p)}}finally{this.libzip.free(s)}let a=this.libzip.getNumEntries(this.zip,0),n=new Array(a);for(let c=0;c>>0,n=this.libzip.struct.statMtime(r)>>>0,c=this.libzip.struct.statCrc(r)>>>0;return{size:a,mtime:n,crc:c}}makeLibzipError(e){let r=this.libzip.struct.errorCodeZip(e),s=this.libzip.error.strerror(e),a=new kj(s,this.libzip.errors[r]);if(r===this.libzip.errors.ZIP_ER_CHANGED)throw new Error(`Assertion failed: Unexpected libzip error: ${a.message}`);return a}setFileSource(e,r,s){let a=this.allocateSource(s);try{let n=this.libzip.file.add(this.zip,e,a,this.libzip.ZIP_FL_OVERWRITE);if(n===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));if(r!==null&&this.libzip.file.setCompression(this.zip,n,0,r[0],r[1])===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));return n}catch(n){throw this.libzip.source.free(a),n}}setMtime(e,r){if(this.libzip.file.setMtime(this.zip,e,0,r,0)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip))}getExternalAttributes(e){if(this.libzip.file.getExternalAttributes(this.zip,e,0,0,this.libzip.uint08S,this.libzip.uint32S)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));let s=this.libzip.getValue(this.libzip.uint08S,"i8")>>>0,a=this.libzip.getValue(this.libzip.uint32S,"i32")>>>0;return[s,a]}setExternalAttributes(e,r,s){if(this.libzip.file.setExternalAttributes(this.zip,e,0,0,r,s)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip))}locate(e){return this.libzip.name.locate(this.zip,e,0)}getFileSource(e){let r=this.libzip.struct.statS();if(this.libzip.statIndex(this.zip,e,0,0,r)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));let a=this.libzip.struct.statCompSize(r),n=this.libzip.struct.statCompMethod(r),c=this.libzip.malloc(a);try{let f=this.libzip.fopenIndex(this.zip,e,0,this.libzip.ZIP_FL_COMPRESSED);if(f===0)throw this.makeLibzipError(this.libzip.getError(this.zip));try{let p=this.libzip.fread(f,c,a,0);if(p===-1)throw this.makeLibzipError(this.libzip.file.getError(f));if(pa)throw new Error("Overread");let h=this.libzip.HEAPU8.subarray(c,c+a);return{data:Buffer.from(h),compressionMethod:n}}finally{this.libzip.fclose(f)}}finally{this.libzip.free(c)}}deleteEntry(e){if(this.libzip.delete(this.zip,e)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip))}addDirectory(e){let r=this.libzip.dir.add(this.zip,e);if(r===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));return r}getBufferAndClose(){try{if(this.libzip.source.keep(this.lzSource),this.libzip.close(this.zip)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));if(this.libzip.source.open(this.lzSource)===-1)throw this.makeLibzipError(this.libzip.source.error(this.lzSource));if(this.libzip.source.seek(this.lzSource,0,0,this.libzip.SEEK_END)===-1)throw this.makeLibzipError(this.libzip.source.error(this.lzSource));let e=this.libzip.source.tell(this.lzSource);if(e===-1)throw this.makeLibzipError(this.libzip.source.error(this.lzSource));if(this.libzip.source.seek(this.lzSource,0,0,this.libzip.SEEK_SET)===-1)throw this.makeLibzipError(this.libzip.source.error(this.lzSource));let r=this.libzip.malloc(e);if(!r)throw new Error("Couldn't allocate enough memory");try{let s=this.libzip.source.read(this.lzSource,r,e);if(s===-1)throw this.makeLibzipError(this.libzip.source.error(this.lzSource));if(se)throw new Error("Overread");let a=Buffer.from(this.libzip.HEAPU8.subarray(r,r+e));return process.env.YARN_IS_TEST_ENV&&process.env.YARN_ZIP_DATA_EPILOGUE&&(a=Buffer.concat([a,Buffer.from(process.env.YARN_ZIP_DATA_EPILOGUE)])),a}finally{this.libzip.free(r)}}finally{this.libzip.source.close(this.lzSource),this.libzip.source.free(this.lzSource)}}allocateBuffer(e){Buffer.isBuffer(e)||(e=Buffer.from(e));let r=this.libzip.malloc(e.byteLength);if(!r)throw new Error("Couldn't allocate enough memory");return new Uint8Array(this.libzip.HEAPU8.buffer,r,e.byteLength).set(e),{buffer:r,byteLength:e.byteLength}}allocateUnattachedSource(e){let r=this.libzip.struct.errorS(),{buffer:s,byteLength:a}=this.allocateBuffer(e),n=this.libzip.source.fromUnattachedBuffer(s,a,0,1,r);if(n===0)throw this.libzip.free(r),this.makeLibzipError(r);return n}allocateSource(e){let{buffer:r,byteLength:s}=this.allocateBuffer(e),a=this.libzip.source.fromBuffer(this.zip,r,s,0,1);if(a===0)throw this.libzip.free(r),this.makeLibzipError(this.libzip.getError(this.zip));return a}discard(){this.libzip.discard(this.zip)}}});function Ynt(t){if(typeof t=="string"&&String(+t)===t)return+t;if(typeof t=="number"&&Number.isFinite(t))return t<0?Date.now()/1e3:t;if(ype.types.isDate(t))return t.getTime()/1e3;throw new Error("Invalid time")}function BT(){return Buffer.from([80,75,5,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0])}var xa,Tj,ype,Rj,lm,Fj,Nj,Epe,As,vT=Xe(()=>{Dt();Dt();Dt();Dt();Dt();Dt();xa=Ie("fs"),Tj=Ie("stream"),ype=Ie("util"),Rj=ut(Ie("zlib"));Qj();lm=3,Fj=0,Nj=8,Epe="mixed";As=class extends Uf{constructor(r,s={}){super();this.listings=new Map;this.entries=new Map;this.fileSources=new Map;this.fds=new Map;this.nextFd=0;this.ready=!1;this.readOnly=!1;s.readOnly&&(this.readOnly=!0);let a=s;this.level=typeof a.level<"u"?a.level:Epe;let n=s.customZipImplementation??BI;if(typeof r=="string"){let{baseFs:f=new Yn}=a;this.baseFs=f,this.path=r}else this.path=null,this.baseFs=null;if(s.stats)this.stats=s.stats;else if(typeof r=="string")try{this.stats=this.baseFs.statSync(r)}catch(f){if(f.code==="ENOENT"&&a.create)this.stats=$a.makeDefaultStats();else throw f}else this.stats=$a.makeDefaultStats();typeof r=="string"?s.create?this.zipImpl=new n({buffer:BT(),readOnly:this.readOnly}):this.zipImpl=new n({path:r,baseFs:this.baseFs,readOnly:this.readOnly,size:this.stats.size}):this.zipImpl=new n({buffer:r??BT(),readOnly:this.readOnly}),this.listings.set(vt.root,new Set);let c=this.zipImpl.getListings();for(let f=0;f{this.closeSync(f)}})}async readPromise(r,s,a,n,c){return this.readSync(r,s,a,n,c)}readSync(r,s,a=0,n=s.byteLength,c=-1){let f=this.fds.get(r);if(typeof f>"u")throw or.EBADF("read");let p=c===-1||c===null?f.cursor:c,h=this.readFileSync(f.p);h.copy(s,a,p,p+n);let E=Math.max(0,Math.min(h.length-p,n));return(c===-1||c===null)&&(f.cursor+=E),E}async writePromise(r,s,a,n,c){return typeof s=="string"?this.writeSync(r,s,c):this.writeSync(r,s,a,n,c)}writeSync(r,s,a,n,c){throw typeof this.fds.get(r)>"u"?or.EBADF("read"):new Error("Unimplemented")}async closePromise(r){return this.closeSync(r)}closeSync(r){if(typeof this.fds.get(r)>"u")throw or.EBADF("read");this.fds.delete(r)}createReadStream(r,{encoding:s}={}){if(r===null)throw new Error("Unimplemented");let a=this.openSync(r,"r"),n=Object.assign(new Tj.PassThrough({emitClose:!0,autoDestroy:!0,destroy:(f,p)=>{clearImmediate(c),this.closeSync(a),p(f)}}),{close(){n.destroy()},bytesRead:0,path:r,pending:!1}),c=setImmediate(async()=>{try{let f=await this.readFilePromise(r,s);n.bytesRead=f.length,n.end(f)}catch(f){n.destroy(f)}});return n}createWriteStream(r,{encoding:s}={}){if(this.readOnly)throw or.EROFS(`open '${r}'`);if(r===null)throw new Error("Unimplemented");let a=[],n=this.openSync(r,"w"),c=Object.assign(new Tj.PassThrough({autoDestroy:!0,emitClose:!0,destroy:(f,p)=>{try{f?p(f):(this.writeFileSync(r,Buffer.concat(a),s),p(null))}catch(h){p(h)}finally{this.closeSync(n)}}}),{close(){c.destroy()},bytesWritten:0,path:r,pending:!1});return c.on("data",f=>{let p=Buffer.from(f);c.bytesWritten+=p.length,a.push(p)}),c}async realpathPromise(r){return this.realpathSync(r)}realpathSync(r){let s=this.resolveFilename(`lstat '${r}'`,r);if(!this.entries.has(s)&&!this.listings.has(s))throw or.ENOENT(`lstat '${r}'`);return s}async existsPromise(r){return this.existsSync(r)}existsSync(r){if(!this.ready)throw or.EBUSY(`archive closed, existsSync '${r}'`);if(this.symlinkCount===0){let a=J.resolve(vt.root,r);return this.entries.has(a)||this.listings.has(a)}let s;try{s=this.resolveFilename(`stat '${r}'`,r,void 0,!1)}catch{return!1}return s===void 0?!1:this.entries.has(s)||this.listings.has(s)}async accessPromise(r,s){return this.accessSync(r,s)}accessSync(r,s=xa.constants.F_OK){let a=this.resolveFilename(`access '${r}'`,r);if(!this.entries.has(a)&&!this.listings.has(a))throw or.ENOENT(`access '${r}'`);if(this.readOnly&&s&xa.constants.W_OK)throw or.EROFS(`access '${r}'`)}async statPromise(r,s={bigint:!1}){return s.bigint?this.statSync(r,{bigint:!0}):this.statSync(r)}statSync(r,s={bigint:!1,throwIfNoEntry:!0}){let a=this.resolveFilename(`stat '${r}'`,r,void 0,s.throwIfNoEntry);if(a!==void 0){if(!this.entries.has(a)&&!this.listings.has(a)){if(s.throwIfNoEntry===!1)return;throw or.ENOENT(`stat '${r}'`)}if(r[r.length-1]==="/"&&!this.listings.has(a))throw or.ENOTDIR(`stat '${r}'`);return this.statImpl(`stat '${r}'`,a,s)}}async fstatPromise(r,s){return this.fstatSync(r,s)}fstatSync(r,s){let a=this.fds.get(r);if(typeof a>"u")throw or.EBADF("fstatSync");let{p:n}=a,c=this.resolveFilename(`stat '${n}'`,n);if(!this.entries.has(c)&&!this.listings.has(c))throw or.ENOENT(`stat '${n}'`);if(n[n.length-1]==="/"&&!this.listings.has(c))throw or.ENOTDIR(`stat '${n}'`);return this.statImpl(`fstat '${n}'`,c,s)}async lstatPromise(r,s={bigint:!1}){return s.bigint?this.lstatSync(r,{bigint:!0}):this.lstatSync(r)}lstatSync(r,s={bigint:!1,throwIfNoEntry:!0}){let a=this.resolveFilename(`lstat '${r}'`,r,!1,s.throwIfNoEntry);if(a!==void 0){if(!this.entries.has(a)&&!this.listings.has(a)){if(s.throwIfNoEntry===!1)return;throw or.ENOENT(`lstat '${r}'`)}if(r[r.length-1]==="/"&&!this.listings.has(a))throw or.ENOTDIR(`lstat '${r}'`);return this.statImpl(`lstat '${r}'`,a,s)}}statImpl(r,s,a={}){let n=this.entries.get(s);if(typeof n<"u"){let c=this.zipImpl.stat(n),f=c.crc,p=c.size,h=c.mtime*1e3,E=this.stats.uid,C=this.stats.gid,S=512,P=Math.ceil(c.size/S),I=h,R=h,N=h,U=new Date(I),W=new Date(R),ee=new Date(N),ie=new Date(h),ue=this.listings.has(s)?xa.constants.S_IFDIR:this.isSymbolicLink(n)?xa.constants.S_IFLNK:xa.constants.S_IFREG,le=ue===xa.constants.S_IFDIR?493:420,me=ue|this.getUnixMode(n,le)&511,pe=Object.assign(new $a.StatEntry,{uid:E,gid:C,size:p,blksize:S,blocks:P,atime:U,birthtime:W,ctime:ee,mtime:ie,atimeMs:I,birthtimeMs:R,ctimeMs:N,mtimeMs:h,mode:me,crc:f});return a.bigint===!0?$a.convertToBigIntStats(pe):pe}if(this.listings.has(s)){let c=this.stats.uid,f=this.stats.gid,p=0,h=512,E=0,C=this.stats.mtimeMs,S=this.stats.mtimeMs,P=this.stats.mtimeMs,I=this.stats.mtimeMs,R=new Date(C),N=new Date(S),U=new Date(P),W=new Date(I),ee=xa.constants.S_IFDIR|493,ue=Object.assign(new $a.StatEntry,{uid:c,gid:f,size:p,blksize:h,blocks:E,atime:R,birthtime:N,ctime:U,mtime:W,atimeMs:C,birthtimeMs:S,ctimeMs:P,mtimeMs:I,mode:ee,crc:0});return a.bigint===!0?$a.convertToBigIntStats(ue):ue}throw new Error("Unreachable")}getUnixMode(r,s){let[a,n]=this.zipImpl.getExternalAttributes(r);return a!==lm?s:n>>>16}registerListing(r){let s=this.listings.get(r);if(s)return s;this.registerListing(J.dirname(r)).add(J.basename(r));let n=new Set;return this.listings.set(r,n),n}registerEntry(r,s){this.registerListing(J.dirname(r)).add(J.basename(r)),this.entries.set(r,s)}unregisterListing(r){this.listings.delete(r),this.listings.get(J.dirname(r))?.delete(J.basename(r))}unregisterEntry(r){this.unregisterListing(r);let s=this.entries.get(r);this.entries.delete(r),!(typeof s>"u")&&(this.fileSources.delete(s),this.isSymbolicLink(s)&&this.symlinkCount--)}deleteEntry(r,s){this.unregisterEntry(r),this.zipImpl.deleteEntry(s)}resolveFilename(r,s,a=!0,n=!0){if(!this.ready)throw or.EBUSY(`archive closed, ${r}`);let c=J.resolve(vt.root,s);if(c==="/")return vt.root;let f=this.entries.get(c);if(a&&f!==void 0)if(this.symlinkCount!==0&&this.isSymbolicLink(f)){let p=this.getFileSource(f).toString();return this.resolveFilename(r,J.resolve(J.dirname(c),p),!0,n)}else return c;for(;;){let p=this.resolveFilename(r,J.dirname(c),!0,n);if(p===void 0)return p;let h=this.listings.has(p),E=this.entries.has(p);if(!h&&!E){if(n===!1)return;throw or.ENOENT(r)}if(!h)throw or.ENOTDIR(r);if(c=J.resolve(p,J.basename(c)),!a||this.symlinkCount===0)break;let C=this.zipImpl.locate(c.slice(1));if(C===-1)break;if(this.isSymbolicLink(C)){let S=this.getFileSource(C).toString();c=J.resolve(J.dirname(c),S)}else break}return c}setFileSource(r,s){let a=Buffer.isBuffer(s)?s:Buffer.from(s),n=J.relative(vt.root,r),c=null;this.level!=="mixed"&&(c=[this.level===0?Fj:Nj,this.level]);let f=this.zipImpl.setFileSource(n,c,a);return this.fileSources.set(f,a),f}isSymbolicLink(r){if(this.symlinkCount===0)return!1;let[s,a]=this.zipImpl.getExternalAttributes(r);return s!==lm?!1:(a>>>16&xa.constants.S_IFMT)===xa.constants.S_IFLNK}getFileSource(r,s={asyncDecompress:!1}){let a=this.fileSources.get(r);if(typeof a<"u")return a;let{data:n,compressionMethod:c}=this.zipImpl.getFileSource(r);if(c===Fj)return this.zipImpl.filesShouldBeCached&&this.fileSources.set(r,n),n;if(c===Nj){if(s.asyncDecompress)return new Promise((f,p)=>{Rj.default.inflateRaw(n,(h,E)=>{h?p(h):(this.zipImpl.filesShouldBeCached&&this.fileSources.set(r,E),f(E))})});{let f=Rj.default.inflateRawSync(n);return this.zipImpl.filesShouldBeCached&&this.fileSources.set(r,f),f}}else throw new Error(`Unsupported compression method: ${c}`)}async fchmodPromise(r,s){return this.chmodPromise(this.fdToPath(r,"fchmod"),s)}fchmodSync(r,s){return this.chmodSync(this.fdToPath(r,"fchmodSync"),s)}async chmodPromise(r,s){return this.chmodSync(r,s)}chmodSync(r,s){if(this.readOnly)throw or.EROFS(`chmod '${r}'`);s&=493;let a=this.resolveFilename(`chmod '${r}'`,r,!1),n=this.entries.get(a);if(typeof n>"u")throw new Error(`Assertion failed: The entry should have been registered (${a})`);let f=this.getUnixMode(n,xa.constants.S_IFREG|0)&-512|s;this.zipImpl.setExternalAttributes(n,lm,f<<16)}async fchownPromise(r,s,a){return this.chownPromise(this.fdToPath(r,"fchown"),s,a)}fchownSync(r,s,a){return this.chownSync(this.fdToPath(r,"fchownSync"),s,a)}async chownPromise(r,s,a){return this.chownSync(r,s,a)}chownSync(r,s,a){throw new Error("Unimplemented")}async renamePromise(r,s){return this.renameSync(r,s)}renameSync(r,s){throw new Error("Unimplemented")}async copyFilePromise(r,s,a){let{indexSource:n,indexDest:c,resolvedDestP:f}=this.prepareCopyFile(r,s,a),p=await this.getFileSource(n,{asyncDecompress:!0}),h=this.setFileSource(f,p);h!==c&&this.registerEntry(f,h)}copyFileSync(r,s,a=0){let{indexSource:n,indexDest:c,resolvedDestP:f}=this.prepareCopyFile(r,s,a),p=this.getFileSource(n),h=this.setFileSource(f,p);h!==c&&this.registerEntry(f,h)}prepareCopyFile(r,s,a=0){if(this.readOnly)throw or.EROFS(`copyfile '${r} -> '${s}'`);if(a&xa.constants.COPYFILE_FICLONE_FORCE)throw or.ENOSYS("unsupported clone operation",`copyfile '${r}' -> ${s}'`);let n=this.resolveFilename(`copyfile '${r} -> ${s}'`,r),c=this.entries.get(n);if(typeof c>"u")throw or.EINVAL(`copyfile '${r}' -> '${s}'`);let f=this.resolveFilename(`copyfile '${r}' -> ${s}'`,s),p=this.entries.get(f);if(a&(xa.constants.COPYFILE_EXCL|xa.constants.COPYFILE_FICLONE_FORCE)&&typeof p<"u")throw or.EEXIST(`copyfile '${r}' -> '${s}'`);return{indexSource:c,resolvedDestP:f,indexDest:p}}async appendFilePromise(r,s,a){if(this.readOnly)throw or.EROFS(`open '${r}'`);return typeof a>"u"?a={flag:"a"}:typeof a=="string"?a={flag:"a",encoding:a}:typeof a.flag>"u"&&(a={flag:"a",...a}),this.writeFilePromise(r,s,a)}appendFileSync(r,s,a={}){if(this.readOnly)throw or.EROFS(`open '${r}'`);return typeof a>"u"?a={flag:"a"}:typeof a=="string"?a={flag:"a",encoding:a}:typeof a.flag>"u"&&(a={flag:"a",...a}),this.writeFileSync(r,s,a)}fdToPath(r,s){let a=this.fds.get(r)?.p;if(typeof a>"u")throw or.EBADF(s);return a}async writeFilePromise(r,s,a){let{encoding:n,mode:c,index:f,resolvedP:p}=this.prepareWriteFile(r,a);f!==void 0&&typeof a=="object"&&a.flag&&a.flag.includes("a")&&(s=Buffer.concat([await this.getFileSource(f,{asyncDecompress:!0}),Buffer.from(s)])),n!==null&&(s=s.toString(n));let h=this.setFileSource(p,s);h!==f&&this.registerEntry(p,h),c!==null&&await this.chmodPromise(p,c)}writeFileSync(r,s,a){let{encoding:n,mode:c,index:f,resolvedP:p}=this.prepareWriteFile(r,a);f!==void 0&&typeof a=="object"&&a.flag&&a.flag.includes("a")&&(s=Buffer.concat([this.getFileSource(f),Buffer.from(s)])),n!==null&&(s=s.toString(n));let h=this.setFileSource(p,s);h!==f&&this.registerEntry(p,h),c!==null&&this.chmodSync(p,c)}prepareWriteFile(r,s){if(typeof r=="number"&&(r=this.fdToPath(r,"read")),this.readOnly)throw or.EROFS(`open '${r}'`);let a=this.resolveFilename(`open '${r}'`,r);if(this.listings.has(a))throw or.EISDIR(`open '${r}'`);let n=null,c=null;typeof s=="string"?n=s:typeof s=="object"&&({encoding:n=null,mode:c=null}=s);let f=this.entries.get(a);return{encoding:n,mode:c,resolvedP:a,index:f}}async unlinkPromise(r){return this.unlinkSync(r)}unlinkSync(r){if(this.readOnly)throw or.EROFS(`unlink '${r}'`);let s=this.resolveFilename(`unlink '${r}'`,r);if(this.listings.has(s))throw or.EISDIR(`unlink '${r}'`);let a=this.entries.get(s);if(typeof a>"u")throw or.EINVAL(`unlink '${r}'`);this.deleteEntry(s,a)}async utimesPromise(r,s,a){return this.utimesSync(r,s,a)}utimesSync(r,s,a){if(this.readOnly)throw or.EROFS(`utimes '${r}'`);let n=this.resolveFilename(`utimes '${r}'`,r);this.utimesImpl(n,a)}async lutimesPromise(r,s,a){return this.lutimesSync(r,s,a)}lutimesSync(r,s,a){if(this.readOnly)throw or.EROFS(`lutimes '${r}'`);let n=this.resolveFilename(`utimes '${r}'`,r,!1);this.utimesImpl(n,a)}utimesImpl(r,s){this.listings.has(r)&&(this.entries.has(r)||this.hydrateDirectory(r));let a=this.entries.get(r);if(a===void 0)throw new Error("Unreachable");this.zipImpl.setMtime(a,Ynt(s))}async mkdirPromise(r,s){return this.mkdirSync(r,s)}mkdirSync(r,{mode:s=493,recursive:a=!1}={}){if(a)return this.mkdirpSync(r,{chmod:s});if(this.readOnly)throw or.EROFS(`mkdir '${r}'`);let n=this.resolveFilename(`mkdir '${r}'`,r);if(this.entries.has(n)||this.listings.has(n))throw or.EEXIST(`mkdir '${r}'`);this.hydrateDirectory(n),this.chmodSync(n,s)}async rmdirPromise(r,s){return this.rmdirSync(r,s)}rmdirSync(r,{recursive:s=!1}={}){if(this.readOnly)throw or.EROFS(`rmdir '${r}'`);if(s){this.removeSync(r);return}let a=this.resolveFilename(`rmdir '${r}'`,r),n=this.listings.get(a);if(!n)throw or.ENOTDIR(`rmdir '${r}'`);if(n.size>0)throw or.ENOTEMPTY(`rmdir '${r}'`);let c=this.entries.get(a);if(typeof c>"u")throw or.EINVAL(`rmdir '${r}'`);this.deleteEntry(r,c)}async rmPromise(r,s){return this.rmSync(r,s)}rmSync(r,{recursive:s=!1}={}){if(this.readOnly)throw or.EROFS(`rm '${r}'`);if(s){this.removeSync(r);return}let a=this.resolveFilename(`rm '${r}'`,r),n=this.listings.get(a);if(!n)throw or.ENOTDIR(`rm '${r}'`);if(n.size>0)throw or.ENOTEMPTY(`rm '${r}'`);let c=this.entries.get(a);if(typeof c>"u")throw or.EINVAL(`rm '${r}'`);this.deleteEntry(r,c)}hydrateDirectory(r){let s=this.zipImpl.addDirectory(J.relative(vt.root,r));return this.registerListing(r),this.registerEntry(r,s),s}async linkPromise(r,s){return this.linkSync(r,s)}linkSync(r,s){throw or.EOPNOTSUPP(`link '${r}' -> '${s}'`)}async symlinkPromise(r,s){return this.symlinkSync(r,s)}symlinkSync(r,s){if(this.readOnly)throw or.EROFS(`symlink '${r}' -> '${s}'`);let a=this.resolveFilename(`symlink '${r}' -> '${s}'`,s);if(this.listings.has(a))throw or.EISDIR(`symlink '${r}' -> '${s}'`);if(this.entries.has(a))throw or.EEXIST(`symlink '${r}' -> '${s}'`);let n=this.setFileSource(a,r);this.registerEntry(a,n),this.zipImpl.setExternalAttributes(n,lm,(xa.constants.S_IFLNK|511)<<16),this.symlinkCount+=1}async readFilePromise(r,s){typeof s=="object"&&(s=s?s.encoding:void 0);let a=await this.readFileBuffer(r,{asyncDecompress:!0});return s?a.toString(s):a}readFileSync(r,s){typeof s=="object"&&(s=s?s.encoding:void 0);let a=this.readFileBuffer(r);return s?a.toString(s):a}readFileBuffer(r,s={asyncDecompress:!1}){typeof r=="number"&&(r=this.fdToPath(r,"read"));let a=this.resolveFilename(`open '${r}'`,r);if(!this.entries.has(a)&&!this.listings.has(a))throw or.ENOENT(`open '${r}'`);if(r[r.length-1]==="/"&&!this.listings.has(a))throw or.ENOTDIR(`open '${r}'`);if(this.listings.has(a))throw or.EISDIR("read");let n=this.entries.get(a);if(n===void 0)throw new Error("Unreachable");return this.getFileSource(n,s)}async readdirPromise(r,s){return this.readdirSync(r,s)}readdirSync(r,s){let a=this.resolveFilename(`scandir '${r}'`,r);if(!this.entries.has(a)&&!this.listings.has(a))throw or.ENOENT(`scandir '${r}'`);let n=this.listings.get(a);if(!n)throw or.ENOTDIR(`scandir '${r}'`);if(s?.recursive)if(s?.withFileTypes){let c=Array.from(n,f=>Object.assign(this.statImpl("lstat",J.join(r,f)),{name:f,path:vt.dot,parentPath:vt.dot}));for(let f of c){if(!f.isDirectory())continue;let p=J.join(f.path,f.name),h=this.listings.get(J.join(a,p));for(let E of h)c.push(Object.assign(this.statImpl("lstat",J.join(r,p,E)),{name:E,path:p,parentPath:p}))}return c}else{let c=[...n];for(let f of c){let p=this.listings.get(J.join(a,f));if(!(typeof p>"u"))for(let h of p)c.push(J.join(f,h))}return c}else return s?.withFileTypes?Array.from(n,c=>Object.assign(this.statImpl("lstat",J.join(r,c)),{name:c,path:void 0,parentPath:void 0})):[...n]}async readlinkPromise(r){let s=this.prepareReadlink(r);return(await this.getFileSource(s,{asyncDecompress:!0})).toString()}readlinkSync(r){let s=this.prepareReadlink(r);return this.getFileSource(s).toString()}prepareReadlink(r){let s=this.resolveFilename(`readlink '${r}'`,r,!1);if(!this.entries.has(s)&&!this.listings.has(s))throw or.ENOENT(`readlink '${r}'`);if(r[r.length-1]==="/"&&!this.listings.has(s))throw or.ENOTDIR(`open '${r}'`);if(this.listings.has(s))throw or.EINVAL(`readlink '${r}'`);let a=this.entries.get(s);if(a===void 0)throw new Error("Unreachable");if(!this.isSymbolicLink(a))throw or.EINVAL(`readlink '${r}'`);return a}async truncatePromise(r,s=0){let a=this.resolveFilename(`open '${r}'`,r),n=this.entries.get(a);if(typeof n>"u")throw or.EINVAL(`open '${r}'`);let c=await this.getFileSource(n,{asyncDecompress:!0}),f=Buffer.alloc(s,0);return c.copy(f),await this.writeFilePromise(r,f)}truncateSync(r,s=0){let a=this.resolveFilename(`open '${r}'`,r),n=this.entries.get(a);if(typeof n>"u")throw or.EINVAL(`open '${r}'`);let c=this.getFileSource(n),f=Buffer.alloc(s,0);return c.copy(f),this.writeFileSync(r,f)}async ftruncatePromise(r,s){return this.truncatePromise(this.fdToPath(r,"ftruncate"),s)}ftruncateSync(r,s){return this.truncateSync(this.fdToPath(r,"ftruncateSync"),s)}watch(r,s,a){let n;switch(typeof s){case"function":case"string":case"undefined":n=!0;break;default:({persistent:n=!0}=s);break}if(!n)return{on:()=>{},close:()=>{}};let c=setInterval(()=>{},24*60*60*1e3);return{on:()=>{},close:()=>{clearInterval(c)}}}watchFile(r,s,a){let n=J.resolve(vt.root,r);return sE(this,n,s,a)}unwatchFile(r,s){let a=J.resolve(vt.root,r);return md(this,a,s)}}});function Cpe(t,e,r=Buffer.alloc(0),s){let a=new As(r),n=C=>C===e||C.startsWith(`${e}/`)?C.slice(0,e.length):null,c=async(C,S)=>()=>a,f=(C,S)=>a,p={...t},h=new Yn(p),E=new e0({baseFs:h,getMountPoint:n,factoryPromise:c,factorySync:f,magicByte:21,maxAge:1/0,typeCheck:s?.typeCheck});return U2(Ipe.default,new t0(E)),a}var Ipe,wpe=Xe(()=>{Dt();Ipe=ut(Ie("fs"));vT()});var Bpe=Xe(()=>{mpe();vT();wpe()});var Oj,uv,ST,vpe=Xe(()=>{Dt();vT();Oj={CENTRAL_DIRECTORY:33639248,END_OF_CENTRAL_DIRECTORY:101010256},uv=22,ST=class t{constructor(e){this.filesShouldBeCached=!1;if("buffer"in e)throw new Error("Buffer based zip archives are not supported");if(!e.readOnly)throw new Error("Writable zip archives are not supported");this.baseFs=e.baseFs,this.fd=this.baseFs.openSync(e.path,"r");try{this.entries=t.readZipSync(this.fd,this.baseFs,e.size)}catch(r){throw this.baseFs.closeSync(this.fd),this.fd="closed",r}}static readZipSync(e,r,s){if(s=0;N--)if(n.readUInt32LE(N)===Oj.END_OF_CENTRAL_DIRECTORY){a=N;break}if(a===-1)throw new Error("Not a zip archive")}let c=n.readUInt16LE(a+10),f=n.readUInt32LE(a+12),p=n.readUInt32LE(a+16),h=n.readUInt16LE(a+20);if(a+h+uv>n.length)throw new Error("Zip archive inconsistent");if(c==65535||f==4294967295||p==4294967295)throw new Error("Zip 64 is not supported");if(f>s)throw new Error("Zip archive inconsistent");if(c>f/46)throw new Error("Zip archive inconsistent");let E=Buffer.alloc(f);if(r.readSync(e,E,0,E.length,p)!==E.length)throw new Error("Zip archive inconsistent");let C=[],S=0,P=0,I=0;for(;PE.length)throw new Error("Zip archive inconsistent");if(E.readUInt32LE(S)!==Oj.CENTRAL_DIRECTORY)throw new Error("Zip archive inconsistent");let N=E.readUInt16LE(S+4)>>>8;if(E.readUInt16LE(S+8)&1)throw new Error("Encrypted zip files are not supported");let W=E.readUInt16LE(S+10),ee=E.readUInt32LE(S+16),ie=E.readUInt16LE(S+28),ue=E.readUInt16LE(S+30),le=E.readUInt16LE(S+32),me=E.readUInt32LE(S+42),pe=E.toString("utf8",S+46,S+46+ie).replaceAll("\0"," ");if(pe.includes("\0"))throw new Error("Invalid ZIP file");let Be=E.readUInt32LE(S+20),Ce=E.readUInt32LE(S+38);C.push({name:pe,os:N,mtime:fi.SAFE_TIME,crc:ee,compressionMethod:W,isSymbolicLink:N===lm&&(Ce>>>16&fi.S_IFMT)===fi.S_IFLNK,size:E.readUInt32LE(S+24),compressedSize:Be,externalAttributes:Ce,localHeaderOffset:me}),I+=Be,P+=1,S+=46+ie+ue+le}if(I>s)throw new Error("Zip archive inconsistent");if(S!==E.length)throw new Error("Zip archive inconsistent");return C}getExternalAttributes(e){let r=this.entries[e];return[r.os,r.externalAttributes]}getListings(){return this.entries.map(e=>e.name)}getSymlinkCount(){let e=0;for(let r of this.entries)r.isSymbolicLink&&(e+=1);return e}stat(e){let r=this.entries[e];return{crc:r.crc,mtime:r.mtime,size:r.size}}locate(e){for(let r=0;rEpe,DEFLATE:()=>Nj,JsZipImpl:()=>ST,LibZipImpl:()=>BI,STORE:()=>Fj,ZIP_UNIX:()=>lm,ZipFS:()=>As,ZipOpenFS:()=>$f,getArchivePart:()=>xj,getLibzipPromise:()=>Jnt,getLibzipSync:()=>Vnt,makeEmptyArchive:()=>BT,mountMemoryDrive:()=>Cpe});function Vnt(){return cv()}async function Jnt(){return cv()}var Spe,eA=Xe(()=>{Dj();Spe=ut(ppe());dpe();Bpe();vpe();Qj();Ape(()=>{let t=(0,Spe.default)();return gpe(t)})});var Av,Dpe=Xe(()=>{Dt();Yt();pv();Av=class extends ot{constructor(){super(...arguments);this.cwd=ge.String("--cwd",process.cwd(),{description:"The directory to run the command in"});this.commandName=ge.String();this.args=ge.Proxy()}static{this.usage={description:"run a command using yarn's portable shell",details:` + This command will run a command using Yarn's portable shell. + + Make sure to escape glob patterns, redirections, and other features that might be expanded by your own shell. + + Note: To escape something from Yarn's shell, you might have to escape it twice, the first time from your own shell. + + Note: Don't use this command in Yarn scripts, as Yarn's shell is automatically used. + + For a list of features, visit: https://github.com/yarnpkg/berry/blob/master/packages/yarnpkg-shell/README.md. + `,examples:[["Run a simple command","$0 echo Hello"],["Run a command with a glob pattern","$0 echo '*.js'"],["Run a command with a redirection","$0 echo Hello World '>' hello.txt"],["Run a command with an escaped glob pattern (The double escape is needed in Unix shells)",`$0 echo '"*.js"'`],["Run a command with a variable (Double quotes are needed in Unix shells, to prevent them from expanding the variable)",'$0 "GREETING=Hello echo $GREETING World"']]}}async execute(){let r=this.args.length>0?`${this.commandName} ${this.args.join(" ")}`:this.commandName;return await vI(r,[],{cwd:fe.toPortablePath(this.cwd),stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr})}}});var Vl,bpe=Xe(()=>{Vl=class extends Error{constructor(e){super(e),this.name="ShellError"}}});var PT={};Vt(PT,{fastGlobOptions:()=>kpe,isBraceExpansion:()=>Lj,isGlobPattern:()=>Knt,match:()=>znt,micromatchOptions:()=>bT});function Knt(t){if(!DT.default.scan(t,bT).isGlob)return!1;try{DT.default.parse(t,bT)}catch{return!1}return!0}function znt(t,{cwd:e,baseFs:r}){return(0,Ppe.default)(t,{...kpe,cwd:fe.fromPortablePath(e),fs:ax(xpe.default,new t0(r))})}function Lj(t){return DT.default.scan(t,bT).isBrace}var Ppe,xpe,DT,bT,kpe,Qpe=Xe(()=>{Dt();Ppe=ut(BQ()),xpe=ut(Ie("fs")),DT=ut(Go()),bT={strictBrackets:!0},kpe={onlyDirectories:!1,onlyFiles:!1}});function Mj(){}function Uj(){for(let t of cm)t.kill()}function Npe(t,e,r,s){return a=>{let n=a[0]instanceof tA.Transform?"pipe":a[0],c=a[1]instanceof tA.Transform?"pipe":a[1],f=a[2]instanceof tA.Transform?"pipe":a[2],p=(0,Rpe.default)(t,e,{...s,stdio:[n,c,f]});return cm.add(p),cm.size===1&&(process.on("SIGINT",Mj),process.on("SIGTERM",Uj)),a[0]instanceof tA.Transform&&a[0].pipe(p.stdin),a[1]instanceof tA.Transform&&p.stdout.pipe(a[1],{end:!1}),a[2]instanceof tA.Transform&&p.stderr.pipe(a[2],{end:!1}),{stdin:p.stdin,promise:new Promise(h=>{p.on("error",E=>{switch(cm.delete(p),cm.size===0&&(process.off("SIGINT",Mj),process.off("SIGTERM",Uj)),E.code){case"ENOENT":a[2].write(`command not found: ${t} +`),h(127);break;case"EACCES":a[2].write(`permission denied: ${t} +`),h(128);break;default:a[2].write(`uncaught error: ${E.message} +`),h(1);break}}),p.on("close",E=>{cm.delete(p),cm.size===0&&(process.off("SIGINT",Mj),process.off("SIGTERM",Uj)),h(E!==null?E:129)})})}}}function Ope(t){return e=>{let r=e[0]==="pipe"?new tA.PassThrough:e[0];return{stdin:r,promise:Promise.resolve().then(()=>t({stdin:r,stdout:e[1],stderr:e[2]}))}}}function xT(t,e){return Hj.start(t,e)}function Tpe(t,e=null){let r=new tA.PassThrough,s=new Fpe.StringDecoder,a="";return r.on("data",n=>{let c=s.write(n),f;do if(f=c.indexOf(` +`),f!==-1){let p=a+c.substring(0,f);c=c.substring(f+1),a="",t(e!==null?`${e} ${p}`:p)}while(f!==-1);a+=c}),r.on("end",()=>{let n=s.end();n!==""&&t(e!==null?`${e} ${n}`:n)}),r}function Lpe(t,{prefix:e}){return{stdout:Tpe(r=>t.stdout.write(`${r} +`),t.stdout.isTTY?e:null),stderr:Tpe(r=>t.stderr.write(`${r} +`),t.stderr.isTTY?e:null)}}var Rpe,tA,Fpe,cm,Oc,_j,Hj,jj=Xe(()=>{Rpe=ut(_U()),tA=Ie("stream"),Fpe=Ie("string_decoder"),cm=new Set;Oc=class{constructor(e){this.stream=e}close(){}get(){return this.stream}},_j=class{constructor(){this.stream=null}close(){if(this.stream===null)throw new Error("Assertion failed: No stream attached");this.stream.end()}attach(e){this.stream=e}get(){if(this.stream===null)throw new Error("Assertion failed: No stream attached");return this.stream}},Hj=class t{constructor(e,r){this.stdin=null;this.stdout=null;this.stderr=null;this.pipe=null;this.ancestor=e,this.implementation=r}static start(e,{stdin:r,stdout:s,stderr:a}){let n=new t(null,e);return n.stdin=r,n.stdout=s,n.stderr=a,n}pipeTo(e,r=1){let s=new t(this,e),a=new _j;return s.pipe=a,s.stdout=this.stdout,s.stderr=this.stderr,(r&1)===1?this.stdout=a:this.ancestor!==null&&(this.stderr=this.ancestor.stdout),(r&2)===2?this.stderr=a:this.ancestor!==null&&(this.stderr=this.ancestor.stderr),s}async exec(){let e=["ignore","ignore","ignore"];if(this.pipe)e[0]="pipe";else{if(this.stdin===null)throw new Error("Assertion failed: No input stream registered");e[0]=this.stdin.get()}let r;if(this.stdout===null)throw new Error("Assertion failed: No output stream registered");r=this.stdout,e[1]=r.get();let s;if(this.stderr===null)throw new Error("Assertion failed: No error stream registered");s=this.stderr,e[2]=s.get();let a=this.implementation(e);return this.pipe&&this.pipe.attach(a.stdin),await a.promise.then(n=>(r.close(),s.close(),n))}async run(){let e=[];for(let s=this;s;s=s.ancestor)e.push(s.exec());return(await Promise.all(e))[0]}}});var mv={};Vt(mv,{EntryCommand:()=>Av,ShellError:()=>Vl,execute:()=>vI,globUtils:()=>PT});function Mpe(t,e,r){let s=new Jl.PassThrough({autoDestroy:!0});switch(t){case 0:(e&1)===1&&r.stdin.pipe(s,{end:!1}),(e&2)===2&&r.stdin instanceof Jl.Writable&&s.pipe(r.stdin,{end:!1});break;case 1:(e&1)===1&&r.stdout.pipe(s,{end:!1}),(e&2)===2&&s.pipe(r.stdout,{end:!1});break;case 2:(e&1)===1&&r.stderr.pipe(s,{end:!1}),(e&2)===2&&s.pipe(r.stderr,{end:!1});break;default:throw new Vl(`Bad file descriptor: "${t}"`)}return s}function QT(t,e={}){let r={...t,...e};return r.environment={...t.environment,...e.environment},r.variables={...t.variables,...e.variables},r}async function Znt(t,e,r){let s=[],a=new Jl.PassThrough;return a.on("data",n=>s.push(n)),await TT(t,e,QT(r,{stdout:a})),Buffer.concat(s).toString().replace(/[\r\n]+$/,"")}async function Upe(t,e,r){let s=t.map(async n=>{let c=await um(n.args,e,r);return{name:n.name,value:c.join(" ")}});return(await Promise.all(s)).reduce((n,c)=>(n[c.name]=c.value,n),{})}function kT(t){return t.match(/[^ \r\n\t]+/g)||[]}async function Wpe(t,e,r,s,a=s){switch(t.name){case"$":s(String(process.pid));break;case"#":s(String(e.args.length));break;case"@":if(t.quoted)for(let n of e.args)a(n);else for(let n of e.args){let c=kT(n);for(let f=0;f=0&&n"u"&&(t.defaultValue?c=(await um(t.defaultValue,e,r)).join(" "):t.alternativeValue&&(c="")),typeof c>"u")throw f?new Vl(`Unbound argument #${n}`):new Vl(`Unbound variable "${t.name}"`);if(t.quoted)s(c);else{let p=kT(c);for(let E=0;Es.push(n));let a=Number(s.join(" "));return Number.isNaN(a)?hv({type:"variable",name:s.join(" ")},e,r):hv({type:"number",value:a},e,r)}else return $nt[t.type](await hv(t.left,e,r),await hv(t.right,e,r))}async function um(t,e,r){let s=new Map,a=[],n=[],c=E=>{n.push(E)},f=()=>{n.length>0&&a.push(n.join("")),n=[]},p=E=>{c(E),f()},h=(E,C,S)=>{let P=JSON.stringify({type:E,fd:C}),I=s.get(P);typeof I>"u"&&s.set(P,I=[]),I.push(S)};for(let E of t){let C=!1;switch(E.type){case"redirection":{let S=await um(E.args,e,r);for(let P of S)h(E.subtype,E.fd,P)}break;case"argument":for(let S of E.segments)switch(S.type){case"text":c(S.text);break;case"glob":c(S.pattern),C=!0;break;case"shell":{let P=await Znt(S.shell,e,r);if(S.quoted)c(P);else{let I=kT(P);for(let R=0;R"u")throw new Error("Assertion failed: Expected a glob pattern to have been set");let P=await e.glob.match(S,{cwd:r.cwd,baseFs:e.baseFs});if(P.length===0){let I=Lj(S)?". Note: Brace expansion of arbitrary strings isn't currently supported. For more details, please read this issue: https://github.com/yarnpkg/berry/issues/22":"";throw new Vl(`No matches found: "${S}"${I}`)}for(let I of P.sort())p(I)}}if(s.size>0){let E=[];for(let[C,S]of s.entries())E.splice(E.length,0,C,String(S.length),...S);a.splice(0,0,"__ysh_set_redirects",...E,"--")}return a}function gv(t,e,r){e.builtins.has(t[0])||(t=["command",...t]);let s=fe.fromPortablePath(r.cwd),a=r.environment;typeof a.PWD<"u"&&(a={...a,PWD:s});let[n,...c]=t;if(n==="command")return Npe(c[0],c.slice(1),e,{cwd:s,env:a});let f=e.builtins.get(n);if(typeof f>"u")throw new Error(`Assertion failed: A builtin should exist for "${n}"`);return Ope(async({stdin:p,stdout:h,stderr:E})=>{let{stdin:C,stdout:S,stderr:P}=r;r.stdin=p,r.stdout=h,r.stderr=E;try{return await f(c,e,r)}finally{r.stdin=C,r.stdout=S,r.stderr=P}})}function eit(t,e,r){return s=>{let a=new Jl.PassThrough,n=TT(t,e,QT(r,{stdin:a}));return{stdin:a,promise:n}}}function tit(t,e,r){return s=>{let a=new Jl.PassThrough,n=TT(t,e,r);return{stdin:a,promise:n}}}function _pe(t,e,r,s){if(e.length===0)return t;{let a;do a=String(Math.random());while(Object.hasOwn(s.procedures,a));return s.procedures={...s.procedures},s.procedures[a]=t,gv([...e,"__ysh_run_procedure",a],r,s)}}async function Hpe(t,e,r){let s=t,a=null,n=null;for(;s;){let c=s.then?{...r}:r,f;switch(s.type){case"command":{let p=await um(s.args,e,r),h=await Upe(s.envs,e,r);f=s.envs.length?gv(p,e,QT(c,{environment:h})):gv(p,e,c)}break;case"subshell":{let p=await um(s.args,e,r),h=eit(s.subshell,e,c);f=_pe(h,p,e,c)}break;case"group":{let p=await um(s.args,e,r),h=tit(s.group,e,c);f=_pe(h,p,e,c)}break;case"envs":{let p=await Upe(s.envs,e,r);c.environment={...c.environment,...p},f=gv(["true"],e,c)}break}if(typeof f>"u")throw new Error("Assertion failed: An action should have been generated");if(a===null)n=xT(f,{stdin:new Oc(c.stdin),stdout:new Oc(c.stdout),stderr:new Oc(c.stderr)});else{if(n===null)throw new Error("Assertion failed: The execution pipeline should have been setup");switch(a){case"|":n=n.pipeTo(f,1);break;case"|&":n=n.pipeTo(f,3);break}}s.then?(a=s.then.type,s=s.then.chain):s=null}if(n===null)throw new Error("Assertion failed: The execution pipeline should have been setup");return await n.run()}async function rit(t,e,r,{background:s=!1}={}){function a(n){let c=["#2E86AB","#A23B72","#F18F01","#C73E1D","#CCE2A3"],f=c[n%c.length];return jpe.default.hex(f)}if(s){let n=r.nextBackgroundJobIndex++,c=a(n),f=`[${n}]`,p=c(f),{stdout:h,stderr:E}=Lpe(r,{prefix:p});return r.backgroundJobs.push(Hpe(t,e,QT(r,{stdout:h,stderr:E})).catch(C=>E.write(`${C.message} +`)).finally(()=>{r.stdout.isTTY&&r.stdout.write(`Job ${p}, '${c(AE(t))}' has ended +`)})),0}return await Hpe(t,e,r)}async function nit(t,e,r,{background:s=!1}={}){let a,n=f=>{a=f,r.variables["?"]=String(f)},c=async f=>{try{return await rit(f.chain,e,r,{background:s&&typeof f.then>"u"})}catch(p){if(!(p instanceof Vl))throw p;return r.stderr.write(`${p.message} +`),1}};for(n(await c(t));t.then;){if(r.exitCode!==null)return r.exitCode;switch(t.then.type){case"&&":a===0&&n(await c(t.then.line));break;case"||":a!==0&&n(await c(t.then.line));break;default:throw new Error(`Assertion failed: Unsupported command type: "${t.then.type}"`)}t=t.then.line}return a}async function TT(t,e,r){let s=r.backgroundJobs;r.backgroundJobs=[];let a=0;for(let{command:n,type:c}of t){if(a=await nit(n,e,r,{background:c==="&"}),r.exitCode!==null)return r.exitCode;r.variables["?"]=String(a)}return await Promise.all(r.backgroundJobs),r.backgroundJobs=s,a}function Ype(t){switch(t.type){case"variable":return t.name==="@"||t.name==="#"||t.name==="*"||Number.isFinite(parseInt(t.name,10))||"defaultValue"in t&&!!t.defaultValue&&t.defaultValue.some(e=>dv(e))||"alternativeValue"in t&&!!t.alternativeValue&&t.alternativeValue.some(e=>dv(e));case"arithmetic":return Gj(t.arithmetic);case"shell":return qj(t.shell);default:return!1}}function dv(t){switch(t.type){case"redirection":return t.args.some(e=>dv(e));case"argument":return t.segments.some(e=>Ype(e));default:throw new Error(`Assertion failed: Unsupported argument type: "${t.type}"`)}}function Gj(t){switch(t.type){case"variable":return Ype(t);case"number":return!1;default:return Gj(t.left)||Gj(t.right)}}function qj(t){return t.some(({command:e})=>{for(;e;){let r=e.chain;for(;r;){let s;switch(r.type){case"subshell":s=qj(r.subshell);break;case"command":s=r.envs.some(a=>a.args.some(n=>dv(n)))||r.args.some(a=>dv(a));break}if(s)return!0;if(!r.then)break;r=r.then.chain}if(!e.then)break;e=e.then.line}return!1})}async function vI(t,e=[],{baseFs:r=new Yn,builtins:s={},cwd:a=fe.toPortablePath(process.cwd()),env:n=process.env,stdin:c=process.stdin,stdout:f=process.stdout,stderr:p=process.stderr,variables:h={},glob:E=PT}={}){let C={};for(let[I,R]of Object.entries(n))typeof R<"u"&&(C[I]=R);let S=new Map(Xnt);for(let[I,R]of Object.entries(s))S.set(I,R);c===null&&(c=new Jl.PassThrough,c.end());let P=ux(t,E);if(!qj(P)&&P.length>0&&e.length>0){let{command:I}=P[P.length-1];for(;I.then;)I=I.then.line;let R=I.chain;for(;R.then;)R=R.then.chain;R.type==="command"&&(R.args=R.args.concat(e.map(N=>({type:"argument",segments:[{type:"text",text:N}]}))))}return await TT(P,{args:e,baseFs:r,builtins:S,initialStdin:c,initialStdout:f,initialStderr:p,glob:E},{cwd:a,environment:C,exitCode:null,procedures:{},stdin:c,stdout:f,stderr:p,variables:Object.assign({},h,{"?":0}),nextBackgroundJobIndex:1,backgroundJobs:[]})}var jpe,Gpe,Jl,qpe,Xnt,$nt,pv=Xe(()=>{Dt();wc();jpe=ut(TE()),Gpe=Ie("os"),Jl=Ie("stream"),qpe=Ie("timers/promises");Dpe();bpe();Qpe();jj();jj();Xnt=new Map([["cd",async([t=(0,Gpe.homedir)(),...e],r,s)=>{let a=J.resolve(s.cwd,fe.toPortablePath(t));if(!(await r.baseFs.statPromise(a).catch(c=>{throw c.code==="ENOENT"?new Vl(`cd: no such file or directory: ${t}`):c})).isDirectory())throw new Vl(`cd: not a directory: ${t}`);return s.cwd=a,0}],["pwd",async(t,e,r)=>(r.stdout.write(`${fe.fromPortablePath(r.cwd)} +`),0)],[":",async(t,e,r)=>0],["true",async(t,e,r)=>0],["false",async(t,e,r)=>1],["exit",async([t,...e],r,s)=>s.exitCode=parseInt(t??s.variables["?"],10)],["echo",async(t,e,r)=>(r.stdout.write(`${t.join(" ")} +`),0)],["sleep",async([t],e,r)=>{if(typeof t>"u")throw new Vl("sleep: missing operand");let s=Number(t);if(Number.isNaN(s))throw new Vl(`sleep: invalid time interval '${t}'`);return await(0,qpe.setTimeout)(1e3*s,0)}],["unset",async(t,e,r)=>{for(let s of t)delete r.environment[s],delete r.variables[s];return 0}],["__ysh_run_procedure",async(t,e,r)=>{let s=r.procedures[t[0]];return await xT(s,{stdin:new Oc(r.stdin),stdout:new Oc(r.stdout),stderr:new Oc(r.stderr)}).run()}],["__ysh_set_redirects",async(t,e,r)=>{let s=r.stdin,a=r.stdout,n=r.stderr,c=[],f=[],p=[],h=0;for(;t[h]!=="--";){let C=t[h++],{type:S,fd:P}=JSON.parse(C),I=W=>{switch(P){case null:case 0:c.push(W);break;default:throw new Error(`Unsupported file descriptor: "${P}"`)}},R=W=>{switch(P){case null:case 1:f.push(W);break;case 2:p.push(W);break;default:throw new Error(`Unsupported file descriptor: "${P}"`)}},N=Number(t[h++]),U=h+N;for(let W=h;We.baseFs.createReadStream(J.resolve(r.cwd,fe.toPortablePath(t[W]))));break;case"<<<":I(()=>{let ee=new Jl.PassThrough;return process.nextTick(()=>{ee.write(`${t[W]} +`),ee.end()}),ee});break;case"<&":I(()=>Mpe(Number(t[W]),1,r));break;case">":case">>":{let ee=J.resolve(r.cwd,fe.toPortablePath(t[W]));R(ee==="/dev/null"?new Jl.Writable({autoDestroy:!0,emitClose:!0,write(ie,ue,le){setImmediate(le)}}):e.baseFs.createWriteStream(ee,S===">>"?{flags:"a"}:void 0))}break;case">&":R(Mpe(Number(t[W]),2,r));break;default:throw new Error(`Assertion failed: Unsupported redirection type: "${S}"`)}}if(c.length>0){let C=new Jl.PassThrough;s=C;let S=P=>{if(P===c.length)C.end();else{let I=c[P]();I.pipe(C,{end:!1}),I.on("end",()=>{S(P+1)})}};S(0)}if(f.length>0){let C=new Jl.PassThrough;a=C;for(let S of f)C.pipe(S)}if(p.length>0){let C=new Jl.PassThrough;n=C;for(let S of p)C.pipe(S)}let E=await xT(gv(t.slice(h+1),e,r),{stdin:new Oc(s),stdout:new Oc(a),stderr:new Oc(n)}).run();return await Promise.all(f.map(C=>new Promise((S,P)=>{C.on("error",I=>{P(I)}),C.on("close",()=>{S()}),C.end()}))),await Promise.all(p.map(C=>new Promise((S,P)=>{C.on("error",I=>{P(I)}),C.on("close",()=>{S()}),C.end()}))),E}]]);$nt={addition:(t,e)=>t+e,subtraction:(t,e)=>t-e,multiplication:(t,e)=>t*e,division:(t,e)=>Math.trunc(t/e)}});var Vpe=_((S4t,RT)=>{function iit(){var t=0,e=1,r=2,s=3,a=4,n=5,c=6,f=7,p=8,h=9,E=10,C=11,S=12,P=13,I=14,R=15,N=16,U=17,W=0,ee=1,ie=2,ue=3,le=4;function me(g,we){return 55296<=g.charCodeAt(we)&&g.charCodeAt(we)<=56319&&56320<=g.charCodeAt(we+1)&&g.charCodeAt(we+1)<=57343}function pe(g,we){we===void 0&&(we=0);var ye=g.charCodeAt(we);if(55296<=ye&&ye<=56319&&we=1){var Ae=g.charCodeAt(we-1),se=ye;return 55296<=Ae&&Ae<=56319?(Ae-55296)*1024+(se-56320)+65536:se}return ye}function Be(g,we,ye){var Ae=[g].concat(we).concat([ye]),se=Ae[Ae.length-2],Z=ye,De=Ae.lastIndexOf(I);if(De>1&&Ae.slice(1,De).every(function(j){return j==s})&&[s,P,U].indexOf(g)==-1)return ie;var Re=Ae.lastIndexOf(a);if(Re>0&&Ae.slice(1,Re).every(function(j){return j==a})&&[S,a].indexOf(se)==-1)return Ae.filter(function(j){return j==a}).length%2==1?ue:le;if(se==t&&Z==e)return W;if(se==r||se==t||se==e)return Z==I&&we.every(function(j){return j==s})?ie:ee;if(Z==r||Z==t||Z==e)return ee;if(se==c&&(Z==c||Z==f||Z==h||Z==E))return W;if((se==h||se==f)&&(Z==f||Z==p))return W;if((se==E||se==p)&&Z==p)return W;if(Z==s||Z==R)return W;if(Z==n)return W;if(se==S)return W;var mt=Ae.indexOf(s)!=-1?Ae.lastIndexOf(s)-1:Ae.length-2;return[P,U].indexOf(Ae[mt])!=-1&&Ae.slice(mt+1,-1).every(function(j){return j==s})&&Z==I||se==R&&[N,U].indexOf(Z)!=-1?W:we.indexOf(a)!=-1?ie:se==a&&Z==a?W:ee}this.nextBreak=function(g,we){if(we===void 0&&(we=0),we<0)return 0;if(we>=g.length-1)return g.length;for(var ye=Ce(pe(g,we)),Ae=[],se=we+1;se{var sit=/^(.*?)(\x1b\[[^m]+m|\x1b\]8;;.*?(\x1b\\|\u0007))/,FT;function oit(){if(FT)return FT;if(typeof Intl.Segmenter<"u"){let t=new Intl.Segmenter("en",{granularity:"grapheme"});return FT=e=>Array.from(t.segment(e),({segment:r})=>r)}else{let t=Vpe(),e=new t;return FT=r=>e.splitGraphemes(r)}}Jpe.exports=(t,e=0,r=t.length)=>{if(e<0||r<0)throw new RangeError("Negative indices aren't supported by this implementation");let s=r-e,a="",n=0,c=0;for(;t.length>0;){let f=t.match(sit)||[t,t,void 0],p=oit()(f[1]),h=Math.min(e-n,p.length);p=p.slice(h);let E=Math.min(s-c,p.length);a+=p.slice(0,E).join(""),n+=h,c+=E,typeof f[2]<"u"&&(a+=f[2]),t=t.slice(f[0].length)}return a}});var fn,yv=Xe(()=>{fn=process.env.YARN_IS_TEST_ENV?"0.0.0":"4.12.0"});function the(t,{configuration:e,json:r}){if(!e.get("enableMessageNames"))return"";let a=Yf(t===null?0:t);return!r&&t===null?Ht(e,a,"grey"):a}function Wj(t,{configuration:e,json:r}){let s=the(t,{configuration:e,json:r});if(!s||t===null||t===0)return s;let a=Br[t],n=`https://yarnpkg.com/advanced/error-codes#${s}---${a}`.toLowerCase();return KE(e,s,n)}async function SI({configuration:t,stdout:e,forceError:r},s){let a=await Ot.start({configuration:t,stdout:e,includeFooter:!1},async n=>{let c=!1,f=!1;for(let p of s)typeof p.option<"u"&&(p.error||r?(f=!0,n.reportError(50,p.message)):(c=!0,n.reportWarning(50,p.message)),p.callback?.());c&&!f&&n.reportSeparator()});return a.hasErrors()?a.exitCode():null}var $pe,NT,ait,zpe,Xpe,D0,ehe,Zpe,lit,cit,OT,uit,Ot,Ev=Xe(()=>{$pe=ut(Kpe()),NT=ut(Fd());Gx();Tc();yv();xc();ait="\xB7",zpe=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],Xpe=80,D0=NT.default.GITHUB_ACTIONS?{start:t=>`::group::${t} +`,end:t=>`::endgroup:: +`}:NT.default.TRAVIS?{start:t=>`travis_fold:start:${t} +`,end:t=>`travis_fold:end:${t} +`}:NT.default.GITLAB?{start:t=>`section_start:${Math.floor(Date.now()/1e3)}:${t.toLowerCase().replace(/\W+/g,"_")}[collapsed=true]\r\x1B[0K${t} +`,end:t=>`section_end:${Math.floor(Date.now()/1e3)}:${t.toLowerCase().replace(/\W+/g,"_")}\r\x1B[0K`}:null,ehe=D0!==null,Zpe=new Date,lit=["iTerm.app","Apple_Terminal","WarpTerminal","vscode"].includes(process.env.TERM_PROGRAM)||!!process.env.WT_SESSION,cit=t=>t,OT=cit({patrick:{date:[17,3],chars:["\u{1F340}","\u{1F331}"],size:40},simba:{date:[19,7],chars:["\u{1F981}","\u{1F334}"],size:40},jack:{date:[31,10],chars:["\u{1F383}","\u{1F987}"],size:40},hogsfather:{date:[31,12],chars:["\u{1F389}","\u{1F384}"],size:40},default:{chars:["=","-"],size:80}}),uit=lit&&Object.keys(OT).find(t=>{let e=OT[t];return!(e.date&&(e.date[0]!==Zpe.getDate()||e.date[1]!==Zpe.getMonth()+1))})||"default";Ot=class extends Ao{constructor({configuration:r,stdout:s,json:a=!1,forceSectionAlignment:n=!1,includeNames:c=!0,includePrefix:f=!0,includeFooter:p=!0,includeLogs:h=!a,includeInfos:E=h,includeWarnings:C=h}){super();this.uncommitted=new Set;this.warningCount=0;this.errorCount=0;this.timerFooter=[];this.startTime=Date.now();this.indent=0;this.level=0;this.progress=new Map;this.progressTime=0;this.progressFrame=0;this.progressTimeout=null;this.progressStyle=null;this.progressMaxScaledSize=null;if(RB(this,{configuration:r}),this.configuration=r,this.forceSectionAlignment=n,this.includeNames=c,this.includePrefix=f,this.includeFooter=p,this.includeInfos=E,this.includeWarnings=C,this.json=a,this.stdout=s,r.get("enableProgressBars")&&!a&&s.isTTY&&s.columns>22){let S=r.get("progressBarStyle")||uit;if(!Object.hasOwn(OT,S))throw new Error("Assertion failed: Invalid progress bar style");this.progressStyle=OT[S];let P=Math.min(this.getRecommendedLength(),80);this.progressMaxScaledSize=Math.floor(this.progressStyle.size*P/80)}}static async start(r,s){let a=new this(r),n=process.emitWarning;process.emitWarning=(c,f)=>{if(typeof c!="string"){let h=c;c=h.message,f=f??h.name}let p=typeof f<"u"?`${f}: ${c}`:c;a.reportWarning(0,p)},r.includeVersion&&a.reportInfo(0,zd(r.configuration,`Yarn ${fn}`,2));try{await s(a)}catch(c){a.reportExceptionOnce(c)}finally{await a.finalize(),process.emitWarning=n}return a}hasErrors(){return this.errorCount>0}exitCode(){return this.hasErrors()?1:0}getRecommendedLength(){let s=this.progressStyle!==null?this.stdout.columns-1:super.getRecommendedLength();return Math.max(40,s-12-this.indent*2)}startSectionSync({reportHeader:r,reportFooter:s,skipIfEmpty:a},n){let c={committed:!1,action:()=>{r?.()}};a?this.uncommitted.add(c):(c.action(),c.committed=!0);let f=Date.now();try{return n()}catch(p){throw this.reportExceptionOnce(p),p}finally{let p=Date.now();this.uncommitted.delete(c),c.committed&&s?.(p-f)}}async startSectionPromise({reportHeader:r,reportFooter:s,skipIfEmpty:a},n){let c={committed:!1,action:()=>{r?.()}};a?this.uncommitted.add(c):(c.action(),c.committed=!0);let f=Date.now();try{return await n()}catch(p){throw this.reportExceptionOnce(p),p}finally{let p=Date.now();this.uncommitted.delete(c),c.committed&&s?.(p-f)}}startTimerImpl(r,s,a){return{cb:typeof s=="function"?s:a,reportHeader:()=>{this.level+=1,this.reportInfo(null,`\u250C ${r}`),this.indent+=1,D0!==null&&!this.json&&this.includeInfos&&this.stdout.write(D0.start(r))},reportFooter:f=>{if(this.indent-=1,D0!==null&&!this.json&&this.includeInfos){this.stdout.write(D0.end(r));for(let p of this.timerFooter)p()}this.configuration.get("enableTimers")&&f>200?this.reportInfo(null,`\u2514 Completed in ${Ht(this.configuration,f,ht.DURATION)}`):this.reportInfo(null,"\u2514 Completed"),this.level-=1},skipIfEmpty:(typeof s=="function"?{}:s).skipIfEmpty}}startTimerSync(r,s,a){let{cb:n,...c}=this.startTimerImpl(r,s,a);return this.startSectionSync(c,n)}async startTimerPromise(r,s,a){let{cb:n,...c}=this.startTimerImpl(r,s,a);return this.startSectionPromise(c,n)}reportSeparator(){this.indent===0?this.writeLine(""):this.reportInfo(null,"")}reportInfo(r,s){if(!this.includeInfos)return;this.commit();let a=this.formatNameWithHyperlink(r),n=a?`${a}: `:"",c=`${this.formatPrefix(n,"blueBright")}${s}`;this.json?this.reportJson({type:"info",name:r,displayName:this.formatName(r),indent:this.formatIndent(),data:s}):this.writeLine(c)}reportWarning(r,s){if(this.warningCount+=1,!this.includeWarnings)return;this.commit();let a=this.formatNameWithHyperlink(r),n=a?`${a}: `:"";this.json?this.reportJson({type:"warning",name:r,displayName:this.formatName(r),indent:this.formatIndent(),data:s}):this.writeLine(`${this.formatPrefix(n,"yellowBright")}${s}`)}reportError(r,s){this.errorCount+=1,this.timerFooter.push(()=>this.reportErrorImpl(r,s)),this.reportErrorImpl(r,s)}reportErrorImpl(r,s){this.commit();let a=this.formatNameWithHyperlink(r),n=a?`${a}: `:"";this.json?this.reportJson({type:"error",name:r,displayName:this.formatName(r),indent:this.formatIndent(),data:s}):this.writeLine(`${this.formatPrefix(n,"redBright")}${s}`,{truncate:!1})}reportFold(r,s){if(!D0)return;let a=`${D0.start(r)}${s}${D0.end(r)}`;this.timerFooter.push(()=>this.stdout.write(a))}reportProgress(r){if(this.progressStyle===null)return{...Promise.resolve(),stop:()=>{}};if(r.hasProgress&&r.hasTitle)throw new Error("Unimplemented: Progress bars can't have both progress and titles.");let s=!1,a=Promise.resolve().then(async()=>{let c={progress:r.hasProgress?0:void 0,title:r.hasTitle?"":void 0};this.progress.set(r,{definition:c,lastScaledSize:r.hasProgress?-1:void 0,lastTitle:void 0}),this.refreshProgress({delta:-1});for await(let{progress:f,title:p}of r)s||c.progress===f&&c.title===p||(c.progress=f,c.title=p,this.refreshProgress());n()}),n=()=>{s||(s=!0,this.progress.delete(r),this.refreshProgress({delta:1}))};return{...a,stop:n}}reportJson(r){this.json&&this.writeLine(`${JSON.stringify(r)}`)}async finalize(){if(!this.includeFooter)return;let r="";this.errorCount>0?r="Failed with errors":this.warningCount>0?r="Done with warnings":r="Done";let s=Ht(this.configuration,Date.now()-this.startTime,ht.DURATION),a=this.configuration.get("enableTimers")?`${r} in ${s}`:r;this.errorCount>0?this.reportError(0,a):this.warningCount>0?this.reportWarning(0,a):this.reportInfo(0,a)}writeLine(r,{truncate:s}={}){this.clearProgress({clear:!0}),this.stdout.write(`${this.truncate(r,{truncate:s})} +`),this.writeProgress()}writeLines(r,{truncate:s}={}){this.clearProgress({delta:r.length});for(let a of r)this.stdout.write(`${this.truncate(a,{truncate:s})} +`);this.writeProgress()}commit(){let r=this.uncommitted;this.uncommitted=new Set;for(let s of r)s.committed=!0,s.action()}clearProgress({delta:r=0,clear:s=!1}){this.progressStyle!==null&&this.progress.size+r>0&&(this.stdout.write(`\x1B[${this.progress.size+r}A`),(r>0||s)&&this.stdout.write("\x1B[0J"))}writeProgress(){if(this.progressStyle===null||(this.progressTimeout!==null&&clearTimeout(this.progressTimeout),this.progressTimeout=null,this.progress.size===0))return;let r=Date.now();r-this.progressTime>Xpe&&(this.progressFrame=(this.progressFrame+1)%zpe.length,this.progressTime=r);let s=zpe[this.progressFrame];for(let a of this.progress.values()){let n="";if(typeof a.lastScaledSize<"u"){let h=this.progressStyle.chars[0].repeat(a.lastScaledSize),E=this.progressStyle.chars[1].repeat(this.progressMaxScaledSize-a.lastScaledSize);n=` ${h}${E}`}let c=this.formatName(null),f=c?`${c}: `:"",p=a.definition.title?` ${a.definition.title}`:"";this.stdout.write(`${Ht(this.configuration,"\u27A4","blueBright")} ${f}${s}${n}${p} +`)}this.progressTimeout=setTimeout(()=>{this.refreshProgress({force:!0})},Xpe)}refreshProgress({delta:r=0,force:s=!1}={}){let a=!1,n=!1;if(s||this.progress.size===0)a=!0;else for(let c of this.progress.values()){let f=typeof c.definition.progress<"u"?Math.trunc(this.progressMaxScaledSize*c.definition.progress):void 0,p=c.lastScaledSize;c.lastScaledSize=f;let h=c.lastTitle;if(c.lastTitle=c.definition.title,f!==p||(n=h!==c.definition.title)){a=!0;break}}a&&(this.clearProgress({delta:r,clear:n}),this.writeProgress())}truncate(r,{truncate:s}={}){return this.progressStyle===null&&(s=!1),typeof s>"u"&&(s=this.configuration.get("preferTruncatedLines")),s&&(r=(0,$pe.default)(r,0,this.stdout.columns-1)),r}formatName(r){return this.includeNames?the(r,{configuration:this.configuration,json:this.json}):""}formatPrefix(r,s){return this.includePrefix?`${Ht(this.configuration,"\u27A4",s)} ${r}${this.formatIndent()}`:""}formatNameWithHyperlink(r){return this.includeNames?Wj(r,{configuration:this.configuration,json:this.json}):""}formatIndent(){return this.level>0||!this.forceSectionAlignment?"\u2502 ".repeat(this.indent):`${ait} `}}});var In={};Vt(In,{PackageManager:()=>nhe,detectPackageManager:()=>ihe,executePackageAccessibleBinary:()=>che,executePackageScript:()=>LT,executePackageShellcode:()=>Yj,executeWorkspaceAccessibleBinary:()=>mit,executeWorkspaceLifecycleScript:()=>ahe,executeWorkspaceScript:()=>ohe,getPackageAccessibleBinaries:()=>MT,getWorkspaceAccessibleBinaries:()=>lhe,hasPackageScript:()=>hit,hasWorkspaceScript:()=>Vj,isNodeScript:()=>Jj,makeScriptEnv:()=>Iv,maybeExecuteWorkspaceLifecycleScript:()=>dit,prepareExternalProject:()=>pit});async function b0(t,e,r,s=[]){if(process.platform==="win32"){let a=`@goto #_undefined_# 2>NUL || @title %COMSPEC% & @setlocal & @"${r}" ${s.map(n=>`"${n.replace('"','""')}"`).join(" ")} %*`;await ce.writeFilePromise(J.format({dir:t,name:e,ext:".cmd"}),a)}await ce.writeFilePromise(J.join(t,e),`#!/bin/sh +exec "${r}" ${s.map(a=>`'${a.replace(/'/g,`'"'"'`)}'`).join(" ")} "$@" +`,{mode:493})}async function ihe(t){let e=await Ut.tryFind(t);if(e?.packageManager){let s=xQ(e.packageManager);if(s?.name){let a=`found ${JSON.stringify({packageManager:e.packageManager})} in manifest`,[n]=s.reference.split(".");switch(s.name){case"yarn":return{packageManagerField:!0,packageManager:Number(n)===1?"Yarn Classic":"Yarn",reason:a};case"npm":return{packageManagerField:!0,packageManager:"npm",reason:a};case"pnpm":return{packageManagerField:!0,packageManager:"pnpm",reason:a}}}}let r;try{r=await ce.readFilePromise(J.join(t,Er.lockfile),"utf8")}catch{}return r!==void 0?r.match(/^__metadata:$/m)?{packageManager:"Yarn",reason:'"__metadata" key found in yarn.lock'}:{packageManager:"Yarn Classic",reason:'"__metadata" key not found in yarn.lock, must be a Yarn classic lockfile'}:ce.existsSync(J.join(t,"package-lock.json"))?{packageManager:"npm",reason:`found npm's "package-lock.json" lockfile`}:ce.existsSync(J.join(t,"pnpm-lock.yaml"))?{packageManager:"pnpm",reason:`found pnpm's "pnpm-lock.yaml" lockfile`}:null}async function Iv({project:t,locator:e,binFolder:r,ignoreCorepack:s,lifecycleScript:a,baseEnv:n=t?.configuration.env??process.env}){let c={};for(let[E,C]of Object.entries(n))typeof C<"u"&&(c[E.toLowerCase()!=="path"?E:"PATH"]=C);let f=fe.fromPortablePath(r);c.BERRY_BIN_FOLDER=fe.fromPortablePath(f);let p=process.env.COREPACK_ROOT&&!s?fe.join(process.env.COREPACK_ROOT,"dist/yarn.js"):process.argv[1];if(await Promise.all([b0(r,"node",process.execPath),...fn!==null?[b0(r,"run",process.execPath,[p,"run"]),b0(r,"yarn",process.execPath,[p]),b0(r,"yarnpkg",process.execPath,[p]),b0(r,"node-gyp",process.execPath,[p,"run","--top-level","node-gyp"])]:[]]),t&&(c.INIT_CWD=fe.fromPortablePath(t.configuration.startingCwd),c.PROJECT_CWD=fe.fromPortablePath(t.cwd)),c.PATH=c.PATH?`${f}${fe.delimiter}${c.PATH}`:`${f}`,c.npm_execpath=`${f}${fe.sep}yarn`,c.npm_node_execpath=`${f}${fe.sep}node`,e){if(!t)throw new Error("Assertion failed: Missing project");let E=t.tryWorkspaceByLocator(e),C=E?E.manifest.version??"":t.storedPackages.get(e.locatorHash).version??"";c.npm_package_name=un(e),c.npm_package_version=C;let S;if(E)S=E.cwd;else{let P=t.storedPackages.get(e.locatorHash);if(!P)throw new Error(`Package for ${Yr(t.configuration,e)} not found in the project`);let I=t.configuration.getLinkers(),R={project:t,report:new Ot({stdout:new P0.PassThrough,configuration:t.configuration})},N=I.find(U=>U.supportsPackage(P,R));if(!N)throw new Error(`The package ${Yr(t.configuration,P)} isn't supported by any of the available linkers`);S=await N.findPackageLocation(P,R)}c.npm_package_json=fe.fromPortablePath(J.join(S,Er.manifest))}let h=fn!==null?`yarn/${fn}`:`yarn/${Pp("@yarnpkg/core").version}-core`;return c.npm_config_user_agent=`${h} npm/? node/${process.version} ${process.platform} ${process.arch}`,a&&(c.npm_lifecycle_event=a),t&&await t.configuration.triggerHook(E=>E.setupScriptEnvironment,t,c,async(E,C,S)=>await b0(r,E,C,S)),c}async function pit(t,e,{configuration:r,report:s,workspace:a=null,locator:n=null}){await Ait(async()=>{await ce.mktempPromise(async c=>{let f=J.join(c,"pack.log"),p=null,{stdout:h,stderr:E}=r.getSubprocessStreams(f,{prefix:fe.fromPortablePath(t),report:s}),C=n&&Gu(n)?rI(n):n,S=C?ll(C):"an external project";h.write(`Packing ${S} from sources +`);let P=await ihe(t),I;P!==null?(h.write(`Using ${P.packageManager} for bootstrap. Reason: ${P.reason} + +`),I=P.packageManager):(h.write(`No package manager configuration detected; defaulting to Yarn + +`),I="Yarn");let R=I==="Yarn"&&!P?.packageManagerField;await ce.mktempPromise(async N=>{let U=await Iv({binFolder:N,ignoreCorepack:R,baseEnv:{...process.env,COREPACK_ENABLE_AUTO_PIN:"0"}}),ee=new Map([["Yarn Classic",async()=>{let ue=a!==null?["workspace",a]:[],le=J.join(t,Er.manifest),me=await ce.readFilePromise(le),pe=await Wu(process.execPath,[process.argv[1],"set","version","classic","--only-if-needed","--yarn-path"],{cwd:t,env:U,stdin:p,stdout:h,stderr:E,end:1});if(pe.code!==0)return pe.code;await ce.writeFilePromise(le,me),await ce.appendFilePromise(J.join(t,".npmignore"),`/.yarn +`),h.write(` +`),delete U.NODE_ENV;let Be=await Wu("yarn",["install"],{cwd:t,env:U,stdin:p,stdout:h,stderr:E,end:1});if(Be.code!==0)return Be.code;h.write(` +`);let Ce=await Wu("yarn",[...ue,"pack","--filename",fe.fromPortablePath(e)],{cwd:t,env:U,stdin:p,stdout:h,stderr:E});return Ce.code!==0?Ce.code:0}],["Yarn",async()=>{let ue=a!==null?["workspace",a]:[];U.YARN_ENABLE_INLINE_BUILDS="1";let le=J.join(t,Er.lockfile);await ce.existsPromise(le)||await ce.writeFilePromise(le,"");let me=await Wu("yarn",[...ue,"pack","--install-if-needed","--filename",fe.fromPortablePath(e)],{cwd:t,env:U,stdin:p,stdout:h,stderr:E});return me.code!==0?me.code:0}],["npm",async()=>{if(a!==null){let we=new P0.PassThrough,ye=WE(we);we.pipe(h,{end:!1});let Ae=await Wu("npm",["--version"],{cwd:t,env:U,stdin:p,stdout:we,stderr:E,end:0});if(we.end(),Ae.code!==0)return h.end(),E.end(),Ae.code;let se=(await ye).toString().trim();if(!Zf(se,">=7.x")){let Z=Da(null,"npm"),De=On(Z,se),Re=On(Z,">=7.x");throw new Error(`Workspaces aren't supported by ${ni(r,De)}; please upgrade to ${ni(r,Re)} (npm has been detected as the primary package manager for ${Ht(r,t,ht.PATH)})`)}}let ue=a!==null?["--workspace",a]:[];delete U.npm_config_user_agent,delete U.npm_config_production,delete U.NPM_CONFIG_PRODUCTION,delete U.NODE_ENV;let le=await Wu("npm",["install","--legacy-peer-deps"],{cwd:t,env:U,stdin:p,stdout:h,stderr:E,end:1});if(le.code!==0)return le.code;let me=new P0.PassThrough,pe=WE(me);me.pipe(h);let Be=await Wu("npm",["pack","--silent",...ue],{cwd:t,env:U,stdin:p,stdout:me,stderr:E});if(Be.code!==0)return Be.code;let Ce=(await pe).toString().trim().replace(/^.*\n/s,""),g=J.resolve(t,fe.toPortablePath(Ce));return await ce.renamePromise(g,e),0}]]).get(I);if(typeof ee>"u")throw new Error("Assertion failed: Unsupported workflow");let ie=await ee();if(!(ie===0||typeof ie>"u"))throw ce.detachTemp(c),new jt(58,`Packing the package failed (exit code ${ie}, logs can be found here: ${Ht(r,f,ht.PATH)})`)})})})}async function hit(t,e,{project:r}){let s=r.tryWorkspaceByLocator(t);if(s!==null)return Vj(s,e);let a=r.storedPackages.get(t.locatorHash);if(!a)throw new Error(`Package for ${Yr(r.configuration,t)} not found in the project`);return await $f.openPromise(async n=>{let c=r.configuration,f=r.configuration.getLinkers(),p={project:r,report:new Ot({stdout:new P0.PassThrough,configuration:c})},h=f.find(P=>P.supportsPackage(a,p));if(!h)throw new Error(`The package ${Yr(r.configuration,a)} isn't supported by any of the available linkers`);let E=await h.findPackageLocation(a,p),C=new Sn(E,{baseFs:n});return(await Ut.find(vt.dot,{baseFs:C})).scripts.has(e)})}async function LT(t,e,r,{cwd:s,project:a,stdin:n,stdout:c,stderr:f}){return await ce.mktempPromise(async p=>{let{manifest:h,env:E,cwd:C}=await she(t,{project:a,binFolder:p,cwd:s,lifecycleScript:e}),S=h.scripts.get(e);if(typeof S>"u")return 1;let P=async()=>await vI(S,r,{cwd:C,env:E,stdin:n,stdout:c,stderr:f});return await(await a.configuration.reduceHook(R=>R.wrapScriptExecution,P,a,t,e,{script:S,args:r,cwd:C,env:E,stdin:n,stdout:c,stderr:f}))()})}async function Yj(t,e,r,{cwd:s,project:a,stdin:n,stdout:c,stderr:f}){return await ce.mktempPromise(async p=>{let{env:h,cwd:E}=await she(t,{project:a,binFolder:p,cwd:s});return await vI(e,r,{cwd:E,env:h,stdin:n,stdout:c,stderr:f})})}async function git(t,{binFolder:e,cwd:r,lifecycleScript:s}){let a=await Iv({project:t.project,locator:t.anchoredLocator,binFolder:e,lifecycleScript:s});return await Kj(e,await lhe(t)),typeof r>"u"&&(r=J.dirname(await ce.realpathPromise(J.join(t.cwd,"package.json")))),{manifest:t.manifest,binFolder:e,env:a,cwd:r}}async function she(t,{project:e,binFolder:r,cwd:s,lifecycleScript:a}){let n=e.tryWorkspaceByLocator(t);if(n!==null)return git(n,{binFolder:r,cwd:s,lifecycleScript:a});let c=e.storedPackages.get(t.locatorHash);if(!c)throw new Error(`Package for ${Yr(e.configuration,t)} not found in the project`);return await $f.openPromise(async f=>{let p=e.configuration,h=e.configuration.getLinkers(),E={project:e,report:new Ot({stdout:new P0.PassThrough,configuration:p})},C=h.find(N=>N.supportsPackage(c,E));if(!C)throw new Error(`The package ${Yr(e.configuration,c)} isn't supported by any of the available linkers`);let S=await Iv({project:e,locator:t,binFolder:r,lifecycleScript:a});await Kj(r,await MT(t,{project:e}));let P=await C.findPackageLocation(c,E),I=new Sn(P,{baseFs:f}),R=await Ut.find(vt.dot,{baseFs:I});return typeof s>"u"&&(s=P),{manifest:R,binFolder:r,env:S,cwd:s}})}async function ohe(t,e,r,{cwd:s,stdin:a,stdout:n,stderr:c}){return await LT(t.anchoredLocator,e,r,{cwd:s,project:t.project,stdin:a,stdout:n,stderr:c})}function Vj(t,e){return t.manifest.scripts.has(e)}async function ahe(t,e,{cwd:r,report:s}){let{configuration:a}=t.project,n=null;await ce.mktempPromise(async c=>{let f=J.join(c,`${e}.log`),p=`# This file contains the result of Yarn calling the "${e}" lifecycle script inside a workspace ("${fe.fromPortablePath(t.cwd)}") +`,{stdout:h,stderr:E}=a.getSubprocessStreams(f,{report:s,prefix:Yr(a,t.anchoredLocator),header:p});s.reportInfo(36,`Calling the "${e}" lifecycle script`);let C=await ohe(t,e,[],{cwd:r,stdin:n,stdout:h,stderr:E});if(h.end(),E.end(),C!==0)throw ce.detachTemp(c),new jt(36,`${bB(e)} script failed (exit code ${Ht(a,C,ht.NUMBER)}, logs can be found here: ${Ht(a,f,ht.PATH)}); run ${Ht(a,`yarn ${e}`,ht.CODE)} to investigate`)})}async function dit(t,e,r){Vj(t,e)&&await ahe(t,e,r)}function Jj(t){let e=J.extname(t);if(e.match(/\.[cm]?[jt]sx?$/))return!0;if(e===".exe"||e===".bin")return!1;let r=Buffer.alloc(4),s;try{s=ce.openSync(t,"r")}catch{return!0}try{ce.readSync(s,r,0,r.length,0)}finally{ce.closeSync(s)}let a=r.readUint32BE();return!(a===3405691582||a===3489328638||a===2135247942||(a&4294901760)===1297743872)}async function MT(t,{project:e}){let r=e.configuration,s=new Map,a=e.storedPackages.get(t.locatorHash);if(!a)throw new Error(`Package for ${Yr(r,t)} not found in the project`);let n=new P0.Writable,c=r.getLinkers(),f={project:e,report:new Ot({configuration:r,stdout:n})},p=new Set([t.locatorHash]);for(let E of a.dependencies.values()){let C=e.storedResolutions.get(E.descriptorHash);if(!C)throw new Error(`Assertion failed: The resolution (${ni(r,E)}) should have been registered`);p.add(C)}let h=await Promise.all(Array.from(p,async E=>{let C=e.storedPackages.get(E);if(!C)throw new Error(`Assertion failed: The package (${E}) should have been registered`);if(C.bin.size===0)return Wl.skip;let S=c.find(I=>I.supportsPackage(C,f));if(!S)return Wl.skip;let P=null;try{P=await S.findPackageLocation(C,f)}catch(I){if(I.code==="LOCATOR_NOT_INSTALLED")return Wl.skip;throw I}return{dependency:C,packageLocation:P}}));for(let E of h){if(E===Wl.skip)continue;let{dependency:C,packageLocation:S}=E;for(let[P,I]of C.bin){let R=J.resolve(S,I);s.set(P,[C,fe.fromPortablePath(R),Jj(R)])}}return s}async function lhe(t){return await MT(t.anchoredLocator,{project:t.project})}async function Kj(t,e){await Promise.all(Array.from(e,([r,[,s,a]])=>a?b0(t,r,process.execPath,[s]):b0(t,r,s,[])))}async function che(t,e,r,{cwd:s,project:a,stdin:n,stdout:c,stderr:f,nodeArgs:p=[],packageAccessibleBinaries:h}){h??=await MT(t,{project:a});let E=h.get(e);if(!E)throw new Error(`Binary not found (${e}) for ${Yr(a.configuration,t)}`);return await ce.mktempPromise(async C=>{let[,S]=E,P=await Iv({project:a,locator:t,binFolder:C});await Kj(P.BERRY_BIN_FOLDER,h);let I=Jj(fe.toPortablePath(S))?Wu(process.execPath,[...p,S,...r],{cwd:s,env:P,stdin:n,stdout:c,stderr:f}):Wu(S,r,{cwd:s,env:P,stdin:n,stdout:c,stderr:f}),R;try{R=await I}finally{await ce.removePromise(P.BERRY_BIN_FOLDER)}return R.code})}async function mit(t,e,r,{cwd:s,stdin:a,stdout:n,stderr:c,packageAccessibleBinaries:f}){return await che(t.anchoredLocator,e,r,{project:t.project,cwd:s,stdin:a,stdout:n,stderr:c,packageAccessibleBinaries:f})}var rhe,P0,nhe,fit,Ait,zj=Xe(()=>{Dt();Dt();eA();pv();ql();rhe=ut(Ld()),P0=Ie("stream");oI();Tc();Ev();yv();dT();xc();Pc();Rp();Wo();nhe=(a=>(a.Yarn1="Yarn Classic",a.Yarn2="Yarn",a.Npm="npm",a.Pnpm="pnpm",a))(nhe||{});fit=2,Ait=(0,rhe.default)(fit)});var DI=_((J4t,fhe)=>{"use strict";var uhe=new Map([["C","cwd"],["f","file"],["z","gzip"],["P","preservePaths"],["U","unlink"],["strip-components","strip"],["stripComponents","strip"],["keep-newer","newer"],["keepNewer","newer"],["keep-newer-files","newer"],["keepNewerFiles","newer"],["k","keep"],["keep-existing","keep"],["keepExisting","keep"],["m","noMtime"],["no-mtime","noMtime"],["p","preserveOwner"],["L","follow"],["h","follow"]]);fhe.exports=t=>t?Object.keys(t).map(e=>[uhe.has(e)?uhe.get(e):e,t[e]]).reduce((e,r)=>(e[r[0]]=r[1],e),Object.create(null)):{}});var PI=_((K4t,Ihe)=>{"use strict";var Ahe=typeof process=="object"&&process?process:{stdout:null,stderr:null},yit=Ie("events"),phe=Ie("stream"),hhe=Ie("string_decoder").StringDecoder,_p=Symbol("EOF"),Hp=Symbol("maybeEmitEnd"),x0=Symbol("emittedEnd"),UT=Symbol("emittingEnd"),Cv=Symbol("emittedError"),_T=Symbol("closed"),ghe=Symbol("read"),HT=Symbol("flush"),dhe=Symbol("flushChunk"),ul=Symbol("encoding"),jp=Symbol("decoder"),jT=Symbol("flowing"),wv=Symbol("paused"),bI=Symbol("resume"),Ys=Symbol("bufferLength"),Xj=Symbol("bufferPush"),Zj=Symbol("bufferShift"),Ko=Symbol("objectMode"),zo=Symbol("destroyed"),$j=Symbol("emitData"),mhe=Symbol("emitEnd"),e6=Symbol("emitEnd2"),Gp=Symbol("async"),Bv=t=>Promise.resolve().then(t),yhe=global._MP_NO_ITERATOR_SYMBOLS_!=="1",Eit=yhe&&Symbol.asyncIterator||Symbol("asyncIterator not implemented"),Iit=yhe&&Symbol.iterator||Symbol("iterator not implemented"),Cit=t=>t==="end"||t==="finish"||t==="prefinish",wit=t=>t instanceof ArrayBuffer||typeof t=="object"&&t.constructor&&t.constructor.name==="ArrayBuffer"&&t.byteLength>=0,Bit=t=>!Buffer.isBuffer(t)&&ArrayBuffer.isView(t),GT=class{constructor(e,r,s){this.src=e,this.dest=r,this.opts=s,this.ondrain=()=>e[bI](),r.on("drain",this.ondrain)}unpipe(){this.dest.removeListener("drain",this.ondrain)}proxyErrors(){}end(){this.unpipe(),this.opts.end&&this.dest.end()}},t6=class extends GT{unpipe(){this.src.removeListener("error",this.proxyErrors),super.unpipe()}constructor(e,r,s){super(e,r,s),this.proxyErrors=a=>r.emit("error",a),e.on("error",this.proxyErrors)}};Ihe.exports=class Ehe extends phe{constructor(e){super(),this[jT]=!1,this[wv]=!1,this.pipes=[],this.buffer=[],this[Ko]=e&&e.objectMode||!1,this[Ko]?this[ul]=null:this[ul]=e&&e.encoding||null,this[ul]==="buffer"&&(this[ul]=null),this[Gp]=e&&!!e.async||!1,this[jp]=this[ul]?new hhe(this[ul]):null,this[_p]=!1,this[x0]=!1,this[UT]=!1,this[_T]=!1,this[Cv]=null,this.writable=!0,this.readable=!0,this[Ys]=0,this[zo]=!1}get bufferLength(){return this[Ys]}get encoding(){return this[ul]}set encoding(e){if(this[Ko])throw new Error("cannot set encoding in objectMode");if(this[ul]&&e!==this[ul]&&(this[jp]&&this[jp].lastNeed||this[Ys]))throw new Error("cannot change encoding");this[ul]!==e&&(this[jp]=e?new hhe(e):null,this.buffer.length&&(this.buffer=this.buffer.map(r=>this[jp].write(r)))),this[ul]=e}setEncoding(e){this.encoding=e}get objectMode(){return this[Ko]}set objectMode(e){this[Ko]=this[Ko]||!!e}get async(){return this[Gp]}set async(e){this[Gp]=this[Gp]||!!e}write(e,r,s){if(this[_p])throw new Error("write after end");if(this[zo])return this.emit("error",Object.assign(new Error("Cannot call write after a stream was destroyed"),{code:"ERR_STREAM_DESTROYED"})),!0;typeof r=="function"&&(s=r,r="utf8"),r||(r="utf8");let a=this[Gp]?Bv:n=>n();return!this[Ko]&&!Buffer.isBuffer(e)&&(Bit(e)?e=Buffer.from(e.buffer,e.byteOffset,e.byteLength):wit(e)?e=Buffer.from(e):typeof e!="string"&&(this.objectMode=!0)),this[Ko]?(this.flowing&&this[Ys]!==0&&this[HT](!0),this.flowing?this.emit("data",e):this[Xj](e),this[Ys]!==0&&this.emit("readable"),s&&a(s),this.flowing):e.length?(typeof e=="string"&&!(r===this[ul]&&!this[jp].lastNeed)&&(e=Buffer.from(e,r)),Buffer.isBuffer(e)&&this[ul]&&(e=this[jp].write(e)),this.flowing&&this[Ys]!==0&&this[HT](!0),this.flowing?this.emit("data",e):this[Xj](e),this[Ys]!==0&&this.emit("readable"),s&&a(s),this.flowing):(this[Ys]!==0&&this.emit("readable"),s&&a(s),this.flowing)}read(e){if(this[zo])return null;if(this[Ys]===0||e===0||e>this[Ys])return this[Hp](),null;this[Ko]&&(e=null),this.buffer.length>1&&!this[Ko]&&(this.encoding?this.buffer=[this.buffer.join("")]:this.buffer=[Buffer.concat(this.buffer,this[Ys])]);let r=this[ghe](e||null,this.buffer[0]);return this[Hp](),r}[ghe](e,r){return e===r.length||e===null?this[Zj]():(this.buffer[0]=r.slice(e),r=r.slice(0,e),this[Ys]-=e),this.emit("data",r),!this.buffer.length&&!this[_p]&&this.emit("drain"),r}end(e,r,s){return typeof e=="function"&&(s=e,e=null),typeof r=="function"&&(s=r,r="utf8"),e&&this.write(e,r),s&&this.once("end",s),this[_p]=!0,this.writable=!1,(this.flowing||!this[wv])&&this[Hp](),this}[bI](){this[zo]||(this[wv]=!1,this[jT]=!0,this.emit("resume"),this.buffer.length?this[HT]():this[_p]?this[Hp]():this.emit("drain"))}resume(){return this[bI]()}pause(){this[jT]=!1,this[wv]=!0}get destroyed(){return this[zo]}get flowing(){return this[jT]}get paused(){return this[wv]}[Xj](e){this[Ko]?this[Ys]+=1:this[Ys]+=e.length,this.buffer.push(e)}[Zj](){return this.buffer.length&&(this[Ko]?this[Ys]-=1:this[Ys]-=this.buffer[0].length),this.buffer.shift()}[HT](e){do;while(this[dhe](this[Zj]()));!e&&!this.buffer.length&&!this[_p]&&this.emit("drain")}[dhe](e){return e?(this.emit("data",e),this.flowing):!1}pipe(e,r){if(this[zo])return;let s=this[x0];return r=r||{},e===Ahe.stdout||e===Ahe.stderr?r.end=!1:r.end=r.end!==!1,r.proxyErrors=!!r.proxyErrors,s?r.end&&e.end():(this.pipes.push(r.proxyErrors?new t6(this,e,r):new GT(this,e,r)),this[Gp]?Bv(()=>this[bI]()):this[bI]()),e}unpipe(e){let r=this.pipes.find(s=>s.dest===e);r&&(this.pipes.splice(this.pipes.indexOf(r),1),r.unpipe())}addListener(e,r){return this.on(e,r)}on(e,r){let s=super.on(e,r);return e==="data"&&!this.pipes.length&&!this.flowing?this[bI]():e==="readable"&&this[Ys]!==0?super.emit("readable"):Cit(e)&&this[x0]?(super.emit(e),this.removeAllListeners(e)):e==="error"&&this[Cv]&&(this[Gp]?Bv(()=>r.call(this,this[Cv])):r.call(this,this[Cv])),s}get emittedEnd(){return this[x0]}[Hp](){!this[UT]&&!this[x0]&&!this[zo]&&this.buffer.length===0&&this[_p]&&(this[UT]=!0,this.emit("end"),this.emit("prefinish"),this.emit("finish"),this[_T]&&this.emit("close"),this[UT]=!1)}emit(e,r,...s){if(e!=="error"&&e!=="close"&&e!==zo&&this[zo])return;if(e==="data")return r?this[Gp]?Bv(()=>this[$j](r)):this[$j](r):!1;if(e==="end")return this[mhe]();if(e==="close"){if(this[_T]=!0,!this[x0]&&!this[zo])return;let n=super.emit("close");return this.removeAllListeners("close"),n}else if(e==="error"){this[Cv]=r;let n=super.emit("error",r);return this[Hp](),n}else if(e==="resume"){let n=super.emit("resume");return this[Hp](),n}else if(e==="finish"||e==="prefinish"){let n=super.emit(e);return this.removeAllListeners(e),n}let a=super.emit(e,r,...s);return this[Hp](),a}[$j](e){for(let s of this.pipes)s.dest.write(e)===!1&&this.pause();let r=super.emit("data",e);return this[Hp](),r}[mhe](){this[x0]||(this[x0]=!0,this.readable=!1,this[Gp]?Bv(()=>this[e6]()):this[e6]())}[e6](){if(this[jp]){let r=this[jp].end();if(r){for(let s of this.pipes)s.dest.write(r);super.emit("data",r)}}for(let r of this.pipes)r.end();let e=super.emit("end");return this.removeAllListeners("end"),e}collect(){let e=[];this[Ko]||(e.dataLength=0);let r=this.promise();return this.on("data",s=>{e.push(s),this[Ko]||(e.dataLength+=s.length)}),r.then(()=>e)}concat(){return this[Ko]?Promise.reject(new Error("cannot concat in objectMode")):this.collect().then(e=>this[Ko]?Promise.reject(new Error("cannot concat in objectMode")):this[ul]?e.join(""):Buffer.concat(e,e.dataLength))}promise(){return new Promise((e,r)=>{this.on(zo,()=>r(new Error("stream destroyed"))),this.on("error",s=>r(s)),this.on("end",()=>e())})}[Eit](){return{next:()=>{let r=this.read();if(r!==null)return Promise.resolve({done:!1,value:r});if(this[_p])return Promise.resolve({done:!0});let s=null,a=null,n=h=>{this.removeListener("data",c),this.removeListener("end",f),a(h)},c=h=>{this.removeListener("error",n),this.removeListener("end",f),this.pause(),s({value:h,done:!!this[_p]})},f=()=>{this.removeListener("error",n),this.removeListener("data",c),s({done:!0})},p=()=>n(new Error("stream destroyed"));return new Promise((h,E)=>{a=E,s=h,this.once(zo,p),this.once("error",n),this.once("end",f),this.once("data",c)})}}}[Iit](){return{next:()=>{let r=this.read();return{value:r,done:r===null}}}}destroy(e){return this[zo]?(e?this.emit("error",e):this.emit(zo),this):(this[zo]=!0,this.buffer.length=0,this[Ys]=0,typeof this.close=="function"&&!this[_T]&&this.close(),e?this.emit("error",e):this.emit(zo),this)}static isStream(e){return!!e&&(e instanceof Ehe||e instanceof phe||e instanceof yit&&(typeof e.pipe=="function"||typeof e.write=="function"&&typeof e.end=="function"))}}});var whe=_((z4t,Che)=>{var vit=Ie("zlib").constants||{ZLIB_VERNUM:4736};Che.exports=Object.freeze(Object.assign(Object.create(null),{Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BLOCK:5,Z_OK:0,Z_STREAM_END:1,Z_NEED_DICT:2,Z_ERRNO:-1,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_MEM_ERROR:-4,Z_BUF_ERROR:-5,Z_VERSION_ERROR:-6,Z_NO_COMPRESSION:0,Z_BEST_SPEED:1,Z_BEST_COMPRESSION:9,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,DEFLATE:1,INFLATE:2,GZIP:3,GUNZIP:4,DEFLATERAW:5,INFLATERAW:6,UNZIP:7,BROTLI_DECODE:8,BROTLI_ENCODE:9,Z_MIN_WINDOWBITS:8,Z_MAX_WINDOWBITS:15,Z_DEFAULT_WINDOWBITS:15,Z_MIN_CHUNK:64,Z_MAX_CHUNK:1/0,Z_DEFAULT_CHUNK:16384,Z_MIN_MEMLEVEL:1,Z_MAX_MEMLEVEL:9,Z_DEFAULT_MEMLEVEL:8,Z_MIN_LEVEL:-1,Z_MAX_LEVEL:9,Z_DEFAULT_LEVEL:-1,BROTLI_OPERATION_PROCESS:0,BROTLI_OPERATION_FLUSH:1,BROTLI_OPERATION_FINISH:2,BROTLI_OPERATION_EMIT_METADATA:3,BROTLI_MODE_GENERIC:0,BROTLI_MODE_TEXT:1,BROTLI_MODE_FONT:2,BROTLI_DEFAULT_MODE:0,BROTLI_MIN_QUALITY:0,BROTLI_MAX_QUALITY:11,BROTLI_DEFAULT_QUALITY:11,BROTLI_MIN_WINDOW_BITS:10,BROTLI_MAX_WINDOW_BITS:24,BROTLI_LARGE_MAX_WINDOW_BITS:30,BROTLI_DEFAULT_WINDOW:22,BROTLI_MIN_INPUT_BLOCK_BITS:16,BROTLI_MAX_INPUT_BLOCK_BITS:24,BROTLI_PARAM_MODE:0,BROTLI_PARAM_QUALITY:1,BROTLI_PARAM_LGWIN:2,BROTLI_PARAM_LGBLOCK:3,BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING:4,BROTLI_PARAM_SIZE_HINT:5,BROTLI_PARAM_LARGE_WINDOW:6,BROTLI_PARAM_NPOSTFIX:7,BROTLI_PARAM_NDIRECT:8,BROTLI_DECODER_RESULT_ERROR:0,BROTLI_DECODER_RESULT_SUCCESS:1,BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT:2,BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT:3,BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION:0,BROTLI_DECODER_PARAM_LARGE_WINDOW:1,BROTLI_DECODER_NO_ERROR:0,BROTLI_DECODER_SUCCESS:1,BROTLI_DECODER_NEEDS_MORE_INPUT:2,BROTLI_DECODER_NEEDS_MORE_OUTPUT:3,BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE:-1,BROTLI_DECODER_ERROR_FORMAT_RESERVED:-2,BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE:-3,BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET:-4,BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME:-5,BROTLI_DECODER_ERROR_FORMAT_CL_SPACE:-6,BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE:-7,BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT:-8,BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1:-9,BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2:-10,BROTLI_DECODER_ERROR_FORMAT_TRANSFORM:-11,BROTLI_DECODER_ERROR_FORMAT_DICTIONARY:-12,BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS:-13,BROTLI_DECODER_ERROR_FORMAT_PADDING_1:-14,BROTLI_DECODER_ERROR_FORMAT_PADDING_2:-15,BROTLI_DECODER_ERROR_FORMAT_DISTANCE:-16,BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET:-19,BROTLI_DECODER_ERROR_INVALID_ARGUMENTS:-20,BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES:-21,BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS:-22,BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP:-25,BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1:-26,BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2:-27,BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES:-30,BROTLI_DECODER_ERROR_UNREACHABLE:-31},vit))});var m6=_(Kl=>{"use strict";var o6=Ie("assert"),k0=Ie("buffer").Buffer,She=Ie("zlib"),fm=Kl.constants=whe(),Sit=PI(),Bhe=k0.concat,Am=Symbol("_superWrite"),kI=class extends Error{constructor(e){super("zlib: "+e.message),this.code=e.code,this.errno=e.errno,this.code||(this.code="ZLIB_ERROR"),this.message="zlib: "+e.message,Error.captureStackTrace(this,this.constructor)}get name(){return"ZlibError"}},Dit=Symbol("opts"),vv=Symbol("flushFlag"),vhe=Symbol("finishFlushFlag"),d6=Symbol("fullFlushFlag"),Ii=Symbol("handle"),qT=Symbol("onError"),xI=Symbol("sawError"),r6=Symbol("level"),n6=Symbol("strategy"),i6=Symbol("ended"),X4t=Symbol("_defaultFullFlush"),WT=class extends Sit{constructor(e,r){if(!e||typeof e!="object")throw new TypeError("invalid options for ZlibBase constructor");super(e),this[xI]=!1,this[i6]=!1,this[Dit]=e,this[vv]=e.flush,this[vhe]=e.finishFlush;try{this[Ii]=new She[r](e)}catch(s){throw new kI(s)}this[qT]=s=>{this[xI]||(this[xI]=!0,this.close(),this.emit("error",s))},this[Ii].on("error",s=>this[qT](new kI(s))),this.once("end",()=>this.close)}close(){this[Ii]&&(this[Ii].close(),this[Ii]=null,this.emit("close"))}reset(){if(!this[xI])return o6(this[Ii],"zlib binding closed"),this[Ii].reset()}flush(e){this.ended||(typeof e!="number"&&(e=this[d6]),this.write(Object.assign(k0.alloc(0),{[vv]:e})))}end(e,r,s){return e&&this.write(e,r),this.flush(this[vhe]),this[i6]=!0,super.end(null,null,s)}get ended(){return this[i6]}write(e,r,s){if(typeof r=="function"&&(s=r,r="utf8"),typeof e=="string"&&(e=k0.from(e,r)),this[xI])return;o6(this[Ii],"zlib binding closed");let a=this[Ii]._handle,n=a.close;a.close=()=>{};let c=this[Ii].close;this[Ii].close=()=>{},k0.concat=h=>h;let f;try{let h=typeof e[vv]=="number"?e[vv]:this[vv];f=this[Ii]._processChunk(e,h),k0.concat=Bhe}catch(h){k0.concat=Bhe,this[qT](new kI(h))}finally{this[Ii]&&(this[Ii]._handle=a,a.close=n,this[Ii].close=c,this[Ii].removeAllListeners("error"))}this[Ii]&&this[Ii].on("error",h=>this[qT](new kI(h)));let p;if(f)if(Array.isArray(f)&&f.length>0){p=this[Am](k0.from(f[0]));for(let h=1;h{this.flush(a),n()};try{this[Ii].params(e,r)}finally{this[Ii].flush=s}this[Ii]&&(this[r6]=e,this[n6]=r)}}}},a6=class extends qp{constructor(e){super(e,"Deflate")}},l6=class extends qp{constructor(e){super(e,"Inflate")}},s6=Symbol("_portable"),c6=class extends qp{constructor(e){super(e,"Gzip"),this[s6]=e&&!!e.portable}[Am](e){return this[s6]?(this[s6]=!1,e[9]=255,super[Am](e)):super[Am](e)}},u6=class extends qp{constructor(e){super(e,"Gunzip")}},f6=class extends qp{constructor(e){super(e,"DeflateRaw")}},A6=class extends qp{constructor(e){super(e,"InflateRaw")}},p6=class extends qp{constructor(e){super(e,"Unzip")}},YT=class extends WT{constructor(e,r){e=e||{},e.flush=e.flush||fm.BROTLI_OPERATION_PROCESS,e.finishFlush=e.finishFlush||fm.BROTLI_OPERATION_FINISH,super(e,r),this[d6]=fm.BROTLI_OPERATION_FLUSH}},h6=class extends YT{constructor(e){super(e,"BrotliCompress")}},g6=class extends YT{constructor(e){super(e,"BrotliDecompress")}};Kl.Deflate=a6;Kl.Inflate=l6;Kl.Gzip=c6;Kl.Gunzip=u6;Kl.DeflateRaw=f6;Kl.InflateRaw=A6;Kl.Unzip=p6;typeof She.BrotliCompress=="function"?(Kl.BrotliCompress=h6,Kl.BrotliDecompress=g6):Kl.BrotliCompress=Kl.BrotliDecompress=class{constructor(){throw new Error("Brotli is not supported in this version of Node.js")}}});var QI=_((e3t,Dhe)=>{var bit=process.env.TESTING_TAR_FAKE_PLATFORM||process.platform;Dhe.exports=bit!=="win32"?t=>t:t=>t&&t.replace(/\\/g,"/")});var VT=_((r3t,bhe)=>{"use strict";var Pit=PI(),y6=QI(),E6=Symbol("slurp");bhe.exports=class extends Pit{constructor(e,r,s){switch(super(),this.pause(),this.extended=r,this.globalExtended=s,this.header=e,this.startBlockSize=512*Math.ceil(e.size/512),this.blockRemain=this.startBlockSize,this.remain=e.size,this.type=e.type,this.meta=!1,this.ignore=!1,this.type){case"File":case"OldFile":case"Link":case"SymbolicLink":case"CharacterDevice":case"BlockDevice":case"Directory":case"FIFO":case"ContiguousFile":case"GNUDumpDir":break;case"NextFileHasLongLinkpath":case"NextFileHasLongPath":case"OldGnuLongPath":case"GlobalExtendedHeader":case"ExtendedHeader":case"OldExtendedHeader":this.meta=!0;break;default:this.ignore=!0}this.path=y6(e.path),this.mode=e.mode,this.mode&&(this.mode=this.mode&4095),this.uid=e.uid,this.gid=e.gid,this.uname=e.uname,this.gname=e.gname,this.size=e.size,this.mtime=e.mtime,this.atime=e.atime,this.ctime=e.ctime,this.linkpath=y6(e.linkpath),this.uname=e.uname,this.gname=e.gname,r&&this[E6](r),s&&this[E6](s,!0)}write(e){let r=e.length;if(r>this.blockRemain)throw new Error("writing more to entry than is appropriate");let s=this.remain,a=this.blockRemain;return this.remain=Math.max(0,s-r),this.blockRemain=Math.max(0,a-r),this.ignore?!0:s>=r?super.write(e):super.write(e.slice(0,s))}[E6](e,r){for(let s in e)e[s]!==null&&e[s]!==void 0&&!(r&&s==="path")&&(this[s]=s==="path"||s==="linkpath"?y6(e[s]):e[s])}}});var I6=_(JT=>{"use strict";JT.name=new Map([["0","File"],["","OldFile"],["1","Link"],["2","SymbolicLink"],["3","CharacterDevice"],["4","BlockDevice"],["5","Directory"],["6","FIFO"],["7","ContiguousFile"],["g","GlobalExtendedHeader"],["x","ExtendedHeader"],["A","SolarisACL"],["D","GNUDumpDir"],["I","Inode"],["K","NextFileHasLongLinkpath"],["L","NextFileHasLongPath"],["M","ContinuationFile"],["N","OldGnuLongPath"],["S","SparseFile"],["V","TapeVolumeHeader"],["X","OldExtendedHeader"]]);JT.code=new Map(Array.from(JT.name).map(t=>[t[1],t[0]]))});var Qhe=_((i3t,khe)=>{"use strict";var xit=(t,e)=>{if(Number.isSafeInteger(t))t<0?Qit(t,e):kit(t,e);else throw Error("cannot encode number outside of javascript safe integer range");return e},kit=(t,e)=>{e[0]=128;for(var r=e.length;r>1;r--)e[r-1]=t&255,t=Math.floor(t/256)},Qit=(t,e)=>{e[0]=255;var r=!1;t=t*-1;for(var s=e.length;s>1;s--){var a=t&255;t=Math.floor(t/256),r?e[s-1]=Phe(a):a===0?e[s-1]=0:(r=!0,e[s-1]=xhe(a))}},Tit=t=>{let e=t[0],r=e===128?Fit(t.slice(1,t.length)):e===255?Rit(t):null;if(r===null)throw Error("invalid base256 encoding");if(!Number.isSafeInteger(r))throw Error("parsed number outside of javascript safe integer range");return r},Rit=t=>{for(var e=t.length,r=0,s=!1,a=e-1;a>-1;a--){var n=t[a],c;s?c=Phe(n):n===0?c=n:(s=!0,c=xhe(n)),c!==0&&(r-=c*Math.pow(256,e-a-1))}return r},Fit=t=>{for(var e=t.length,r=0,s=e-1;s>-1;s--){var a=t[s];a!==0&&(r+=a*Math.pow(256,e-s-1))}return r},Phe=t=>(255^t)&255,xhe=t=>(255^t)+1&255;khe.exports={encode:xit,parse:Tit}});var RI=_((s3t,Rhe)=>{"use strict";var C6=I6(),TI=Ie("path").posix,The=Qhe(),w6=Symbol("slurp"),zl=Symbol("type"),S6=class{constructor(e,r,s,a){this.cksumValid=!1,this.needPax=!1,this.nullBlock=!1,this.block=null,this.path=null,this.mode=null,this.uid=null,this.gid=null,this.size=null,this.mtime=null,this.cksum=null,this[zl]="0",this.linkpath=null,this.uname=null,this.gname=null,this.devmaj=0,this.devmin=0,this.atime=null,this.ctime=null,Buffer.isBuffer(e)?this.decode(e,r||0,s,a):e&&this.set(e)}decode(e,r,s,a){if(r||(r=0),!e||!(e.length>=r+512))throw new Error("need 512 bytes for header");if(this.path=pm(e,r,100),this.mode=Q0(e,r+100,8),this.uid=Q0(e,r+108,8),this.gid=Q0(e,r+116,8),this.size=Q0(e,r+124,12),this.mtime=B6(e,r+136,12),this.cksum=Q0(e,r+148,12),this[w6](s),this[w6](a,!0),this[zl]=pm(e,r+156,1),this[zl]===""&&(this[zl]="0"),this[zl]==="0"&&this.path.substr(-1)==="/"&&(this[zl]="5"),this[zl]==="5"&&(this.size=0),this.linkpath=pm(e,r+157,100),e.slice(r+257,r+265).toString()==="ustar\x0000")if(this.uname=pm(e,r+265,32),this.gname=pm(e,r+297,32),this.devmaj=Q0(e,r+329,8),this.devmin=Q0(e,r+337,8),e[r+475]!==0){let c=pm(e,r+345,155);this.path=c+"/"+this.path}else{let c=pm(e,r+345,130);c&&(this.path=c+"/"+this.path),this.atime=B6(e,r+476,12),this.ctime=B6(e,r+488,12)}let n=8*32;for(let c=r;c=r+512))throw new Error("need 512 bytes for header");let s=this.ctime||this.atime?130:155,a=Nit(this.path||"",s),n=a[0],c=a[1];this.needPax=a[2],this.needPax=hm(e,r,100,n)||this.needPax,this.needPax=T0(e,r+100,8,this.mode)||this.needPax,this.needPax=T0(e,r+108,8,this.uid)||this.needPax,this.needPax=T0(e,r+116,8,this.gid)||this.needPax,this.needPax=T0(e,r+124,12,this.size)||this.needPax,this.needPax=v6(e,r+136,12,this.mtime)||this.needPax,e[r+156]=this[zl].charCodeAt(0),this.needPax=hm(e,r+157,100,this.linkpath)||this.needPax,e.write("ustar\x0000",r+257,8),this.needPax=hm(e,r+265,32,this.uname)||this.needPax,this.needPax=hm(e,r+297,32,this.gname)||this.needPax,this.needPax=T0(e,r+329,8,this.devmaj)||this.needPax,this.needPax=T0(e,r+337,8,this.devmin)||this.needPax,this.needPax=hm(e,r+345,s,c)||this.needPax,e[r+475]!==0?this.needPax=hm(e,r+345,155,c)||this.needPax:(this.needPax=hm(e,r+345,130,c)||this.needPax,this.needPax=v6(e,r+476,12,this.atime)||this.needPax,this.needPax=v6(e,r+488,12,this.ctime)||this.needPax);let f=8*32;for(let p=r;p{let s=t,a="",n,c=TI.parse(t).root||".";if(Buffer.byteLength(s)<100)n=[s,a,!1];else{a=TI.dirname(s),s=TI.basename(s);do Buffer.byteLength(s)<=100&&Buffer.byteLength(a)<=e?n=[s,a,!1]:Buffer.byteLength(s)>100&&Buffer.byteLength(a)<=e?n=[s.substr(0,99),a,!0]:(s=TI.join(TI.basename(a),s),a=TI.dirname(a));while(a!==c&&!n);n||(n=[t.substr(0,99),"",!0])}return n},pm=(t,e,r)=>t.slice(e,e+r).toString("utf8").replace(/\0.*/,""),B6=(t,e,r)=>Oit(Q0(t,e,r)),Oit=t=>t===null?null:new Date(t*1e3),Q0=(t,e,r)=>t[e]&128?The.parse(t.slice(e,e+r)):Mit(t,e,r),Lit=t=>isNaN(t)?null:t,Mit=(t,e,r)=>Lit(parseInt(t.slice(e,e+r).toString("utf8").replace(/\0.*$/,"").trim(),8)),Uit={12:8589934591,8:2097151},T0=(t,e,r,s)=>s===null?!1:s>Uit[r]||s<0?(The.encode(s,t.slice(e,e+r)),!0):(_it(t,e,r,s),!1),_it=(t,e,r,s)=>t.write(Hit(s,r),e,r,"ascii"),Hit=(t,e)=>jit(Math.floor(t).toString(8),e),jit=(t,e)=>(t.length===e-1?t:new Array(e-t.length-1).join("0")+t+" ")+"\0",v6=(t,e,r,s)=>s===null?!1:T0(t,e,r,s.getTime()/1e3),Git=new Array(156).join("\0"),hm=(t,e,r,s)=>s===null?!1:(t.write(s+Git,e,r,"utf8"),s.length!==Buffer.byteLength(s)||s.length>r);Rhe.exports=S6});var KT=_((o3t,Fhe)=>{"use strict";var qit=RI(),Wit=Ie("path"),Sv=class{constructor(e,r){this.atime=e.atime||null,this.charset=e.charset||null,this.comment=e.comment||null,this.ctime=e.ctime||null,this.gid=e.gid||null,this.gname=e.gname||null,this.linkpath=e.linkpath||null,this.mtime=e.mtime||null,this.path=e.path||null,this.size=e.size||null,this.uid=e.uid||null,this.uname=e.uname||null,this.dev=e.dev||null,this.ino=e.ino||null,this.nlink=e.nlink||null,this.global=r||!1}encode(){let e=this.encodeBody();if(e==="")return null;let r=Buffer.byteLength(e),s=512*Math.ceil(1+r/512),a=Buffer.allocUnsafe(s);for(let n=0;n<512;n++)a[n]=0;new qit({path:("PaxHeader/"+Wit.basename(this.path)).slice(0,99),mode:this.mode||420,uid:this.uid||null,gid:this.gid||null,size:r,mtime:this.mtime||null,type:this.global?"GlobalExtendedHeader":"ExtendedHeader",linkpath:"",uname:this.uname||"",gname:this.gname||"",devmaj:0,devmin:0,atime:this.atime||null,ctime:this.ctime||null}).encode(a),a.write(e,512,r,"utf8");for(let n=r+512;n=Math.pow(10,n)&&(n+=1),n+a+s}};Sv.parse=(t,e,r)=>new Sv(Yit(Vit(t),e),r);var Yit=(t,e)=>e?Object.keys(t).reduce((r,s)=>(r[s]=t[s],r),e):t,Vit=t=>t.replace(/\n$/,"").split(` +`).reduce(Jit,Object.create(null)),Jit=(t,e)=>{let r=parseInt(e,10);if(r!==Buffer.byteLength(e)+1)return t;e=e.substr((r+" ").length);let s=e.split("="),a=s.shift().replace(/^SCHILY\.(dev|ino|nlink)/,"$1");if(!a)return t;let n=s.join("=");return t[a]=/^([A-Z]+\.)?([mac]|birth|creation)time$/.test(a)?new Date(n*1e3):/^[0-9]+$/.test(n)?+n:n,t};Fhe.exports=Sv});var FI=_((a3t,Nhe)=>{Nhe.exports=t=>{let e=t.length-1,r=-1;for(;e>-1&&t.charAt(e)==="/";)r=e,e--;return r===-1?t:t.slice(0,r)}});var zT=_((l3t,Ohe)=>{"use strict";Ohe.exports=t=>class extends t{warn(e,r,s={}){this.file&&(s.file=this.file),this.cwd&&(s.cwd=this.cwd),s.code=r instanceof Error&&r.code||e,s.tarCode=e,!this.strict&&s.recoverable!==!1?(r instanceof Error&&(s=Object.assign(r,s),r=r.message),this.emit("warn",s.tarCode,r,s)):r instanceof Error?this.emit("error",Object.assign(r,s)):this.emit("error",Object.assign(new Error(`${e}: ${r}`),s))}}});var b6=_((u3t,Lhe)=>{"use strict";var XT=["|","<",">","?",":"],D6=XT.map(t=>String.fromCharCode(61440+t.charCodeAt(0))),Kit=new Map(XT.map((t,e)=>[t,D6[e]])),zit=new Map(D6.map((t,e)=>[t,XT[e]]));Lhe.exports={encode:t=>XT.reduce((e,r)=>e.split(r).join(Kit.get(r)),t),decode:t=>D6.reduce((e,r)=>e.split(r).join(zit.get(r)),t)}});var P6=_((f3t,Uhe)=>{var{isAbsolute:Xit,parse:Mhe}=Ie("path").win32;Uhe.exports=t=>{let e="",r=Mhe(t);for(;Xit(t)||r.root;){let s=t.charAt(0)==="/"&&t.slice(0,4)!=="//?/"?"/":r.root;t=t.substr(s.length),e+=s,r=Mhe(t)}return[e,t]}});var Hhe=_((A3t,_he)=>{"use strict";_he.exports=(t,e,r)=>(t&=4095,r&&(t=(t|384)&-19),e&&(t&256&&(t|=64),t&32&&(t|=8),t&4&&(t|=1)),t)});var M6=_((g3t,t0e)=>{"use strict";var Jhe=PI(),Khe=KT(),zhe=RI(),nA=Ie("fs"),jhe=Ie("path"),rA=QI(),Zit=FI(),Xhe=(t,e)=>e?(t=rA(t).replace(/^\.(\/|$)/,""),Zit(e)+"/"+t):rA(t),$it=16*1024*1024,Ghe=Symbol("process"),qhe=Symbol("file"),Whe=Symbol("directory"),k6=Symbol("symlink"),Yhe=Symbol("hardlink"),Dv=Symbol("header"),ZT=Symbol("read"),Q6=Symbol("lstat"),$T=Symbol("onlstat"),T6=Symbol("onread"),R6=Symbol("onreadlink"),F6=Symbol("openfile"),N6=Symbol("onopenfile"),R0=Symbol("close"),eR=Symbol("mode"),O6=Symbol("awaitDrain"),x6=Symbol("ondrain"),iA=Symbol("prefix"),Vhe=Symbol("hadError"),Zhe=zT(),est=b6(),$he=P6(),e0e=Hhe(),tR=Zhe(class extends Jhe{constructor(e,r){if(r=r||{},super(r),typeof e!="string")throw new TypeError("path is required");this.path=rA(e),this.portable=!!r.portable,this.myuid=process.getuid&&process.getuid()||0,this.myuser=process.env.USER||"",this.maxReadSize=r.maxReadSize||$it,this.linkCache=r.linkCache||new Map,this.statCache=r.statCache||new Map,this.preservePaths=!!r.preservePaths,this.cwd=rA(r.cwd||process.cwd()),this.strict=!!r.strict,this.noPax=!!r.noPax,this.noMtime=!!r.noMtime,this.mtime=r.mtime||null,this.prefix=r.prefix?rA(r.prefix):null,this.fd=null,this.blockLen=null,this.blockRemain=null,this.buf=null,this.offset=null,this.length=null,this.pos=null,this.remain=null,typeof r.onwarn=="function"&&this.on("warn",r.onwarn);let s=!1;if(!this.preservePaths){let[a,n]=$he(this.path);a&&(this.path=n,s=a)}this.win32=!!r.win32||process.platform==="win32",this.win32&&(this.path=est.decode(this.path.replace(/\\/g,"/")),e=e.replace(/\\/g,"/")),this.absolute=rA(r.absolute||jhe.resolve(this.cwd,e)),this.path===""&&(this.path="./"),s&&this.warn("TAR_ENTRY_INFO",`stripping ${s} from absolute path`,{entry:this,path:s+this.path}),this.statCache.has(this.absolute)?this[$T](this.statCache.get(this.absolute)):this[Q6]()}emit(e,...r){return e==="error"&&(this[Vhe]=!0),super.emit(e,...r)}[Q6](){nA.lstat(this.absolute,(e,r)=>{if(e)return this.emit("error",e);this[$T](r)})}[$T](e){this.statCache.set(this.absolute,e),this.stat=e,e.isFile()||(e.size=0),this.type=rst(e),this.emit("stat",e),this[Ghe]()}[Ghe](){switch(this.type){case"File":return this[qhe]();case"Directory":return this[Whe]();case"SymbolicLink":return this[k6]();default:return this.end()}}[eR](e){return e0e(e,this.type==="Directory",this.portable)}[iA](e){return Xhe(e,this.prefix)}[Dv](){this.type==="Directory"&&this.portable&&(this.noMtime=!0),this.header=new zhe({path:this[iA](this.path),linkpath:this.type==="Link"?this[iA](this.linkpath):this.linkpath,mode:this[eR](this.stat.mode),uid:this.portable?null:this.stat.uid,gid:this.portable?null:this.stat.gid,size:this.stat.size,mtime:this.noMtime?null:this.mtime||this.stat.mtime,type:this.type,uname:this.portable?null:this.stat.uid===this.myuid?this.myuser:"",atime:this.portable?null:this.stat.atime,ctime:this.portable?null:this.stat.ctime}),this.header.encode()&&!this.noPax&&super.write(new Khe({atime:this.portable?null:this.header.atime,ctime:this.portable?null:this.header.ctime,gid:this.portable?null:this.header.gid,mtime:this.noMtime?null:this.mtime||this.header.mtime,path:this[iA](this.path),linkpath:this.type==="Link"?this[iA](this.linkpath):this.linkpath,size:this.header.size,uid:this.portable?null:this.header.uid,uname:this.portable?null:this.header.uname,dev:this.portable?null:this.stat.dev,ino:this.portable?null:this.stat.ino,nlink:this.portable?null:this.stat.nlink}).encode()),super.write(this.header.block)}[Whe](){this.path.substr(-1)!=="/"&&(this.path+="/"),this.stat.size=0,this[Dv](),this.end()}[k6](){nA.readlink(this.absolute,(e,r)=>{if(e)return this.emit("error",e);this[R6](r)})}[R6](e){this.linkpath=rA(e),this[Dv](),this.end()}[Yhe](e){this.type="Link",this.linkpath=rA(jhe.relative(this.cwd,e)),this.stat.size=0,this[Dv](),this.end()}[qhe](){if(this.stat.nlink>1){let e=this.stat.dev+":"+this.stat.ino;if(this.linkCache.has(e)){let r=this.linkCache.get(e);if(r.indexOf(this.cwd)===0)return this[Yhe](r)}this.linkCache.set(e,this.absolute)}if(this[Dv](),this.stat.size===0)return this.end();this[F6]()}[F6](){nA.open(this.absolute,"r",(e,r)=>{if(e)return this.emit("error",e);this[N6](r)})}[N6](e){if(this.fd=e,this[Vhe])return this[R0]();this.blockLen=512*Math.ceil(this.stat.size/512),this.blockRemain=this.blockLen;let r=Math.min(this.blockLen,this.maxReadSize);this.buf=Buffer.allocUnsafe(r),this.offset=0,this.pos=0,this.remain=this.stat.size,this.length=this.buf.length,this[ZT]()}[ZT](){let{fd:e,buf:r,offset:s,length:a,pos:n}=this;nA.read(e,r,s,a,n,(c,f)=>{if(c)return this[R0](()=>this.emit("error",c));this[T6](f)})}[R0](e){nA.close(this.fd,e)}[T6](e){if(e<=0&&this.remain>0){let a=new Error("encountered unexpected EOF");return a.path=this.absolute,a.syscall="read",a.code="EOF",this[R0](()=>this.emit("error",a))}if(e>this.remain){let a=new Error("did not encounter expected EOF");return a.path=this.absolute,a.syscall="read",a.code="EOF",this[R0](()=>this.emit("error",a))}if(e===this.remain)for(let a=e;athis[x6]())}[O6](e){this.once("drain",e)}write(e){if(this.blockRemaine?this.emit("error",e):this.end());this.offset>=this.length&&(this.buf=Buffer.allocUnsafe(Math.min(this.blockRemain,this.buf.length)),this.offset=0),this.length=this.buf.length-this.offset,this[ZT]()}}),L6=class extends tR{[Q6](){this[$T](nA.lstatSync(this.absolute))}[k6](){this[R6](nA.readlinkSync(this.absolute))}[F6](){this[N6](nA.openSync(this.absolute,"r"))}[ZT](){let e=!0;try{let{fd:r,buf:s,offset:a,length:n,pos:c}=this,f=nA.readSync(r,s,a,n,c);this[T6](f),e=!1}finally{if(e)try{this[R0](()=>{})}catch{}}}[O6](e){e()}[R0](e){nA.closeSync(this.fd),e()}},tst=Zhe(class extends Jhe{constructor(e,r){r=r||{},super(r),this.preservePaths=!!r.preservePaths,this.portable=!!r.portable,this.strict=!!r.strict,this.noPax=!!r.noPax,this.noMtime=!!r.noMtime,this.readEntry=e,this.type=e.type,this.type==="Directory"&&this.portable&&(this.noMtime=!0),this.prefix=r.prefix||null,this.path=rA(e.path),this.mode=this[eR](e.mode),this.uid=this.portable?null:e.uid,this.gid=this.portable?null:e.gid,this.uname=this.portable?null:e.uname,this.gname=this.portable?null:e.gname,this.size=e.size,this.mtime=this.noMtime?null:r.mtime||e.mtime,this.atime=this.portable?null:e.atime,this.ctime=this.portable?null:e.ctime,this.linkpath=rA(e.linkpath),typeof r.onwarn=="function"&&this.on("warn",r.onwarn);let s=!1;if(!this.preservePaths){let[a,n]=$he(this.path);a&&(this.path=n,s=a)}this.remain=e.size,this.blockRemain=e.startBlockSize,this.header=new zhe({path:this[iA](this.path),linkpath:this.type==="Link"?this[iA](this.linkpath):this.linkpath,mode:this.mode,uid:this.portable?null:this.uid,gid:this.portable?null:this.gid,size:this.size,mtime:this.noMtime?null:this.mtime,type:this.type,uname:this.portable?null:this.uname,atime:this.portable?null:this.atime,ctime:this.portable?null:this.ctime}),s&&this.warn("TAR_ENTRY_INFO",`stripping ${s} from absolute path`,{entry:this,path:s+this.path}),this.header.encode()&&!this.noPax&&super.write(new Khe({atime:this.portable?null:this.atime,ctime:this.portable?null:this.ctime,gid:this.portable?null:this.gid,mtime:this.noMtime?null:this.mtime,path:this[iA](this.path),linkpath:this.type==="Link"?this[iA](this.linkpath):this.linkpath,size:this.size,uid:this.portable?null:this.uid,uname:this.portable?null:this.uname,dev:this.portable?null:this.readEntry.dev,ino:this.portable?null:this.readEntry.ino,nlink:this.portable?null:this.readEntry.nlink}).encode()),super.write(this.header.block),e.pipe(this)}[iA](e){return Xhe(e,this.prefix)}[eR](e){return e0e(e,this.type==="Directory",this.portable)}write(e){let r=e.length;if(r>this.blockRemain)throw new Error("writing more to entry than is appropriate");return this.blockRemain-=r,super.write(e)}end(){return this.blockRemain&&super.write(Buffer.alloc(this.blockRemain)),super.end()}});tR.Sync=L6;tR.Tar=tst;var rst=t=>t.isFile()?"File":t.isDirectory()?"Directory":t.isSymbolicLink()?"SymbolicLink":"Unsupported";t0e.exports=tR});var uR=_((m3t,l0e)=>{"use strict";var lR=class{constructor(e,r){this.path=e||"./",this.absolute=r,this.entry=null,this.stat=null,this.readdir=null,this.pending=!1,this.ignore=!1,this.piped=!1}},nst=PI(),ist=m6(),sst=VT(),V6=M6(),ost=V6.Sync,ast=V6.Tar,lst=$x(),r0e=Buffer.alloc(1024),iR=Symbol("onStat"),rR=Symbol("ended"),sA=Symbol("queue"),NI=Symbol("current"),gm=Symbol("process"),nR=Symbol("processing"),n0e=Symbol("processJob"),oA=Symbol("jobs"),U6=Symbol("jobDone"),sR=Symbol("addFSEntry"),i0e=Symbol("addTarEntry"),G6=Symbol("stat"),q6=Symbol("readdir"),oR=Symbol("onreaddir"),aR=Symbol("pipe"),s0e=Symbol("entry"),_6=Symbol("entryOpt"),W6=Symbol("writeEntryClass"),a0e=Symbol("write"),H6=Symbol("ondrain"),cR=Ie("fs"),o0e=Ie("path"),cst=zT(),j6=QI(),J6=cst(class extends nst{constructor(e){super(e),e=e||Object.create(null),this.opt=e,this.file=e.file||"",this.cwd=e.cwd||process.cwd(),this.maxReadSize=e.maxReadSize,this.preservePaths=!!e.preservePaths,this.strict=!!e.strict,this.noPax=!!e.noPax,this.prefix=j6(e.prefix||""),this.linkCache=e.linkCache||new Map,this.statCache=e.statCache||new Map,this.readdirCache=e.readdirCache||new Map,this[W6]=V6,typeof e.onwarn=="function"&&this.on("warn",e.onwarn),this.portable=!!e.portable,this.zip=null,e.gzip?(typeof e.gzip!="object"&&(e.gzip={}),this.portable&&(e.gzip.portable=!0),this.zip=new ist.Gzip(e.gzip),this.zip.on("data",r=>super.write(r)),this.zip.on("end",r=>super.end()),this.zip.on("drain",r=>this[H6]()),this.on("resume",r=>this.zip.resume())):this.on("drain",this[H6]),this.noDirRecurse=!!e.noDirRecurse,this.follow=!!e.follow,this.noMtime=!!e.noMtime,this.mtime=e.mtime||null,this.filter=typeof e.filter=="function"?e.filter:r=>!0,this[sA]=new lst,this[oA]=0,this.jobs=+e.jobs||4,this[nR]=!1,this[rR]=!1}[a0e](e){return super.write(e)}add(e){return this.write(e),this}end(e){return e&&this.write(e),this[rR]=!0,this[gm](),this}write(e){if(this[rR])throw new Error("write after end");return e instanceof sst?this[i0e](e):this[sR](e),this.flowing}[i0e](e){let r=j6(o0e.resolve(this.cwd,e.path));if(!this.filter(e.path,e))e.resume();else{let s=new lR(e.path,r,!1);s.entry=new ast(e,this[_6](s)),s.entry.on("end",a=>this[U6](s)),this[oA]+=1,this[sA].push(s)}this[gm]()}[sR](e){let r=j6(o0e.resolve(this.cwd,e));this[sA].push(new lR(e,r)),this[gm]()}[G6](e){e.pending=!0,this[oA]+=1;let r=this.follow?"stat":"lstat";cR[r](e.absolute,(s,a)=>{e.pending=!1,this[oA]-=1,s?this.emit("error",s):this[iR](e,a)})}[iR](e,r){this.statCache.set(e.absolute,r),e.stat=r,this.filter(e.path,r)||(e.ignore=!0),this[gm]()}[q6](e){e.pending=!0,this[oA]+=1,cR.readdir(e.absolute,(r,s)=>{if(e.pending=!1,this[oA]-=1,r)return this.emit("error",r);this[oR](e,s)})}[oR](e,r){this.readdirCache.set(e.absolute,r),e.readdir=r,this[gm]()}[gm](){if(!this[nR]){this[nR]=!0;for(let e=this[sA].head;e!==null&&this[oA]this.warn(r,s,a),noPax:this.noPax,cwd:this.cwd,absolute:e.absolute,preservePaths:this.preservePaths,maxReadSize:this.maxReadSize,strict:this.strict,portable:this.portable,linkCache:this.linkCache,statCache:this.statCache,noMtime:this.noMtime,mtime:this.mtime,prefix:this.prefix}}[s0e](e){this[oA]+=1;try{return new this[W6](e.path,this[_6](e)).on("end",()=>this[U6](e)).on("error",r=>this.emit("error",r))}catch(r){this.emit("error",r)}}[H6](){this[NI]&&this[NI].entry&&this[NI].entry.resume()}[aR](e){e.piped=!0,e.readdir&&e.readdir.forEach(a=>{let n=e.path,c=n==="./"?"":n.replace(/\/*$/,"/");this[sR](c+a)});let r=e.entry,s=this.zip;s?r.on("data",a=>{s.write(a)||r.pause()}):r.on("data",a=>{super.write(a)||r.pause()})}pause(){return this.zip&&this.zip.pause(),super.pause()}}),Y6=class extends J6{constructor(e){super(e),this[W6]=ost}pause(){}resume(){}[G6](e){let r=this.follow?"statSync":"lstatSync";this[iR](e,cR[r](e.absolute))}[q6](e,r){this[oR](e,cR.readdirSync(e.absolute))}[aR](e){let r=e.entry,s=this.zip;e.readdir&&e.readdir.forEach(a=>{let n=e.path,c=n==="./"?"":n.replace(/\/*$/,"/");this[sR](c+a)}),s?r.on("data",a=>{s.write(a)}):r.on("data",a=>{super[a0e](a)})}};J6.Sync=Y6;l0e.exports=J6});var GI=_(Pv=>{"use strict";var ust=PI(),fst=Ie("events").EventEmitter,fl=Ie("fs"),X6=fl.writev;if(!X6){let t=process.binding("fs"),e=t.FSReqWrap||t.FSReqCallback;X6=(r,s,a,n)=>{let c=(p,h)=>n(p,h,s),f=new e;f.oncomplete=c,t.writeBuffers(r,s,a,f)}}var HI=Symbol("_autoClose"),Yu=Symbol("_close"),bv=Symbol("_ended"),ii=Symbol("_fd"),c0e=Symbol("_finished"),N0=Symbol("_flags"),K6=Symbol("_flush"),Z6=Symbol("_handleChunk"),$6=Symbol("_makeBuf"),gR=Symbol("_mode"),fR=Symbol("_needDrain"),UI=Symbol("_onerror"),jI=Symbol("_onopen"),z6=Symbol("_onread"),LI=Symbol("_onwrite"),O0=Symbol("_open"),Wp=Symbol("_path"),dm=Symbol("_pos"),aA=Symbol("_queue"),MI=Symbol("_read"),u0e=Symbol("_readSize"),F0=Symbol("_reading"),AR=Symbol("_remain"),f0e=Symbol("_size"),pR=Symbol("_write"),OI=Symbol("_writing"),hR=Symbol("_defaultFlag"),_I=Symbol("_errored"),dR=class extends ust{constructor(e,r){if(r=r||{},super(r),this.readable=!0,this.writable=!1,typeof e!="string")throw new TypeError("path must be a string");this[_I]=!1,this[ii]=typeof r.fd=="number"?r.fd:null,this[Wp]=e,this[u0e]=r.readSize||16*1024*1024,this[F0]=!1,this[f0e]=typeof r.size=="number"?r.size:1/0,this[AR]=this[f0e],this[HI]=typeof r.autoClose=="boolean"?r.autoClose:!0,typeof this[ii]=="number"?this[MI]():this[O0]()}get fd(){return this[ii]}get path(){return this[Wp]}write(){throw new TypeError("this is a readable stream")}end(){throw new TypeError("this is a readable stream")}[O0](){fl.open(this[Wp],"r",(e,r)=>this[jI](e,r))}[jI](e,r){e?this[UI](e):(this[ii]=r,this.emit("open",r),this[MI]())}[$6](){return Buffer.allocUnsafe(Math.min(this[u0e],this[AR]))}[MI](){if(!this[F0]){this[F0]=!0;let e=this[$6]();if(e.length===0)return process.nextTick(()=>this[z6](null,0,e));fl.read(this[ii],e,0,e.length,null,(r,s,a)=>this[z6](r,s,a))}}[z6](e,r,s){this[F0]=!1,e?this[UI](e):this[Z6](r,s)&&this[MI]()}[Yu](){if(this[HI]&&typeof this[ii]=="number"){let e=this[ii];this[ii]=null,fl.close(e,r=>r?this.emit("error",r):this.emit("close"))}}[UI](e){this[F0]=!0,this[Yu](),this.emit("error",e)}[Z6](e,r){let s=!1;return this[AR]-=e,e>0&&(s=super.write(ethis[jI](e,r))}[jI](e,r){this[hR]&&this[N0]==="r+"&&e&&e.code==="ENOENT"?(this[N0]="w",this[O0]()):e?this[UI](e):(this[ii]=r,this.emit("open",r),this[K6]())}end(e,r){return e&&this.write(e,r),this[bv]=!0,!this[OI]&&!this[aA].length&&typeof this[ii]=="number"&&this[LI](null,0),this}write(e,r){return typeof e=="string"&&(e=Buffer.from(e,r)),this[bv]?(this.emit("error",new Error("write() after end()")),!1):this[ii]===null||this[OI]||this[aA].length?(this[aA].push(e),this[fR]=!0,!1):(this[OI]=!0,this[pR](e),!0)}[pR](e){fl.write(this[ii],e,0,e.length,this[dm],(r,s)=>this[LI](r,s))}[LI](e,r){e?this[UI](e):(this[dm]!==null&&(this[dm]+=r),this[aA].length?this[K6]():(this[OI]=!1,this[bv]&&!this[c0e]?(this[c0e]=!0,this[Yu](),this.emit("finish")):this[fR]&&(this[fR]=!1,this.emit("drain"))))}[K6](){if(this[aA].length===0)this[bv]&&this[LI](null,0);else if(this[aA].length===1)this[pR](this[aA].pop());else{let e=this[aA];this[aA]=[],X6(this[ii],e,this[dm],(r,s)=>this[LI](r,s))}}[Yu](){if(this[HI]&&typeof this[ii]=="number"){let e=this[ii];this[ii]=null,fl.close(e,r=>r?this.emit("error",r):this.emit("close"))}}},tG=class extends mR{[O0](){let e;if(this[hR]&&this[N0]==="r+")try{e=fl.openSync(this[Wp],this[N0],this[gR])}catch(r){if(r.code==="ENOENT")return this[N0]="w",this[O0]();throw r}else e=fl.openSync(this[Wp],this[N0],this[gR]);this[jI](null,e)}[Yu](){if(this[HI]&&typeof this[ii]=="number"){let e=this[ii];this[ii]=null,fl.closeSync(e),this.emit("close")}}[pR](e){let r=!0;try{this[LI](null,fl.writeSync(this[ii],e,0,e.length,this[dm])),r=!1}finally{if(r)try{this[Yu]()}catch{}}}};Pv.ReadStream=dR;Pv.ReadStreamSync=eG;Pv.WriteStream=mR;Pv.WriteStreamSync=tG});var vR=_((I3t,y0e)=>{"use strict";var Ast=zT(),pst=RI(),hst=Ie("events"),gst=$x(),dst=1024*1024,mst=VT(),A0e=KT(),yst=m6(),rG=Buffer.from([31,139]),Lc=Symbol("state"),mm=Symbol("writeEntry"),Yp=Symbol("readEntry"),nG=Symbol("nextEntry"),p0e=Symbol("processEntry"),Mc=Symbol("extendedHeader"),xv=Symbol("globalExtendedHeader"),L0=Symbol("meta"),h0e=Symbol("emitMeta"),Di=Symbol("buffer"),Vp=Symbol("queue"),ym=Symbol("ended"),g0e=Symbol("emittedEnd"),Em=Symbol("emit"),Al=Symbol("unzip"),yR=Symbol("consumeChunk"),ER=Symbol("consumeChunkSub"),iG=Symbol("consumeBody"),d0e=Symbol("consumeMeta"),m0e=Symbol("consumeHeader"),IR=Symbol("consuming"),sG=Symbol("bufferConcat"),oG=Symbol("maybeEnd"),kv=Symbol("writing"),M0=Symbol("aborted"),CR=Symbol("onDone"),Im=Symbol("sawValidEntry"),wR=Symbol("sawNullBlock"),BR=Symbol("sawEOF"),Est=t=>!0;y0e.exports=Ast(class extends hst{constructor(e){e=e||{},super(e),this.file=e.file||"",this[Im]=null,this.on(CR,r=>{(this[Lc]==="begin"||this[Im]===!1)&&this.warn("TAR_BAD_ARCHIVE","Unrecognized archive format")}),e.ondone?this.on(CR,e.ondone):this.on(CR,r=>{this.emit("prefinish"),this.emit("finish"),this.emit("end"),this.emit("close")}),this.strict=!!e.strict,this.maxMetaEntrySize=e.maxMetaEntrySize||dst,this.filter=typeof e.filter=="function"?e.filter:Est,this.writable=!0,this.readable=!1,this[Vp]=new gst,this[Di]=null,this[Yp]=null,this[mm]=null,this[Lc]="begin",this[L0]="",this[Mc]=null,this[xv]=null,this[ym]=!1,this[Al]=null,this[M0]=!1,this[wR]=!1,this[BR]=!1,typeof e.onwarn=="function"&&this.on("warn",e.onwarn),typeof e.onentry=="function"&&this.on("entry",e.onentry)}[m0e](e,r){this[Im]===null&&(this[Im]=!1);let s;try{s=new pst(e,r,this[Mc],this[xv])}catch(a){return this.warn("TAR_ENTRY_INVALID",a)}if(s.nullBlock)this[wR]?(this[BR]=!0,this[Lc]==="begin"&&(this[Lc]="header"),this[Em]("eof")):(this[wR]=!0,this[Em]("nullBlock"));else if(this[wR]=!1,!s.cksumValid)this.warn("TAR_ENTRY_INVALID","checksum failure",{header:s});else if(!s.path)this.warn("TAR_ENTRY_INVALID","path is required",{header:s});else{let a=s.type;if(/^(Symbolic)?Link$/.test(a)&&!s.linkpath)this.warn("TAR_ENTRY_INVALID","linkpath required",{header:s});else if(!/^(Symbolic)?Link$/.test(a)&&s.linkpath)this.warn("TAR_ENTRY_INVALID","linkpath forbidden",{header:s});else{let n=this[mm]=new mst(s,this[Mc],this[xv]);if(!this[Im])if(n.remain){let c=()=>{n.invalid||(this[Im]=!0)};n.on("end",c)}else this[Im]=!0;n.meta?n.size>this.maxMetaEntrySize?(n.ignore=!0,this[Em]("ignoredEntry",n),this[Lc]="ignore",n.resume()):n.size>0&&(this[L0]="",n.on("data",c=>this[L0]+=c),this[Lc]="meta"):(this[Mc]=null,n.ignore=n.ignore||!this.filter(n.path,n),n.ignore?(this[Em]("ignoredEntry",n),this[Lc]=n.remain?"ignore":"header",n.resume()):(n.remain?this[Lc]="body":(this[Lc]="header",n.end()),this[Yp]?this[Vp].push(n):(this[Vp].push(n),this[nG]())))}}}[p0e](e){let r=!0;return e?Array.isArray(e)?this.emit.apply(this,e):(this[Yp]=e,this.emit("entry",e),e.emittedEnd||(e.on("end",s=>this[nG]()),r=!1)):(this[Yp]=null,r=!1),r}[nG](){do;while(this[p0e](this[Vp].shift()));if(!this[Vp].length){let e=this[Yp];!e||e.flowing||e.size===e.remain?this[kv]||this.emit("drain"):e.once("drain",s=>this.emit("drain"))}}[iG](e,r){let s=this[mm],a=s.blockRemain,n=a>=e.length&&r===0?e:e.slice(r,r+a);return s.write(n),s.blockRemain||(this[Lc]="header",this[mm]=null,s.end()),n.length}[d0e](e,r){let s=this[mm],a=this[iG](e,r);return this[mm]||this[h0e](s),a}[Em](e,r,s){!this[Vp].length&&!this[Yp]?this.emit(e,r,s):this[Vp].push([e,r,s])}[h0e](e){switch(this[Em]("meta",this[L0]),e.type){case"ExtendedHeader":case"OldExtendedHeader":this[Mc]=A0e.parse(this[L0],this[Mc],!1);break;case"GlobalExtendedHeader":this[xv]=A0e.parse(this[L0],this[xv],!0);break;case"NextFileHasLongPath":case"OldGnuLongPath":this[Mc]=this[Mc]||Object.create(null),this[Mc].path=this[L0].replace(/\0.*/,"");break;case"NextFileHasLongLinkpath":this[Mc]=this[Mc]||Object.create(null),this[Mc].linkpath=this[L0].replace(/\0.*/,"");break;default:throw new Error("unknown meta: "+e.type)}}abort(e){this[M0]=!0,this.emit("abort",e),this.warn("TAR_ABORT",e,{recoverable:!1})}write(e){if(this[M0])return;if(this[Al]===null&&e){if(this[Di]&&(e=Buffer.concat([this[Di],e]),this[Di]=null),e.lengththis[yR](n)),this[Al].on("error",n=>this.abort(n)),this[Al].on("end",n=>{this[ym]=!0,this[yR]()}),this[kv]=!0;let a=this[Al][s?"end":"write"](e);return this[kv]=!1,a}}this[kv]=!0,this[Al]?this[Al].write(e):this[yR](e),this[kv]=!1;let r=this[Vp].length?!1:this[Yp]?this[Yp].flowing:!0;return!r&&!this[Vp].length&&this[Yp].once("drain",s=>this.emit("drain")),r}[sG](e){e&&!this[M0]&&(this[Di]=this[Di]?Buffer.concat([this[Di],e]):e)}[oG](){if(this[ym]&&!this[g0e]&&!this[M0]&&!this[IR]){this[g0e]=!0;let e=this[mm];if(e&&e.blockRemain){let r=this[Di]?this[Di].length:0;this.warn("TAR_BAD_ARCHIVE",`Truncated input (needed ${e.blockRemain} more bytes, only ${r} available)`,{entry:e}),this[Di]&&e.write(this[Di]),e.end()}this[Em](CR)}}[yR](e){if(this[IR])this[sG](e);else if(!e&&!this[Di])this[oG]();else{if(this[IR]=!0,this[Di]){this[sG](e);let r=this[Di];this[Di]=null,this[ER](r)}else this[ER](e);for(;this[Di]&&this[Di].length>=512&&!this[M0]&&!this[BR];){let r=this[Di];this[Di]=null,this[ER](r)}this[IR]=!1}(!this[Di]||this[ym])&&this[oG]()}[ER](e){let r=0,s=e.length;for(;r+512<=s&&!this[M0]&&!this[BR];)switch(this[Lc]){case"begin":case"header":this[m0e](e,r),r+=512;break;case"ignore":case"body":r+=this[iG](e,r);break;case"meta":r+=this[d0e](e,r);break;default:throw new Error("invalid state: "+this[Lc])}r{"use strict";var Ist=DI(),I0e=vR(),qI=Ie("fs"),Cst=GI(),E0e=Ie("path"),aG=FI();w0e.exports=(t,e,r)=>{typeof t=="function"?(r=t,e=null,t={}):Array.isArray(t)&&(e=t,t={}),typeof e=="function"&&(r=e,e=null),e?e=Array.from(e):e=[];let s=Ist(t);if(s.sync&&typeof r=="function")throw new TypeError("callback not supported for sync tar functions");if(!s.file&&typeof r=="function")throw new TypeError("callback only supported with file option");return e.length&&Bst(s,e),s.noResume||wst(s),s.file&&s.sync?vst(s):s.file?Sst(s,r):C0e(s)};var wst=t=>{let e=t.onentry;t.onentry=e?r=>{e(r),r.resume()}:r=>r.resume()},Bst=(t,e)=>{let r=new Map(e.map(n=>[aG(n),!0])),s=t.filter,a=(n,c)=>{let f=c||E0e.parse(n).root||".",p=n===f?!1:r.has(n)?r.get(n):a(E0e.dirname(n),f);return r.set(n,p),p};t.filter=s?(n,c)=>s(n,c)&&a(aG(n)):n=>a(aG(n))},vst=t=>{let e=C0e(t),r=t.file,s=!0,a;try{let n=qI.statSync(r),c=t.maxReadSize||16*1024*1024;if(n.size{let r=new I0e(t),s=t.maxReadSize||16*1024*1024,a=t.file,n=new Promise((c,f)=>{r.on("error",f),r.on("end",c),qI.stat(a,(p,h)=>{if(p)f(p);else{let E=new Cst.ReadStream(a,{readSize:s,size:h.size});E.on("error",f),E.pipe(r)}})});return e?n.then(e,e):n},C0e=t=>new I0e(t)});var P0e=_((w3t,b0e)=>{"use strict";var Dst=DI(),DR=uR(),B0e=GI(),v0e=SR(),S0e=Ie("path");b0e.exports=(t,e,r)=>{if(typeof e=="function"&&(r=e),Array.isArray(t)&&(e=t,t={}),!e||!Array.isArray(e)||!e.length)throw new TypeError("no files or directories specified");e=Array.from(e);let s=Dst(t);if(s.sync&&typeof r=="function")throw new TypeError("callback not supported for sync tar functions");if(!s.file&&typeof r=="function")throw new TypeError("callback only supported with file option");return s.file&&s.sync?bst(s,e):s.file?Pst(s,e,r):s.sync?xst(s,e):kst(s,e)};var bst=(t,e)=>{let r=new DR.Sync(t),s=new B0e.WriteStreamSync(t.file,{mode:t.mode||438});r.pipe(s),D0e(r,e)},Pst=(t,e,r)=>{let s=new DR(t),a=new B0e.WriteStream(t.file,{mode:t.mode||438});s.pipe(a);let n=new Promise((c,f)=>{a.on("error",f),a.on("close",c),s.on("error",f)});return lG(s,e),r?n.then(r,r):n},D0e=(t,e)=>{e.forEach(r=>{r.charAt(0)==="@"?v0e({file:S0e.resolve(t.cwd,r.substr(1)),sync:!0,noResume:!0,onentry:s=>t.add(s)}):t.add(r)}),t.end()},lG=(t,e)=>{for(;e.length;){let r=e.shift();if(r.charAt(0)==="@")return v0e({file:S0e.resolve(t.cwd,r.substr(1)),noResume:!0,onentry:s=>t.add(s)}).then(s=>lG(t,e));t.add(r)}t.end()},xst=(t,e)=>{let r=new DR.Sync(t);return D0e(r,e),r},kst=(t,e)=>{let r=new DR(t);return lG(r,e),r}});var cG=_((B3t,N0e)=>{"use strict";var Qst=DI(),x0e=uR(),Xl=Ie("fs"),k0e=GI(),Q0e=SR(),T0e=Ie("path"),R0e=RI();N0e.exports=(t,e,r)=>{let s=Qst(t);if(!s.file)throw new TypeError("file is required");if(s.gzip)throw new TypeError("cannot append to compressed archives");if(!e||!Array.isArray(e)||!e.length)throw new TypeError("no files or directories specified");return e=Array.from(e),s.sync?Tst(s,e):Fst(s,e,r)};var Tst=(t,e)=>{let r=new x0e.Sync(t),s=!0,a,n;try{try{a=Xl.openSync(t.file,"r+")}catch(p){if(p.code==="ENOENT")a=Xl.openSync(t.file,"w+");else throw p}let c=Xl.fstatSync(a),f=Buffer.alloc(512);e:for(n=0;nc.size)break;n+=h,t.mtimeCache&&t.mtimeCache.set(p.path,p.mtime)}s=!1,Rst(t,r,n,a,e)}finally{if(s)try{Xl.closeSync(a)}catch{}}},Rst=(t,e,r,s,a)=>{let n=new k0e.WriteStreamSync(t.file,{fd:s,start:r});e.pipe(n),Nst(e,a)},Fst=(t,e,r)=>{e=Array.from(e);let s=new x0e(t),a=(c,f,p)=>{let h=(I,R)=>{I?Xl.close(c,N=>p(I)):p(null,R)},E=0;if(f===0)return h(null,0);let C=0,S=Buffer.alloc(512),P=(I,R)=>{if(I)return h(I);if(C+=R,C<512&&R)return Xl.read(c,S,C,S.length-C,E+C,P);if(E===0&&S[0]===31&&S[1]===139)return h(new Error("cannot append to compressed archives"));if(C<512)return h(null,E);let N=new R0e(S);if(!N.cksumValid)return h(null,E);let U=512*Math.ceil(N.size/512);if(E+U+512>f||(E+=U+512,E>=f))return h(null,E);t.mtimeCache&&t.mtimeCache.set(N.path,N.mtime),C=0,Xl.read(c,S,0,512,E,P)};Xl.read(c,S,0,512,E,P)},n=new Promise((c,f)=>{s.on("error",f);let p="r+",h=(E,C)=>{if(E&&E.code==="ENOENT"&&p==="r+")return p="w+",Xl.open(t.file,p,h);if(E)return f(E);Xl.fstat(C,(S,P)=>{if(S)return Xl.close(C,()=>f(S));a(C,P.size,(I,R)=>{if(I)return f(I);let N=new k0e.WriteStream(t.file,{fd:C,start:R});s.pipe(N),N.on("error",f),N.on("close",c),F0e(s,e)})})};Xl.open(t.file,p,h)});return r?n.then(r,r):n},Nst=(t,e)=>{e.forEach(r=>{r.charAt(0)==="@"?Q0e({file:T0e.resolve(t.cwd,r.substr(1)),sync:!0,noResume:!0,onentry:s=>t.add(s)}):t.add(r)}),t.end()},F0e=(t,e)=>{for(;e.length;){let r=e.shift();if(r.charAt(0)==="@")return Q0e({file:T0e.resolve(t.cwd,r.substr(1)),noResume:!0,onentry:s=>t.add(s)}).then(s=>F0e(t,e));t.add(r)}t.end()}});var L0e=_((v3t,O0e)=>{"use strict";var Ost=DI(),Lst=cG();O0e.exports=(t,e,r)=>{let s=Ost(t);if(!s.file)throw new TypeError("file is required");if(s.gzip)throw new TypeError("cannot append to compressed archives");if(!e||!Array.isArray(e)||!e.length)throw new TypeError("no files or directories specified");return e=Array.from(e),Mst(s),Lst(s,e,r)};var Mst=t=>{let e=t.filter;t.mtimeCache||(t.mtimeCache=new Map),t.filter=e?(r,s)=>e(r,s)&&!(t.mtimeCache.get(r)>s.mtime):(r,s)=>!(t.mtimeCache.get(r)>s.mtime)}});var _0e=_((S3t,U0e)=>{var{promisify:M0e}=Ie("util"),U0=Ie("fs"),Ust=t=>{if(!t)t={mode:511,fs:U0};else if(typeof t=="object")t={mode:511,fs:U0,...t};else if(typeof t=="number")t={mode:t,fs:U0};else if(typeof t=="string")t={mode:parseInt(t,8),fs:U0};else throw new TypeError("invalid options argument");return t.mkdir=t.mkdir||t.fs.mkdir||U0.mkdir,t.mkdirAsync=M0e(t.mkdir),t.stat=t.stat||t.fs.stat||U0.stat,t.statAsync=M0e(t.stat),t.statSync=t.statSync||t.fs.statSync||U0.statSync,t.mkdirSync=t.mkdirSync||t.fs.mkdirSync||U0.mkdirSync,t};U0e.exports=Ust});var j0e=_((D3t,H0e)=>{var _st=process.platform,{resolve:Hst,parse:jst}=Ie("path"),Gst=t=>{if(/\0/.test(t))throw Object.assign(new TypeError("path must be a string without null bytes"),{path:t,code:"ERR_INVALID_ARG_VALUE"});if(t=Hst(t),_st==="win32"){let e=/[*|"<>?:]/,{root:r}=jst(t);if(e.test(t.substr(r.length)))throw Object.assign(new Error("Illegal characters in path."),{path:t,code:"EINVAL"})}return t};H0e.exports=Gst});var V0e=_((b3t,Y0e)=>{var{dirname:G0e}=Ie("path"),q0e=(t,e,r=void 0)=>r===e?Promise.resolve():t.statAsync(e).then(s=>s.isDirectory()?r:void 0,s=>s.code==="ENOENT"?q0e(t,G0e(e),e):void 0),W0e=(t,e,r=void 0)=>{if(r!==e)try{return t.statSync(e).isDirectory()?r:void 0}catch(s){return s.code==="ENOENT"?W0e(t,G0e(e),e):void 0}};Y0e.exports={findMade:q0e,findMadeSync:W0e}});var AG=_((P3t,K0e)=>{var{dirname:J0e}=Ie("path"),uG=(t,e,r)=>{e.recursive=!1;let s=J0e(t);return s===t?e.mkdirAsync(t,e).catch(a=>{if(a.code!=="EISDIR")throw a}):e.mkdirAsync(t,e).then(()=>r||t,a=>{if(a.code==="ENOENT")return uG(s,e).then(n=>uG(t,e,n));if(a.code!=="EEXIST"&&a.code!=="EROFS")throw a;return e.statAsync(t).then(n=>{if(n.isDirectory())return r;throw a},()=>{throw a})})},fG=(t,e,r)=>{let s=J0e(t);if(e.recursive=!1,s===t)try{return e.mkdirSync(t,e)}catch(a){if(a.code!=="EISDIR")throw a;return}try{return e.mkdirSync(t,e),r||t}catch(a){if(a.code==="ENOENT")return fG(t,e,fG(s,e,r));if(a.code!=="EEXIST"&&a.code!=="EROFS")throw a;try{if(!e.statSync(t).isDirectory())throw a}catch{throw a}}};K0e.exports={mkdirpManual:uG,mkdirpManualSync:fG}});var Z0e=_((x3t,X0e)=>{var{dirname:z0e}=Ie("path"),{findMade:qst,findMadeSync:Wst}=V0e(),{mkdirpManual:Yst,mkdirpManualSync:Vst}=AG(),Jst=(t,e)=>(e.recursive=!0,z0e(t)===t?e.mkdirAsync(t,e):qst(e,t).then(s=>e.mkdirAsync(t,e).then(()=>s).catch(a=>{if(a.code==="ENOENT")return Yst(t,e);throw a}))),Kst=(t,e)=>{if(e.recursive=!0,z0e(t)===t)return e.mkdirSync(t,e);let s=Wst(e,t);try{return e.mkdirSync(t,e),s}catch(a){if(a.code==="ENOENT")return Vst(t,e);throw a}};X0e.exports={mkdirpNative:Jst,mkdirpNativeSync:Kst}});var rge=_((k3t,tge)=>{var $0e=Ie("fs"),zst=process.version,pG=zst.replace(/^v/,"").split("."),ege=+pG[0]>10||+pG[0]==10&&+pG[1]>=12,Xst=ege?t=>t.mkdir===$0e.mkdir:()=>!1,Zst=ege?t=>t.mkdirSync===$0e.mkdirSync:()=>!1;tge.exports={useNative:Xst,useNativeSync:Zst}});var lge=_((Q3t,age)=>{var WI=_0e(),YI=j0e(),{mkdirpNative:nge,mkdirpNativeSync:ige}=Z0e(),{mkdirpManual:sge,mkdirpManualSync:oge}=AG(),{useNative:$st,useNativeSync:eot}=rge(),VI=(t,e)=>(t=YI(t),e=WI(e),$st(e)?nge(t,e):sge(t,e)),tot=(t,e)=>(t=YI(t),e=WI(e),eot(e)?ige(t,e):oge(t,e));VI.sync=tot;VI.native=(t,e)=>nge(YI(t),WI(e));VI.manual=(t,e)=>sge(YI(t),WI(e));VI.nativeSync=(t,e)=>ige(YI(t),WI(e));VI.manualSync=(t,e)=>oge(YI(t),WI(e));age.exports=VI});var gge=_((T3t,hge)=>{"use strict";var Uc=Ie("fs"),Cm=Ie("path"),rot=Uc.lchown?"lchown":"chown",not=Uc.lchownSync?"lchownSync":"chownSync",uge=Uc.lchown&&!process.version.match(/v1[1-9]+\./)&&!process.version.match(/v10\.[6-9]/),cge=(t,e,r)=>{try{return Uc[not](t,e,r)}catch(s){if(s.code!=="ENOENT")throw s}},iot=(t,e,r)=>{try{return Uc.chownSync(t,e,r)}catch(s){if(s.code!=="ENOENT")throw s}},sot=uge?(t,e,r,s)=>a=>{!a||a.code!=="EISDIR"?s(a):Uc.chown(t,e,r,s)}:(t,e,r,s)=>s,hG=uge?(t,e,r)=>{try{return cge(t,e,r)}catch(s){if(s.code!=="EISDIR")throw s;iot(t,e,r)}}:(t,e,r)=>cge(t,e,r),oot=process.version,fge=(t,e,r)=>Uc.readdir(t,e,r),aot=(t,e)=>Uc.readdirSync(t,e);/^v4\./.test(oot)&&(fge=(t,e,r)=>Uc.readdir(t,r));var bR=(t,e,r,s)=>{Uc[rot](t,e,r,sot(t,e,r,a=>{s(a&&a.code!=="ENOENT"?a:null)}))},Age=(t,e,r,s,a)=>{if(typeof e=="string")return Uc.lstat(Cm.resolve(t,e),(n,c)=>{if(n)return a(n.code!=="ENOENT"?n:null);c.name=e,Age(t,c,r,s,a)});if(e.isDirectory())gG(Cm.resolve(t,e.name),r,s,n=>{if(n)return a(n);let c=Cm.resolve(t,e.name);bR(c,r,s,a)});else{let n=Cm.resolve(t,e.name);bR(n,r,s,a)}},gG=(t,e,r,s)=>{fge(t,{withFileTypes:!0},(a,n)=>{if(a){if(a.code==="ENOENT")return s();if(a.code!=="ENOTDIR"&&a.code!=="ENOTSUP")return s(a)}if(a||!n.length)return bR(t,e,r,s);let c=n.length,f=null,p=h=>{if(!f){if(h)return s(f=h);if(--c===0)return bR(t,e,r,s)}};n.forEach(h=>Age(t,h,e,r,p))})},lot=(t,e,r,s)=>{if(typeof e=="string")try{let a=Uc.lstatSync(Cm.resolve(t,e));a.name=e,e=a}catch(a){if(a.code==="ENOENT")return;throw a}e.isDirectory()&&pge(Cm.resolve(t,e.name),r,s),hG(Cm.resolve(t,e.name),r,s)},pge=(t,e,r)=>{let s;try{s=aot(t,{withFileTypes:!0})}catch(a){if(a.code==="ENOENT")return;if(a.code==="ENOTDIR"||a.code==="ENOTSUP")return hG(t,e,r);throw a}return s&&s.length&&s.forEach(a=>lot(t,a,e,r)),hG(t,e,r)};hge.exports=gG;gG.sync=pge});var Ege=_((R3t,dG)=>{"use strict";var dge=lge(),_c=Ie("fs"),PR=Ie("path"),mge=gge(),Vu=QI(),xR=class extends Error{constructor(e,r){super("Cannot extract through symbolic link"),this.path=r,this.symlink=e}get name(){return"SylinkError"}},kR=class extends Error{constructor(e,r){super(r+": Cannot cd into '"+e+"'"),this.path=e,this.code=r}get name(){return"CwdError"}},QR=(t,e)=>t.get(Vu(e)),Qv=(t,e,r)=>t.set(Vu(e),r),cot=(t,e)=>{_c.stat(t,(r,s)=>{(r||!s.isDirectory())&&(r=new kR(t,r&&r.code||"ENOTDIR")),e(r)})};dG.exports=(t,e,r)=>{t=Vu(t);let s=e.umask,a=e.mode|448,n=(a&s)!==0,c=e.uid,f=e.gid,p=typeof c=="number"&&typeof f=="number"&&(c!==e.processUid||f!==e.processGid),h=e.preserve,E=e.unlink,C=e.cache,S=Vu(e.cwd),P=(N,U)=>{N?r(N):(Qv(C,t,!0),U&&p?mge(U,c,f,W=>P(W)):n?_c.chmod(t,a,r):r())};if(C&&QR(C,t)===!0)return P();if(t===S)return cot(t,P);if(h)return dge(t,{mode:a}).then(N=>P(null,N),P);let R=Vu(PR.relative(S,t)).split("/");TR(S,R,a,C,E,S,null,P)};var TR=(t,e,r,s,a,n,c,f)=>{if(!e.length)return f(null,c);let p=e.shift(),h=Vu(PR.resolve(t+"/"+p));if(QR(s,h))return TR(h,e,r,s,a,n,c,f);_c.mkdir(h,r,yge(h,e,r,s,a,n,c,f))},yge=(t,e,r,s,a,n,c,f)=>p=>{p?_c.lstat(t,(h,E)=>{if(h)h.path=h.path&&Vu(h.path),f(h);else if(E.isDirectory())TR(t,e,r,s,a,n,c,f);else if(a)_c.unlink(t,C=>{if(C)return f(C);_c.mkdir(t,r,yge(t,e,r,s,a,n,c,f))});else{if(E.isSymbolicLink())return f(new xR(t,t+"/"+e.join("/")));f(p)}}):(c=c||t,TR(t,e,r,s,a,n,c,f))},uot=t=>{let e=!1,r="ENOTDIR";try{e=_c.statSync(t).isDirectory()}catch(s){r=s.code}finally{if(!e)throw new kR(t,r)}};dG.exports.sync=(t,e)=>{t=Vu(t);let r=e.umask,s=e.mode|448,a=(s&r)!==0,n=e.uid,c=e.gid,f=typeof n=="number"&&typeof c=="number"&&(n!==e.processUid||c!==e.processGid),p=e.preserve,h=e.unlink,E=e.cache,C=Vu(e.cwd),S=N=>{Qv(E,t,!0),N&&f&&mge.sync(N,n,c),a&&_c.chmodSync(t,s)};if(E&&QR(E,t)===!0)return S();if(t===C)return uot(C),S();if(p)return S(dge.sync(t,s));let I=Vu(PR.relative(C,t)).split("/"),R=null;for(let N=I.shift(),U=C;N&&(U+="/"+N);N=I.shift())if(U=Vu(PR.resolve(U)),!QR(E,U))try{_c.mkdirSync(U,s),R=R||U,Qv(E,U,!0)}catch{let ee=_c.lstatSync(U);if(ee.isDirectory()){Qv(E,U,!0);continue}else if(h){_c.unlinkSync(U),_c.mkdirSync(U,s),R=R||U,Qv(E,U,!0);continue}else if(ee.isSymbolicLink())return new xR(U,U+"/"+I.join("/"))}return S(R)}});var yG=_((F3t,Ige)=>{var mG=Object.create(null),{hasOwnProperty:fot}=Object.prototype;Ige.exports=t=>(fot.call(mG,t)||(mG[t]=t.normalize("NFKD")),mG[t])});var vge=_((N3t,Bge)=>{var Cge=Ie("assert"),Aot=yG(),pot=FI(),{join:wge}=Ie("path"),hot=process.env.TESTING_TAR_FAKE_PLATFORM||process.platform,got=hot==="win32";Bge.exports=()=>{let t=new Map,e=new Map,r=h=>h.split("/").slice(0,-1).reduce((C,S)=>(C.length&&(S=wge(C[C.length-1],S)),C.push(S||"/"),C),[]),s=new Set,a=h=>{let E=e.get(h);if(!E)throw new Error("function does not have any path reservations");return{paths:E.paths.map(C=>t.get(C)),dirs:[...E.dirs].map(C=>t.get(C))}},n=h=>{let{paths:E,dirs:C}=a(h);return E.every(S=>S[0]===h)&&C.every(S=>S[0]instanceof Set&&S[0].has(h))},c=h=>s.has(h)||!n(h)?!1:(s.add(h),h(()=>f(h)),!0),f=h=>{if(!s.has(h))return!1;let{paths:E,dirs:C}=e.get(h),S=new Set;return E.forEach(P=>{let I=t.get(P);Cge.equal(I[0],h),I.length===1?t.delete(P):(I.shift(),typeof I[0]=="function"?S.add(I[0]):I[0].forEach(R=>S.add(R)))}),C.forEach(P=>{let I=t.get(P);Cge(I[0]instanceof Set),I[0].size===1&&I.length===1?t.delete(P):I[0].size===1?(I.shift(),S.add(I[0])):I[0].delete(h)}),s.delete(h),S.forEach(P=>c(P)),!0};return{check:n,reserve:(h,E)=>{h=got?["win32 parallelization disabled"]:h.map(S=>Aot(pot(wge(S))).toLowerCase());let C=new Set(h.map(S=>r(S)).reduce((S,P)=>S.concat(P)));return e.set(E,{dirs:C,paths:h}),h.forEach(S=>{let P=t.get(S);P?P.push(E):t.set(S,[E])}),C.forEach(S=>{let P=t.get(S);P?P[P.length-1]instanceof Set?P[P.length-1].add(E):P.push(new Set([E])):t.set(S,[new Set([E])])}),c(E)}}}});var bge=_((O3t,Dge)=>{var dot=process.platform,mot=dot==="win32",yot=global.__FAKE_TESTING_FS__||Ie("fs"),{O_CREAT:Eot,O_TRUNC:Iot,O_WRONLY:Cot,UV_FS_O_FILEMAP:Sge=0}=yot.constants,wot=mot&&!!Sge,Bot=512*1024,vot=Sge|Iot|Eot|Cot;Dge.exports=wot?t=>t"w"});var bG=_((L3t,Hge)=>{"use strict";var Sot=Ie("assert"),Dot=vR(),Mn=Ie("fs"),bot=GI(),Jp=Ie("path"),Mge=Ege(),Pge=b6(),Pot=vge(),xot=P6(),Zl=QI(),kot=FI(),Qot=yG(),xge=Symbol("onEntry"),CG=Symbol("checkFs"),kge=Symbol("checkFs2"),NR=Symbol("pruneCache"),wG=Symbol("isReusable"),Hc=Symbol("makeFs"),BG=Symbol("file"),vG=Symbol("directory"),OR=Symbol("link"),Qge=Symbol("symlink"),Tge=Symbol("hardlink"),Rge=Symbol("unsupported"),Fge=Symbol("checkPath"),_0=Symbol("mkdir"),Xo=Symbol("onError"),RR=Symbol("pending"),Nge=Symbol("pend"),JI=Symbol("unpend"),EG=Symbol("ended"),IG=Symbol("maybeClose"),SG=Symbol("skip"),Tv=Symbol("doChown"),Rv=Symbol("uid"),Fv=Symbol("gid"),Nv=Symbol("checkedCwd"),Uge=Ie("crypto"),_ge=bge(),Tot=process.env.TESTING_TAR_FAKE_PLATFORM||process.platform,Ov=Tot==="win32",Rot=(t,e)=>{if(!Ov)return Mn.unlink(t,e);let r=t+".DELETE."+Uge.randomBytes(16).toString("hex");Mn.rename(t,r,s=>{if(s)return e(s);Mn.unlink(r,e)})},Fot=t=>{if(!Ov)return Mn.unlinkSync(t);let e=t+".DELETE."+Uge.randomBytes(16).toString("hex");Mn.renameSync(t,e),Mn.unlinkSync(e)},Oge=(t,e,r)=>t===t>>>0?t:e===e>>>0?e:r,Lge=t=>Qot(kot(Zl(t))).toLowerCase(),Not=(t,e)=>{e=Lge(e);for(let r of t.keys()){let s=Lge(r);(s===e||s.indexOf(e+"/")===0)&&t.delete(r)}},Oot=t=>{for(let e of t.keys())t.delete(e)},Lv=class extends Dot{constructor(e){if(e||(e={}),e.ondone=r=>{this[EG]=!0,this[IG]()},super(e),this[Nv]=!1,this.reservations=Pot(),this.transform=typeof e.transform=="function"?e.transform:null,this.writable=!0,this.readable=!1,this[RR]=0,this[EG]=!1,this.dirCache=e.dirCache||new Map,typeof e.uid=="number"||typeof e.gid=="number"){if(typeof e.uid!="number"||typeof e.gid!="number")throw new TypeError("cannot set owner without number uid and gid");if(e.preserveOwner)throw new TypeError("cannot preserve owner in archive and also set owner explicitly");this.uid=e.uid,this.gid=e.gid,this.setOwner=!0}else this.uid=null,this.gid=null,this.setOwner=!1;e.preserveOwner===void 0&&typeof e.uid!="number"?this.preserveOwner=process.getuid&&process.getuid()===0:this.preserveOwner=!!e.preserveOwner,this.processUid=(this.preserveOwner||this.setOwner)&&process.getuid?process.getuid():null,this.processGid=(this.preserveOwner||this.setOwner)&&process.getgid?process.getgid():null,this.forceChown=e.forceChown===!0,this.win32=!!e.win32||Ov,this.newer=!!e.newer,this.keep=!!e.keep,this.noMtime=!!e.noMtime,this.preservePaths=!!e.preservePaths,this.unlink=!!e.unlink,this.cwd=Zl(Jp.resolve(e.cwd||process.cwd())),this.strip=+e.strip||0,this.processUmask=e.noChmod?0:process.umask(),this.umask=typeof e.umask=="number"?e.umask:this.processUmask,this.dmode=e.dmode||511&~this.umask,this.fmode=e.fmode||438&~this.umask,this.on("entry",r=>this[xge](r))}warn(e,r,s={}){return(e==="TAR_BAD_ARCHIVE"||e==="TAR_ABORT")&&(s.recoverable=!1),super.warn(e,r,s)}[IG](){this[EG]&&this[RR]===0&&(this.emit("prefinish"),this.emit("finish"),this.emit("end"),this.emit("close"))}[Fge](e){if(this.strip){let r=Zl(e.path).split("/");if(r.length=this.strip)e.linkpath=s.slice(this.strip).join("/");else return!1}}if(!this.preservePaths){let r=Zl(e.path),s=r.split("/");if(s.includes("..")||Ov&&/^[a-z]:\.\.$/i.test(s[0]))return this.warn("TAR_ENTRY_ERROR","path contains '..'",{entry:e,path:r}),!1;let[a,n]=xot(r);a&&(e.path=n,this.warn("TAR_ENTRY_INFO",`stripping ${a} from absolute path`,{entry:e,path:r}))}if(Jp.isAbsolute(e.path)?e.absolute=Zl(Jp.resolve(e.path)):e.absolute=Zl(Jp.resolve(this.cwd,e.path)),!this.preservePaths&&e.absolute.indexOf(this.cwd+"/")!==0&&e.absolute!==this.cwd)return this.warn("TAR_ENTRY_ERROR","path escaped extraction target",{entry:e,path:Zl(e.path),resolvedPath:e.absolute,cwd:this.cwd}),!1;if(e.absolute===this.cwd&&e.type!=="Directory"&&e.type!=="GNUDumpDir")return!1;if(this.win32){let{root:r}=Jp.win32.parse(e.absolute);e.absolute=r+Pge.encode(e.absolute.substr(r.length));let{root:s}=Jp.win32.parse(e.path);e.path=s+Pge.encode(e.path.substr(s.length))}return!0}[xge](e){if(!this[Fge](e))return e.resume();switch(Sot.equal(typeof e.absolute,"string"),e.type){case"Directory":case"GNUDumpDir":e.mode&&(e.mode=e.mode|448);case"File":case"OldFile":case"ContiguousFile":case"Link":case"SymbolicLink":return this[CG](e);case"CharacterDevice":case"BlockDevice":case"FIFO":default:return this[Rge](e)}}[Xo](e,r){e.name==="CwdError"?this.emit("error",e):(this.warn("TAR_ENTRY_ERROR",e,{entry:r}),this[JI](),r.resume())}[_0](e,r,s){Mge(Zl(e),{uid:this.uid,gid:this.gid,processUid:this.processUid,processGid:this.processGid,umask:this.processUmask,preserve:this.preservePaths,unlink:this.unlink,cache:this.dirCache,cwd:this.cwd,mode:r,noChmod:this.noChmod},s)}[Tv](e){return this.forceChown||this.preserveOwner&&(typeof e.uid=="number"&&e.uid!==this.processUid||typeof e.gid=="number"&&e.gid!==this.processGid)||typeof this.uid=="number"&&this.uid!==this.processUid||typeof this.gid=="number"&&this.gid!==this.processGid}[Rv](e){return Oge(this.uid,e.uid,this.processUid)}[Fv](e){return Oge(this.gid,e.gid,this.processGid)}[BG](e,r){let s=e.mode&4095||this.fmode,a=new bot.WriteStream(e.absolute,{flags:_ge(e.size),mode:s,autoClose:!1});a.on("error",p=>{a.fd&&Mn.close(a.fd,()=>{}),a.write=()=>!0,this[Xo](p,e),r()});let n=1,c=p=>{if(p){a.fd&&Mn.close(a.fd,()=>{}),this[Xo](p,e),r();return}--n===0&&Mn.close(a.fd,h=>{h?this[Xo](h,e):this[JI](),r()})};a.on("finish",p=>{let h=e.absolute,E=a.fd;if(e.mtime&&!this.noMtime){n++;let C=e.atime||new Date,S=e.mtime;Mn.futimes(E,C,S,P=>P?Mn.utimes(h,C,S,I=>c(I&&P)):c())}if(this[Tv](e)){n++;let C=this[Rv](e),S=this[Fv](e);Mn.fchown(E,C,S,P=>P?Mn.chown(h,C,S,I=>c(I&&P)):c())}c()});let f=this.transform&&this.transform(e)||e;f!==e&&(f.on("error",p=>{this[Xo](p,e),r()}),e.pipe(f)),f.pipe(a)}[vG](e,r){let s=e.mode&4095||this.dmode;this[_0](e.absolute,s,a=>{if(a){this[Xo](a,e),r();return}let n=1,c=f=>{--n===0&&(r(),this[JI](),e.resume())};e.mtime&&!this.noMtime&&(n++,Mn.utimes(e.absolute,e.atime||new Date,e.mtime,c)),this[Tv](e)&&(n++,Mn.chown(e.absolute,this[Rv](e),this[Fv](e),c)),c()})}[Rge](e){e.unsupported=!0,this.warn("TAR_ENTRY_UNSUPPORTED",`unsupported entry type: ${e.type}`,{entry:e}),e.resume()}[Qge](e,r){this[OR](e,e.linkpath,"symlink",r)}[Tge](e,r){let s=Zl(Jp.resolve(this.cwd,e.linkpath));this[OR](e,s,"link",r)}[Nge](){this[RR]++}[JI](){this[RR]--,this[IG]()}[SG](e){this[JI](),e.resume()}[wG](e,r){return e.type==="File"&&!this.unlink&&r.isFile()&&r.nlink<=1&&!Ov}[CG](e){this[Nge]();let r=[e.path];e.linkpath&&r.push(e.linkpath),this.reservations.reserve(r,s=>this[kge](e,s))}[NR](e){e.type==="SymbolicLink"?Oot(this.dirCache):e.type!=="Directory"&&Not(this.dirCache,e.absolute)}[kge](e,r){this[NR](e);let s=f=>{this[NR](e),r(f)},a=()=>{this[_0](this.cwd,this.dmode,f=>{if(f){this[Xo](f,e),s();return}this[Nv]=!0,n()})},n=()=>{if(e.absolute!==this.cwd){let f=Zl(Jp.dirname(e.absolute));if(f!==this.cwd)return this[_0](f,this.dmode,p=>{if(p){this[Xo](p,e),s();return}c()})}c()},c=()=>{Mn.lstat(e.absolute,(f,p)=>{if(p&&(this.keep||this.newer&&p.mtime>e.mtime)){this[SG](e),s();return}if(f||this[wG](e,p))return this[Hc](null,e,s);if(p.isDirectory()){if(e.type==="Directory"){let h=!this.noChmod&&e.mode&&(p.mode&4095)!==e.mode,E=C=>this[Hc](C,e,s);return h?Mn.chmod(e.absolute,e.mode,E):E()}if(e.absolute!==this.cwd)return Mn.rmdir(e.absolute,h=>this[Hc](h,e,s))}if(e.absolute===this.cwd)return this[Hc](null,e,s);Rot(e.absolute,h=>this[Hc](h,e,s))})};this[Nv]?n():a()}[Hc](e,r,s){if(e){this[Xo](e,r),s();return}switch(r.type){case"File":case"OldFile":case"ContiguousFile":return this[BG](r,s);case"Link":return this[Tge](r,s);case"SymbolicLink":return this[Qge](r,s);case"Directory":case"GNUDumpDir":return this[vG](r,s)}}[OR](e,r,s,a){Mn[s](r,e.absolute,n=>{n?this[Xo](n,e):(this[JI](),e.resume()),a()})}},FR=t=>{try{return[null,t()]}catch(e){return[e,null]}},DG=class extends Lv{[Hc](e,r){return super[Hc](e,r,()=>{})}[CG](e){if(this[NR](e),!this[Nv]){let n=this[_0](this.cwd,this.dmode);if(n)return this[Xo](n,e);this[Nv]=!0}if(e.absolute!==this.cwd){let n=Zl(Jp.dirname(e.absolute));if(n!==this.cwd){let c=this[_0](n,this.dmode);if(c)return this[Xo](c,e)}}let[r,s]=FR(()=>Mn.lstatSync(e.absolute));if(s&&(this.keep||this.newer&&s.mtime>e.mtime))return this[SG](e);if(r||this[wG](e,s))return this[Hc](null,e);if(s.isDirectory()){if(e.type==="Directory"){let c=!this.noChmod&&e.mode&&(s.mode&4095)!==e.mode,[f]=c?FR(()=>{Mn.chmodSync(e.absolute,e.mode)}):[];return this[Hc](f,e)}let[n]=FR(()=>Mn.rmdirSync(e.absolute));this[Hc](n,e)}let[a]=e.absolute===this.cwd?[]:FR(()=>Fot(e.absolute));this[Hc](a,e)}[BG](e,r){let s=e.mode&4095||this.fmode,a=f=>{let p;try{Mn.closeSync(n)}catch(h){p=h}(f||p)&&this[Xo](f||p,e),r()},n;try{n=Mn.openSync(e.absolute,_ge(e.size),s)}catch(f){return a(f)}let c=this.transform&&this.transform(e)||e;c!==e&&(c.on("error",f=>this[Xo](f,e)),e.pipe(c)),c.on("data",f=>{try{Mn.writeSync(n,f,0,f.length)}catch(p){a(p)}}),c.on("end",f=>{let p=null;if(e.mtime&&!this.noMtime){let h=e.atime||new Date,E=e.mtime;try{Mn.futimesSync(n,h,E)}catch(C){try{Mn.utimesSync(e.absolute,h,E)}catch{p=C}}}if(this[Tv](e)){let h=this[Rv](e),E=this[Fv](e);try{Mn.fchownSync(n,h,E)}catch(C){try{Mn.chownSync(e.absolute,h,E)}catch{p=p||C}}}a(p)})}[vG](e,r){let s=e.mode&4095||this.dmode,a=this[_0](e.absolute,s);if(a){this[Xo](a,e),r();return}if(e.mtime&&!this.noMtime)try{Mn.utimesSync(e.absolute,e.atime||new Date,e.mtime)}catch{}if(this[Tv](e))try{Mn.chownSync(e.absolute,this[Rv](e),this[Fv](e))}catch{}r(),e.resume()}[_0](e,r){try{return Mge.sync(Zl(e),{uid:this.uid,gid:this.gid,processUid:this.processUid,processGid:this.processGid,umask:this.processUmask,preserve:this.preservePaths,unlink:this.unlink,cache:this.dirCache,cwd:this.cwd,mode:r})}catch(s){return s}}[OR](e,r,s,a){try{Mn[s+"Sync"](r,e.absolute),a(),e.resume()}catch(n){return this[Xo](n,e)}}};Lv.Sync=DG;Hge.exports=Lv});var Yge=_((M3t,Wge)=>{"use strict";var Lot=DI(),LR=bG(),Gge=Ie("fs"),qge=GI(),jge=Ie("path"),PG=FI();Wge.exports=(t,e,r)=>{typeof t=="function"?(r=t,e=null,t={}):Array.isArray(t)&&(e=t,t={}),typeof e=="function"&&(r=e,e=null),e?e=Array.from(e):e=[];let s=Lot(t);if(s.sync&&typeof r=="function")throw new TypeError("callback not supported for sync tar functions");if(!s.file&&typeof r=="function")throw new TypeError("callback only supported with file option");return e.length&&Mot(s,e),s.file&&s.sync?Uot(s):s.file?_ot(s,r):s.sync?Hot(s):jot(s)};var Mot=(t,e)=>{let r=new Map(e.map(n=>[PG(n),!0])),s=t.filter,a=(n,c)=>{let f=c||jge.parse(n).root||".",p=n===f?!1:r.has(n)?r.get(n):a(jge.dirname(n),f);return r.set(n,p),p};t.filter=s?(n,c)=>s(n,c)&&a(PG(n)):n=>a(PG(n))},Uot=t=>{let e=new LR.Sync(t),r=t.file,s=Gge.statSync(r),a=t.maxReadSize||16*1024*1024;new qge.ReadStreamSync(r,{readSize:a,size:s.size}).pipe(e)},_ot=(t,e)=>{let r=new LR(t),s=t.maxReadSize||16*1024*1024,a=t.file,n=new Promise((c,f)=>{r.on("error",f),r.on("close",c),Gge.stat(a,(p,h)=>{if(p)f(p);else{let E=new qge.ReadStream(a,{readSize:s,size:h.size});E.on("error",f),E.pipe(r)}})});return e?n.then(e,e):n},Hot=t=>new LR.Sync(t),jot=t=>new LR(t)});var Vge=_(Ps=>{"use strict";Ps.c=Ps.create=P0e();Ps.r=Ps.replace=cG();Ps.t=Ps.list=SR();Ps.u=Ps.update=L0e();Ps.x=Ps.extract=Yge();Ps.Pack=uR();Ps.Unpack=bG();Ps.Parse=vR();Ps.ReadEntry=VT();Ps.WriteEntry=M6();Ps.Header=RI();Ps.Pax=KT();Ps.types=I6()});var xG,Jge,H0,Mv,Uv,Kge=Xe(()=>{xG=ut(Ld()),Jge=Ie("worker_threads"),H0=Symbol("kTaskInfo"),Mv=class{constructor(e,r){this.fn=e;this.limit=(0,xG.default)(r.poolSize)}run(e){return this.limit(()=>this.fn(e))}},Uv=class{constructor(e,r){this.source=e;this.workers=[];this.limit=(0,xG.default)(r.poolSize),this.cleanupInterval=setInterval(()=>{if(this.limit.pendingCount===0&&this.limit.activeCount===0){let s=this.workers.pop();s?s.terminate():clearInterval(this.cleanupInterval)}},5e3).unref()}createWorker(){this.cleanupInterval.refresh();let e=new Jge.Worker(this.source,{eval:!0,execArgv:[...process.execArgv,"--unhandled-rejections=strict"]});return e.on("message",r=>{if(!e[H0])throw new Error("Assertion failed: Worker sent a result without having a task assigned");e[H0].resolve(r),e[H0]=null,e.unref(),this.workers.push(e)}),e.on("error",r=>{e[H0]?.reject(r),e[H0]=null}),e.on("exit",r=>{r!==0&&e[H0]?.reject(new Error(`Worker exited with code ${r}`)),e[H0]=null}),e}run(e){return this.limit(()=>{let r=this.workers.pop()??this.createWorker();return r.ref(),new Promise((s,a)=>{r[H0]={resolve:s,reject:a},r.postMessage(e)})})}}});var Xge=_((j3t,zge)=>{var kG;zge.exports.getContent=()=>(typeof kG>"u"&&(kG=Ie("zlib").brotliDecompressSync(Buffer.from("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","base64")).toString()),kG)});var ps={};Vt(ps,{convertToZip:()=>Yot,convertToZipWorker:()=>RG,extractArchiveTo:()=>rde,getDefaultTaskPool:()=>ede,getTaskPoolForConfiguration:()=>tde,makeArchiveFromDirectory:()=>Wot});function Got(t,e){switch(t){case"async":return new Mv(RG,{poolSize:e});case"workers":return new Uv((0,TG.getContent)(),{poolSize:e});default:throw new Error(`Assertion failed: Unknown value ${t} for taskPoolMode`)}}function ede(){return typeof QG>"u"&&(QG=Got("workers",Ui.availableParallelism())),QG}function tde(t){return typeof t>"u"?ede():Yl(qot,t,()=>{let e=t.get("taskPoolMode"),r=t.get("taskPoolConcurrency");switch(e){case"async":return new Mv(RG,{poolSize:r});case"workers":return new Uv((0,TG.getContent)(),{poolSize:r});default:throw new Error(`Assertion failed: Unknown value ${e} for taskPoolMode`)}})}async function RG(t){let{tmpFile:e,tgz:r,compressionLevel:s,extractBufferOpts:a}=t,n=new As(e,{create:!0,level:s,stats:$a.makeDefaultStats()}),c=Buffer.from(r.buffer,r.byteOffset,r.byteLength);return await rde(c,n,a),n.saveAndClose(),e}async function Wot(t,{baseFs:e=new Yn,prefixPath:r=vt.root,compressionLevel:s,inMemory:a=!1}={}){let n;if(a)n=new As(null,{level:s});else{let f=await ce.mktempPromise(),p=J.join(f,"archive.zip");n=new As(p,{create:!0,level:s})}let c=J.resolve(vt.root,r);return await n.copyPromise(c,t,{baseFs:e,stableTime:!0,stableSort:!0}),n}async function Yot(t,e={}){let r=await ce.mktempPromise(),s=J.join(r,"archive.zip"),a=e.compressionLevel??e.configuration?.get("compressionLevel")??"mixed",n={prefixPath:e.prefixPath,stripComponents:e.stripComponents};return await(e.taskPool??tde(e.configuration)).run({tmpFile:s,tgz:t,compressionLevel:a,extractBufferOpts:n}),new As(s,{level:e.compressionLevel})}async function*Vot(t){let e=new $ge.default.Parse,r=new Zge.PassThrough({objectMode:!0,autoDestroy:!0,emitClose:!0});e.on("entry",s=>{r.write(s)}),e.on("error",s=>{r.destroy(s)}),e.on("close",()=>{r.destroyed||r.end()}),e.end(t);for await(let s of r){let a=s;yield a,a.resume()}}async function rde(t,e,{stripComponents:r=0,prefixPath:s=vt.dot}={}){function a(n){if(n.path[0]==="/")return!0;let c=n.path.split(/\//g);return!!(c.some(f=>f==="..")||c.length<=r)}for await(let n of Vot(t)){if(a(n))continue;let c=J.normalize(fe.toPortablePath(n.path)).replace(/\/$/,"").split(/\//g);if(c.length<=r)continue;let f=c.slice(r).join("/"),p=J.join(s,f),h=420;switch((n.type==="Directory"||(n.mode??0)&73)&&(h|=73),n.type){case"Directory":e.mkdirpSync(J.dirname(p),{chmod:493,utimes:[fi.SAFE_TIME,fi.SAFE_TIME]}),e.mkdirSync(p,{mode:h}),e.utimesSync(p,fi.SAFE_TIME,fi.SAFE_TIME);break;case"OldFile":case"File":e.mkdirpSync(J.dirname(p),{chmod:493,utimes:[fi.SAFE_TIME,fi.SAFE_TIME]}),e.writeFileSync(p,await WE(n),{mode:h}),e.utimesSync(p,fi.SAFE_TIME,fi.SAFE_TIME);break;case"SymbolicLink":e.mkdirpSync(J.dirname(p),{chmod:493,utimes:[fi.SAFE_TIME,fi.SAFE_TIME]}),e.symlinkSync(n.linkpath,p),e.lutimesSync(p,fi.SAFE_TIME,fi.SAFE_TIME);break}}return e}var Zge,$ge,TG,QG,qot,nde=Xe(()=>{Ge();Dt();eA();Zge=Ie("stream"),$ge=ut(Vge());Kge();Pc();TG=ut(Xge());qot=new WeakMap});var sde=_((FG,ide)=>{(function(t,e){typeof FG=="object"?ide.exports=e():typeof define=="function"&&define.amd?define(e):t.treeify=e()})(FG,function(){function t(a,n){var c=n?"\u2514":"\u251C";return a?c+="\u2500 ":c+="\u2500\u2500\u2510",c}function e(a,n){var c=[];for(var f in a)a.hasOwnProperty(f)&&(n&&typeof a[f]=="function"||c.push(f));return c}function r(a,n,c,f,p,h,E){var C="",S=0,P,I,R=f.slice(0);if(R.push([n,c])&&f.length>0&&(f.forEach(function(U,W){W>0&&(C+=(U[1]?" ":"\u2502")+" "),!I&&U[0]===n&&(I=!0)}),C+=t(a,c)+a,p&&(typeof n!="object"||n instanceof Date)&&(C+=": "+n),I&&(C+=" (circular ref.)"),E(C)),!I&&typeof n=="object"){var N=e(n,h);N.forEach(function(U){P=++S===N.length,r(U,n[U],P,R,p,h,E)})}}var s={};return s.asLines=function(a,n,c,f){var p=typeof c!="function"?c:!1;r(".",a,!1,[],n,p,f||c)},s.asTree=function(a,n,c){var f="";return r(".",a,!1,[],n,c,function(p){f+=p+` +`}),f},s})});var xs={};Vt(xs,{emitList:()=>Jot,emitTree:()=>cde,treeNodeToJson:()=>lde,treeNodeToTreeify:()=>ade});function ade(t,{configuration:e}){let r={},s=0,a=(n,c)=>{let f=Array.isArray(n)?n.entries():Object.entries(n);for(let[p,h]of f){if(!h)continue;let{label:E,value:C,children:S}=h,P=[];typeof E<"u"&&P.push(zd(e,E,2)),typeof C<"u"&&P.push(Ht(e,C[0],C[1])),P.length===0&&P.push(zd(e,`${p}`,2));let I=P.join(": ").trim(),R=`\0${s++}\0`,N=c[`${R}${I}`]={};typeof S<"u"&&a(S,N)}};if(typeof t.children>"u")throw new Error("The root node must only contain children");return a(t.children,r),r}function lde(t){let e=r=>{if(typeof r.children>"u"){if(typeof r.value>"u")throw new Error("Assertion failed: Expected a value to be set if the children are missing");return Xd(r.value[0],r.value[1])}let s=Array.isArray(r.children)?r.children.entries():Object.entries(r.children??{}),a=Array.isArray(r.children)?[]:{};for(let[n,c]of s)c&&(a[Kot(n)]=e(c));return typeof r.value>"u"?a:{value:Xd(r.value[0],r.value[1]),children:a}};return e(t)}function Jot(t,{configuration:e,stdout:r,json:s}){let a=t.map(n=>({value:n}));cde({children:a},{configuration:e,stdout:r,json:s})}function cde(t,{configuration:e,stdout:r,json:s,separators:a=0}){if(s){let c=Array.isArray(t.children)?t.children.values():Object.values(t.children??{});for(let f of c)f&&r.write(`${JSON.stringify(lde(f))} +`);return}let n=(0,ode.asTree)(ade(t,{configuration:e}),!1,!1);if(n=n.replace(/\0[0-9]+\0/g,""),a>=1&&(n=n.replace(/^([├└]─)/gm,`\u2502 +$1`).replace(/^│\n/,"")),a>=2)for(let c=0;c<2;++c)n=n.replace(/^([│ ].{2}[├│ ].{2}[^\n]+\n)(([│ ]).{2}[├└].{2}[^\n]*\n[│ ].{2}[│ ].{2}[├└]─)/gm,`$1$3 \u2502 +$2`).replace(/^│\n/,"");if(a>=3)throw new Error("Only the first two levels are accepted by treeUtils.emitTree");r.write(n)}function Kot(t){return typeof t=="string"?t.replace(/^\0[0-9]+\0/,""):t}var ode,ude=Xe(()=>{ode=ut(sde());xc()});var MR,fde=Xe(()=>{MR=class{constructor(e){this.releaseFunction=e;this.map=new Map}addOrCreate(e,r){let s=this.map.get(e);if(typeof s<"u"){if(s.refCount<=0)throw new Error(`Race condition in RefCountedMap. While adding a new key the refCount is: ${s.refCount} for ${JSON.stringify(e)}`);return s.refCount++,{value:s.value,release:()=>this.release(e)}}else{let a=r();return this.map.set(e,{refCount:1,value:a}),{value:a,release:()=>this.release(e)}}}release(e){let r=this.map.get(e);if(!r)throw new Error(`Unbalanced calls to release. No known instances of: ${JSON.stringify(e)}`);let s=r.refCount;if(s<=0)throw new Error(`Unbalanced calls to release. Too many release vs alloc refcount would become: ${s-1} of ${JSON.stringify(e)}`);s==1?(this.map.delete(e),this.releaseFunction(r.value)):r.refCount--}}});function _v(t){let e=t.match(zot);if(!e?.groups)throw new Error("Assertion failed: Expected the checksum to match the requested pattern");let r=e.groups.cacheVersion?parseInt(e.groups.cacheVersion):null;return{cacheKey:e.groups.cacheKey??null,cacheVersion:r,cacheSpec:e.groups.cacheSpec??null,hash:e.groups.hash}}var Ade,NG,OG,UR,Kr,zot,LG=Xe(()=>{Ge();Dt();Dt();eA();Ade=Ie("crypto"),NG=ut(Ie("fs"));fde();Tc();I0();Pc();Wo();OG=YE(process.env.YARN_CACHE_CHECKPOINT_OVERRIDE??process.env.YARN_CACHE_VERSION_OVERRIDE??9),UR=YE(process.env.YARN_CACHE_VERSION_OVERRIDE??10),Kr=class t{constructor(e,{configuration:r,immutable:s=r.get("enableImmutableCache"),check:a=!1}){this.markedFiles=new Set;this.mutexes=new Map;this.refCountedZipFsCache=new MR(e=>{e.discardAndClose()});this.cacheId=`-${(0,Ade.randomBytes)(8).toString("hex")}.tmp`;this.configuration=r,this.cwd=e,this.immutable=s,this.check=a;let{cacheSpec:n,cacheKey:c}=t.getCacheKey(r);this.cacheSpec=n,this.cacheKey=c}static async find(e,{immutable:r,check:s}={}){let a=new t(e.get("cacheFolder"),{configuration:e,immutable:r,check:s});return await a.setup(),a}static getCacheKey(e){let r=e.get("compressionLevel"),s=r!=="mixed"?`c${r}`:"";return{cacheKey:[UR,s].join(""),cacheSpec:s}}get mirrorCwd(){if(!this.configuration.get("enableMirror"))return null;let e=`${this.configuration.get("globalFolder")}/cache`;return e!==this.cwd?e:null}getVersionFilename(e){return`${nI(e)}-${this.cacheKey}.zip`}getChecksumFilename(e,r){let a=_v(r).hash.slice(0,10);return`${nI(e)}-${a}.zip`}isChecksumCompatible(e){if(e===null)return!1;let{cacheVersion:r,cacheSpec:s}=_v(e);if(r===null||r{let pe=new As,Be=J.join(vt.root,x8(e));return pe.mkdirSync(Be,{recursive:!0}),pe.writeJsonSync(J.join(Be,Er.manifest),{name:un(e),mocked:!0}),pe},E=async(pe,{isColdHit:Be,controlPath:Ce=null})=>{if(Ce===null&&c.unstablePackages?.has(e.locatorHash))return{isValid:!0,hash:null};let g=r&&!Be?_v(r).cacheKey:this.cacheKey,we=!c.skipIntegrityCheck||!r?`${g}/${await SQ(pe)}`:r;if(Ce!==null){let Ae=!c.skipIntegrityCheck||!r?`${this.cacheKey}/${await SQ(Ce)}`:r;if(we!==Ae)throw new jt(18,"The remote archive doesn't match the local checksum - has the local cache been corrupted?")}let ye=null;switch(r!==null&&we!==r&&(this.check?ye="throw":_v(r).cacheKey!==_v(we).cacheKey?ye="update":ye=this.configuration.get("checksumBehavior")),ye){case null:case"update":return{isValid:!0,hash:we};case"ignore":return{isValid:!0,hash:r};case"reset":return{isValid:!1,hash:r};default:case"throw":throw new jt(18,"The remote archive doesn't match the expected checksum")}},C=async pe=>{if(!n)throw new Error(`Cache check required but no loader configured for ${Yr(this.configuration,e)}`);let Be=await n(),Ce=Be.getRealPath();Be.saveAndClose(),await ce.chmodPromise(Ce,420);let g=await E(pe,{controlPath:Ce,isColdHit:!1});if(!g.isValid)throw new Error("Assertion failed: Expected a valid checksum");return g.hash},S=async()=>{if(f===null||!await ce.existsPromise(f)){let pe=await n(),Be=pe.getRealPath();return pe.saveAndClose(),{source:"loader",path:Be}}return{source:"mirror",path:f}},P=async()=>{if(!n)throw new Error(`Cache entry required but missing for ${Yr(this.configuration,e)}`);if(this.immutable)throw new jt(56,`Cache entry required but missing for ${Yr(this.configuration,e)}`);let{path:pe,source:Be}=await S(),{hash:Ce}=await E(pe,{isColdHit:!0}),g=this.getLocatorPath(e,Ce),we=[];Be!=="mirror"&&f!==null&&we.push(async()=>{let Ae=`${f}${this.cacheId}`;await ce.copyFilePromise(pe,Ae,NG.default.constants.COPYFILE_FICLONE),await ce.chmodPromise(Ae,420),await ce.renamePromise(Ae,f)}),(!c.mirrorWriteOnly||f===null)&&we.push(async()=>{let Ae=`${g}${this.cacheId}`;await ce.copyFilePromise(pe,Ae,NG.default.constants.COPYFILE_FICLONE),await ce.chmodPromise(Ae,420),await ce.renamePromise(Ae,g)});let ye=c.mirrorWriteOnly?f??g:g;return await Promise.all(we.map(Ae=>Ae())),[!1,ye,Ce]},I=async()=>{let Be=(async()=>{let Ce=c.unstablePackages?.has(e.locatorHash),g=Ce||!r||this.isChecksumCompatible(r)?this.getLocatorPath(e,r):null,we=g!==null?this.markedFiles.has(g)||await p.existsPromise(g):!1,ye=!!c.mockedPackages?.has(e.locatorHash)&&(!this.check||!we),Ae=ye||we,se=Ae?s:a;if(se&&se(),Ae){let Z=null,De=g;if(!ye)if(this.check)Z=await C(De);else{let Re=await E(De,{isColdHit:!1});if(Re.isValid)Z=Re.hash;else return P()}return[ye,De,Z]}else{if(this.immutable&&Ce)throw new jt(56,`Cache entry required but missing for ${Yr(this.configuration,e)}; consider defining ${he.pretty(this.configuration,"supportedArchitectures",he.Type.CODE)} to cache packages for multiple systems`);return P()}})();this.mutexes.set(e.locatorHash,Be);try{return await Be}finally{this.mutexes.delete(e.locatorHash)}};for(let pe;pe=this.mutexes.get(e.locatorHash);)await pe;let[R,N,U]=await I();R||this.markedFiles.add(N);let W=()=>this.refCountedZipFsCache.addOrCreate(N,()=>R?h():new As(N,{baseFs:p,readOnly:!0})),ee,ie=new oE(()=>W4(()=>(ee=W(),ee.value),pe=>`Failed to open the cache entry for ${Yr(this.configuration,e)}: ${pe}`),J),ue=new _f(N,{baseFs:ie,pathUtils:J}),le=()=>{ee?.release()},me=c.unstablePackages?.has(e.locatorHash)?null:U;return[ue,le,me]}},zot=/^(?:(?(?[0-9]+)(?.*))\/)?(?.*)$/});var _R,pde=Xe(()=>{_R=(r=>(r[r.SCRIPT=0]="SCRIPT",r[r.SHELLCODE=1]="SHELLCODE",r))(_R||{})});var Xot,KI,MG=Xe(()=>{Dt();wc();Rp();Wo();Xot=[[/^(git(?:\+(?:https|ssh))?:\/\/.*(?:\.git)?)#(.*)$/,(t,e,r,s)=>`${r}#commit=${s}`],[/^https:\/\/((?:[^/]+?)@)?codeload\.github\.com\/([^/]+\/[^/]+)\/tar\.gz\/([0-9a-f]+)$/,(t,e,r="",s,a)=>`https://${r}github.com/${s}.git#commit=${a}`],[/^https:\/\/((?:[^/]+?)@)?github\.com\/([^/]+\/[^/]+?)(?:\.git)?#([0-9a-f]+)$/,(t,e,r="",s,a)=>`https://${r}github.com/${s}.git#commit=${a}`],[/^https?:\/\/[^/]+\/(?:[^/]+\/)*(?:@.+(?:\/|(?:%2f)))?([^/]+)\/(?:-|download)\/\1-[^/]+\.tgz(?:#|$)/,t=>`npm:${t}`],[/^https:\/\/npm\.pkg\.github\.com\/download\/(?:@[^/]+)\/(?:[^/]+)\/(?:[^/]+)\/(?:[0-9a-f]+)(?:#|$)/,t=>`npm:${t}`],[/^https:\/\/npm\.fontawesome\.com\/(?:@[^/]+)\/([^/]+)\/-\/([^/]+)\/\1-\2.tgz(?:#|$)/,t=>`npm:${t}`],[/^https?:\/\/[^/]+\/.*\/(@[^/]+)\/([^/]+)\/-\/\1\/\2-(?:[.\d\w-]+)\.tgz(?:#|$)/,(t,e)=>kQ({protocol:"npm:",source:null,selector:t,params:{__archiveUrl:e}})],[/^[^/]+\.tgz#[0-9a-f]+$/,t=>`npm:${t}`]],KI=class{constructor(e){this.resolver=e;this.resolutions=null}async setup(e,{report:r}){let s=J.join(e.cwd,Er.lockfile);if(!ce.existsSync(s))return;let a=await ce.readFilePromise(s,"utf8"),n=ls(a);if(Object.hasOwn(n,"__metadata"))return;let c=this.resolutions=new Map;for(let f of Object.keys(n)){let p=HB(f);if(!p){r.reportWarning(14,`Failed to parse the string "${f}" into a proper descriptor`);continue}let h=cl(p.range)?On(p,`npm:${p.range}`):p,{version:E,resolved:C}=n[f];if(!C)continue;let S;for(let[I,R]of Xot){let N=C.match(I);if(N){S=R(E,...N);break}}if(!S){r.reportWarning(14,`${ni(e.configuration,h)}: Only some patterns can be imported from legacy lockfiles (not "${C}")`);continue}let P=h;try{let I=em(h.range),R=HB(I.selector,!0);R&&(P=R)}catch{}c.set(h.descriptorHash,Ws(P,S))}}supportsDescriptor(e,r){return this.resolutions?this.resolutions.has(e.descriptorHash):!1}supportsLocator(e,r){return!1}shouldPersistResolution(e,r){throw new Error("Assertion failed: This resolver doesn't support resolving locators to packages")}bindDescriptor(e,r,s){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,s){if(!this.resolutions)throw new Error("Assertion failed: The resolution store should have been setup");let a=this.resolutions.get(e.descriptorHash);if(!a)throw new Error("Assertion failed: The resolution should have been registered");let n=S8(a),c=s.project.configuration.normalizeDependency(n);return await this.resolver.getCandidates(c,r,s)}async getSatisfying(e,r,s,a){let[n]=await this.getCandidates(e,r,a);return{locators:s.filter(c=>c.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){throw new Error("Assertion failed: This resolver doesn't support resolving locators to packages")}}});var lA,hde=Xe(()=>{Tc();Ev();xc();lA=class extends Ao{constructor({configuration:r,stdout:s,suggestInstall:a=!0}){super();this.errorCount=0;RB(this,{configuration:r}),this.configuration=r,this.stdout=s,this.suggestInstall=a}static async start(r,s){let a=new this(r);try{await s(a)}catch(n){a.reportExceptionOnce(n)}finally{await a.finalize()}return a}hasErrors(){return this.errorCount>0}exitCode(){return this.hasErrors()?1:0}reportCacheHit(r){}reportCacheMiss(r){}startSectionSync(r,s){return s()}async startSectionPromise(r,s){return await s()}startTimerSync(r,s,a){return(typeof s=="function"?s:a)()}async startTimerPromise(r,s,a){return await(typeof s=="function"?s:a)()}reportSeparator(){}reportInfo(r,s){}reportWarning(r,s){}reportError(r,s){this.errorCount+=1,this.stdout.write(`${Ht(this.configuration,"\u27A4","redBright")} ${this.formatNameWithHyperlink(r)}: ${s} +`)}reportProgress(r){return{...Promise.resolve().then(async()=>{for await(let{}of r);}),stop:()=>{}}}reportJson(r){}reportFold(r,s){}async finalize(){this.errorCount>0&&(this.stdout.write(` +`),this.stdout.write(`${Ht(this.configuration,"\u27A4","redBright")} Errors happened when preparing the environment required to run this command. +`),this.suggestInstall&&this.stdout.write(`${Ht(this.configuration,"\u27A4","redBright")} This might be caused by packages being missing from the lockfile, in which case running "yarn install" might help. +`))}formatNameWithHyperlink(r){return Wj(r,{configuration:this.configuration,json:!1})}}});var zI,UG=Xe(()=>{Wo();zI=class{constructor(e){this.resolver=e}supportsDescriptor(e,r){return!!(r.project.storedResolutions.get(e.descriptorHash)||r.project.originalPackages.has(bQ(e).locatorHash))}supportsLocator(e,r){return!!(r.project.originalPackages.has(e.locatorHash)&&!r.project.lockfileNeedsRefresh)}shouldPersistResolution(e,r){throw new Error("The shouldPersistResolution method shouldn't be called on the lockfile resolver, which would always answer yes")}bindDescriptor(e,r,s){return e}getResolutionDependencies(e,r){return this.resolver.getResolutionDependencies(e,r)}async getCandidates(e,r,s){let a=s.project.storedResolutions.get(e.descriptorHash);if(a){let c=s.project.originalPackages.get(a);if(c)return[c]}let n=s.project.originalPackages.get(bQ(e).locatorHash);if(n)return[n];throw new Error("Resolution expected from the lockfile data")}async getSatisfying(e,r,s,a){let[n]=await this.getCandidates(e,r,a);return{locators:s.filter(c=>c.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){let s=r.project.originalPackages.get(e.locatorHash);if(!s)throw new Error("The lockfile resolver isn't meant to resolve packages - they should already have been stored into a cache");return s}}});function Kp(){}function Zot(t,e,r,s,a){for(var n=0,c=e.length,f=0,p=0;nP.length?R:P}),h.value=t.join(E)}else h.value=t.join(r.slice(f,f+h.count));f+=h.count,h.added||(p+=h.count)}}var S=e[c-1];return c>1&&typeof S.value=="string"&&(S.added||S.removed)&&t.equals("",S.value)&&(e[c-2].value+=S.value,e.pop()),e}function $ot(t){return{newPos:t.newPos,components:t.components.slice(0)}}function eat(t,e){if(typeof t=="function")e.callback=t;else if(t)for(var r in t)t.hasOwnProperty(r)&&(e[r]=t[r]);return e}function mde(t,e,r){return r=eat(r,{ignoreWhitespace:!0}),qG.diff(t,e,r)}function tat(t,e,r){return WG.diff(t,e,r)}function HR(t){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?HR=function(e){return typeof e}:HR=function(e){return e&&typeof Symbol=="function"&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},HR(t)}function _G(t){return iat(t)||sat(t)||oat(t)||aat()}function iat(t){if(Array.isArray(t))return HG(t)}function sat(t){if(typeof Symbol<"u"&&Symbol.iterator in Object(t))return Array.from(t)}function oat(t,e){if(t){if(typeof t=="string")return HG(t,e);var r=Object.prototype.toString.call(t).slice(8,-1);if(r==="Object"&&t.constructor&&(r=t.constructor.name),r==="Map"||r==="Set")return Array.from(t);if(r==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return HG(t,e)}}function HG(t,e){(e==null||e>t.length)&&(e=t.length);for(var r=0,s=new Array(e);r"u"&&(c.context=4);var f=tat(r,s,c);if(!f)return;f.push({value:"",lines:[]});function p(U){return U.map(function(W){return" "+W})}for(var h=[],E=0,C=0,S=[],P=1,I=1,R=function(W){var ee=f[W],ie=ee.lines||ee.value.replace(/\n$/,"").split(` +`);if(ee.lines=ie,ee.added||ee.removed){var ue;if(!E){var le=f[W-1];E=P,C=I,le&&(S=c.context>0?p(le.lines.slice(-c.context)):[],E-=S.length,C-=S.length)}(ue=S).push.apply(ue,_G(ie.map(function(Ae){return(ee.added?"+":"-")+Ae}))),ee.added?I+=ie.length:P+=ie.length}else{if(E)if(ie.length<=c.context*2&&W=f.length-2&&ie.length<=c.context){var g=/\n$/.test(r),we=/\n$/.test(s),ye=ie.length==0&&S.length>Ce.oldLines;!g&&ye&&r.length>0&&S.splice(Ce.oldLines,0,"\\ No newline at end of file"),(!g&&!ye||!we)&&S.push("\\ No newline at end of file")}h.push(Ce),E=0,C=0,S=[]}P+=ie.length,I+=ie.length}},N=0;N{Kp.prototype={diff:function(e,r){var s=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{},a=s.callback;typeof s=="function"&&(a=s,s={}),this.options=s;var n=this;function c(R){return a?(setTimeout(function(){a(void 0,R)},0),!0):R}e=this.castInput(e),r=this.castInput(r),e=this.removeEmpty(this.tokenize(e)),r=this.removeEmpty(this.tokenize(r));var f=r.length,p=e.length,h=1,E=f+p;s.maxEditLength&&(E=Math.min(E,s.maxEditLength));var C=[{newPos:-1,components:[]}],S=this.extractCommon(C[0],r,e,0);if(C[0].newPos+1>=f&&S+1>=p)return c([{value:this.join(r),count:r.length}]);function P(){for(var R=-1*h;R<=h;R+=2){var N=void 0,U=C[R-1],W=C[R+1],ee=(W?W.newPos:0)-R;U&&(C[R-1]=void 0);var ie=U&&U.newPos+1=f&&ee+1>=p)return c(Zot(n,N.components,r,e,n.useLongestToken));C[R]=N}h++}if(a)(function R(){setTimeout(function(){if(h>E)return a();P()||R()},0)})();else for(;h<=E;){var I=P();if(I)return I}},pushComponent:function(e,r,s){var a=e[e.length-1];a&&a.added===r&&a.removed===s?e[e.length-1]={count:a.count+1,added:r,removed:s}:e.push({count:1,added:r,removed:s})},extractCommon:function(e,r,s,a){for(var n=r.length,c=s.length,f=e.newPos,p=f-a,h=0;f+1"u"?r:c}:s;return typeof t=="string"?t:JSON.stringify(jG(t,null,null,a),a," ")};Hv.equals=function(t,e){return Kp.prototype.equals.call(Hv,t.replace(/,([\r\n])/g,"$1"),e.replace(/,([\r\n])/g,"$1"))};GG=new Kp;GG.tokenize=function(t){return t.slice()};GG.join=GG.removeEmpty=function(t){return t}});var jR,Ede=Xe(()=>{Tc();jR=class{constructor(e){this.resolver=e}supportsDescriptor(e,r){return this.resolver.supportsDescriptor(e,r)}supportsLocator(e,r){return this.resolver.supportsLocator(e,r)}shouldPersistResolution(e,r){return this.resolver.shouldPersistResolution(e,r)}bindDescriptor(e,r,s){return this.resolver.bindDescriptor(e,r,s)}getResolutionDependencies(e,r){return this.resolver.getResolutionDependencies(e,r)}async getCandidates(e,r,s){throw new jt(20,`This package doesn't seem to be present in your lockfile; run "yarn install" to update the lockfile`)}async getSatisfying(e,r,s,a){throw new jt(20,`This package doesn't seem to be present in your lockfile; run "yarn install" to update the lockfile`)}async resolve(e,r){throw new jt(20,`This package doesn't seem to be present in your lockfile; run "yarn install" to update the lockfile`)}}});var ki,VG=Xe(()=>{Tc();ki=class extends Ao{reportCacheHit(e){}reportCacheMiss(e){}startSectionSync(e,r){return r()}async startSectionPromise(e,r){return await r()}startTimerSync(e,r,s){return(typeof r=="function"?r:s)()}async startTimerPromise(e,r,s){return await(typeof r=="function"?r:s)()}reportSeparator(){}reportInfo(e,r){}reportWarning(e,r){}reportError(e,r){}reportProgress(e){return{...Promise.resolve().then(async()=>{for await(let{}of e);}),stop:()=>{}}}reportJson(e){}reportFold(e,r){}async finalize(){}}});var Ide,XI,JG=Xe(()=>{Dt();Ide=ut(BQ());oI();tm();xc();I0();Rp();Wo();XI=class{constructor(e,{project:r}){this.workspacesCwds=new Set;this.project=r,this.cwd=e}async setup(){this.manifest=await Ut.tryFind(this.cwd)??new Ut,this.relativeCwd=J.relative(this.project.cwd,this.cwd)||vt.dot;let e=this.manifest.name?this.manifest.name:Da(null,`${this.computeCandidateName()}-${us(this.relativeCwd).substring(0,6)}`);this.anchoredDescriptor=On(e,`${Ei.protocol}${this.relativeCwd}`),this.anchoredLocator=Ws(e,`${Ei.protocol}${this.relativeCwd}`);let r=this.manifest.workspaceDefinitions.map(({pattern:a})=>a);if(r.length===0)return;let s=await(0,Ide.default)(r,{cwd:fe.fromPortablePath(this.cwd),onlyDirectories:!0,ignore:["**/node_modules","**/.git","**/.yarn"]});s.sort(),await s.reduce(async(a,n)=>{let c=J.resolve(this.cwd,fe.toPortablePath(n)),f=await ce.existsPromise(J.join(c,"package.json"));await a,f&&this.workspacesCwds.add(c)},Promise.resolve())}get anchoredPackage(){let e=this.project.storedPackages.get(this.anchoredLocator.locatorHash);if(!e)throw new Error(`Assertion failed: Expected workspace ${GB(this.project.configuration,this)} (${Ht(this.project.configuration,J.join(this.cwd,Er.manifest),ht.PATH)}) to have been resolved. Run "yarn install" to update the lockfile`);return e}accepts(e){let r=e.indexOf(":"),s=r!==-1?e.slice(0,r+1):null,a=r!==-1?e.slice(r+1):e;if(s===Ei.protocol&&J.normalize(a)===this.relativeCwd||s===Ei.protocol&&(a==="*"||a==="^"||a==="~"))return!0;let n=cl(a);return n?s===Ei.protocol?n.test(this.manifest.version??"0.0.0"):this.project.configuration.get("enableTransparentWorkspaces")&&this.manifest.version!==null?n.test(this.manifest.version):!1:!1}computeCandidateName(){return this.cwd===this.project.cwd?"root-workspace":`${J.basename(this.cwd)}`||"unnamed-workspace"}getRecursiveWorkspaceDependencies({dependencies:e=Ut.hardDependencies}={}){let r=new Set,s=a=>{for(let n of e)for(let c of a.manifest[n].values()){let f=this.project.tryWorkspaceByDescriptor(c);f===null||r.has(f)||(r.add(f),s(f))}};return s(this),r}getRecursiveWorkspaceDependents({dependencies:e=Ut.hardDependencies}={}){let r=new Set,s=a=>{for(let n of this.project.workspaces)e.some(f=>[...n.manifest[f].values()].some(p=>{let h=this.project.tryWorkspaceByDescriptor(p);return h!==null&&_B(h.anchoredLocator,a.anchoredLocator)}))&&!r.has(n)&&(r.add(n),s(n))};return s(this),r}getRecursiveWorkspaceChildren(){let e=new Set([this]);for(let r of e)for(let s of r.workspacesCwds){let a=this.project.workspacesByCwd.get(s);a&&e.add(a)}return e.delete(this),Array.from(e)}async persistManifest(){let e={};this.manifest.exportTo(e);let r=J.join(this.cwd,Ut.fileName),s=`${JSON.stringify(e,null,this.manifest.indent)} +`;await ce.changeFilePromise(r,s,{automaticNewlines:!0}),this.manifest.raw=e}}});function hat({project:t,allDescriptors:e,allResolutions:r,allPackages:s,accessibleLocators:a=new Set,optionalBuilds:n=new Set,peerRequirements:c=new Map,peerWarnings:f=[],peerRequirementNodes:p=new Map,volatileDescriptors:h=new Set}){let E=new Map,C=[],S=new Map,P=new Map,I=new Map,R=new Map,N=new Map,U=new Map(t.workspaces.map(le=>{let me=le.anchoredLocator.locatorHash,pe=s.get(me);if(typeof pe>"u")throw new Error("Assertion failed: The workspace should have an associated package");return[me,LB(pe)]})),W=()=>{let le=ce.mktempSync(),me=J.join(le,"stacktrace.log"),pe=String(C.length+1).length,Be=C.map((Ce,g)=>`${`${g+1}.`.padStart(pe," ")} ${ll(Ce)} +`).join("");throw ce.writeFileSync(me,Be),ce.detachTemp(le),new jt(45,`Encountered a stack overflow when resolving peer dependencies; cf ${fe.fromPortablePath(me)}`)},ee=le=>{let me=r.get(le.descriptorHash);if(typeof me>"u")throw new Error("Assertion failed: The resolution should have been registered");let pe=s.get(me);if(!pe)throw new Error("Assertion failed: The package could not be found");return pe},ie=(le,me,pe,{top:Be,optional:Ce})=>{C.length>1e3&&W(),C.push(me);let g=ue(le,me,pe,{top:Be,optional:Ce});return C.pop(),g},ue=(le,me,pe,{top:Be,optional:Ce})=>{if(Ce||n.delete(me.locatorHash),a.has(me.locatorHash))return;a.add(me.locatorHash);let g=s.get(me.locatorHash);if(!g)throw new Error(`Assertion failed: The package (${Yr(t.configuration,me)}) should have been registered`);let we=new Set,ye=new Map,Ae=[],se=[],Z=[],De=[];for(let Re of Array.from(g.dependencies.values())){if(g.peerDependencies.has(Re.identHash)&&g.locatorHash!==Be)continue;if(kp(Re))throw new Error("Assertion failed: Virtual packages shouldn't be encountered when virtualizing a branch");h.delete(Re.descriptorHash);let mt=Ce;if(!mt){let ke=g.dependenciesMeta.get(un(Re));if(typeof ke<"u"){let it=ke.get(null);typeof it<"u"&&it.optional&&(mt=!0)}}let j=r.get(Re.descriptorHash);if(!j)throw new Error(`Assertion failed: The resolution (${ni(t.configuration,Re)}) should have been registered`);let rt=U.get(j)||s.get(j);if(!rt)throw new Error(`Assertion failed: The package (${j}, resolved from ${ni(t.configuration,Re)}) should have been registered`);if(rt.peerDependencies.size===0){ie(Re,rt,new Map,{top:Be,optional:mt});continue}let Fe,Ne,Pe=new Set,Ve=new Map;Ae.push(()=>{Fe=b8(Re,me.locatorHash),Ne=P8(rt,me.locatorHash),g.dependencies.set(Re.identHash,Fe),r.set(Fe.descriptorHash,Ne.locatorHash),e.set(Fe.descriptorHash,Fe),s.set(Ne.locatorHash,Ne),bp(R,Ne.locatorHash).add(Fe.descriptorHash),we.add(Ne.locatorHash)}),se.push(()=>{N.set(Ne.locatorHash,Ve);for(let ke of Ne.peerDependencies.values()){let Ue=Yl(ye,ke.identHash,()=>{let x=pe.get(ke.identHash)??null,w=g.dependencies.get(ke.identHash);return!w&&UB(me,ke)&&(le.identHash===me.identHash?w=le:(w=On(me,le.range),e.set(w.descriptorHash,w),r.set(w.descriptorHash,me.locatorHash),h.delete(w.descriptorHash),x=null)),w||(w=On(ke,"missing:")),{subject:me,ident:ke,provided:w,root:!x,requests:new Map,hash:`p${us(me.locatorHash,ke.identHash).slice(0,6)}`}}).provided;if(Ue.range==="missing:"&&Ne.dependencies.has(ke.identHash)){Ne.peerDependencies.delete(ke.identHash);continue}if(Ve.set(ke.identHash,{requester:Ne,descriptor:ke,meta:Ne.peerDependenciesMeta.get(un(ke)),children:new Map}),Ne.dependencies.set(ke.identHash,Ue),kp(Ue)){let x=r.get(Ue.descriptorHash);bp(I,x).add(Ne.locatorHash)}S.set(Ue.identHash,Ue),Ue.range==="missing:"&&Pe.add(Ue.identHash)}Ne.dependencies=new Map(qs(Ne.dependencies,([ke,it])=>un(it)))}),Z.push(()=>{if(!s.has(Ne.locatorHash))return;let ke=E.get(rt.locatorHash);typeof ke=="number"&&ke>=2&&W();let it=E.get(rt.locatorHash),Ue=typeof it<"u"?it+1:1;E.set(rt.locatorHash,Ue),ie(Fe,Ne,Ve,{top:Be,optional:mt}),E.set(rt.locatorHash,Ue-1)}),De.push(()=>{let ke=r.get(Fe.descriptorHash);if(typeof ke>"u")throw new Error("Assertion failed: Expected the descriptor to be registered");let it=N.get(ke);if(typeof it>"u")throw new Error("Assertion failed: Expected the peer requests to be registered");for(let Ue of ye.values()){let x=it.get(Ue.ident.identHash);x&&(Ue.requests.set(Fe.descriptorHash,x),p.set(Ue.hash,Ue),Ue.root||pe.get(Ue.ident.identHash)?.children.set(Fe.descriptorHash,x))}if(s.has(Ne.locatorHash))for(let Ue of Pe)Ne.dependencies.delete(Ue)})}for(let Re of[...Ae,...se])Re();for(let Re of we){we.delete(Re);let mt=s.get(Re),j=us(rI(mt).locatorHash,...Array.from(mt.dependencies.values(),Pe=>{let Ve=Pe.range!=="missing:"?r.get(Pe.descriptorHash):"missing:";if(typeof Ve>"u")throw new Error(`Assertion failed: Expected the resolution for ${ni(t.configuration,Pe)} to have been registered`);return Ve===Be?`${Ve} (top)`:Ve})),rt=P.get(j);if(typeof rt>"u"){P.set(j,mt);continue}let Fe=bp(R,rt.locatorHash);for(let Pe of R.get(mt.locatorHash)??[])r.set(Pe,rt.locatorHash),Fe.add(Pe);s.delete(mt.locatorHash),a.delete(mt.locatorHash),we.delete(mt.locatorHash);let Ne=I.get(mt.locatorHash);if(Ne!==void 0){let Pe=bp(I,rt.locatorHash);for(let Ve of Ne)Pe.add(Ve),we.add(Ve)}}for(let Re of[...Z,...De])Re()};for(let le of t.workspaces){let me=le.anchoredLocator;h.delete(le.anchoredDescriptor.descriptorHash),ie(le.anchoredDescriptor,me,new Map,{top:me.locatorHash,optional:!1})}for(let le of p.values()){if(!le.root)continue;let me=s.get(le.subject.locatorHash);if(typeof me>"u")continue;for(let Be of le.requests.values()){let Ce=`p${us(le.subject.locatorHash,un(le.ident),Be.requester.locatorHash).slice(0,6)}`;c.set(Ce,{subject:le.subject.locatorHash,requested:le.ident,rootRequester:Be.requester.locatorHash,allRequesters:Array.from(qB(Be),g=>g.requester.locatorHash)})}let pe=[...qB(le)];if(le.provided.range!=="missing:"){let Be=ee(le.provided),Ce=Be.version??"0.0.0",g=ye=>{if(ye.startsWith(Ei.protocol)){if(!t.tryWorkspaceByLocator(Be))return null;ye=ye.slice(Ei.protocol.length),(ye==="^"||ye==="~")&&(ye="*")}return ye},we=!0;for(let ye of pe){let Ae=g(ye.descriptor.range);if(Ae===null){we=!1;continue}if(!Zf(Ce,Ae)){we=!1;let se=`p${us(le.subject.locatorHash,un(le.ident),ye.requester.locatorHash).slice(0,6)}`;f.push({type:1,subject:me,requested:le.ident,requester:ye.requester,version:Ce,hash:se,requirementCount:pe.length})}}if(!we){let ye=pe.map(Ae=>g(Ae.descriptor.range));f.push({type:3,node:le,range:ye.includes(null)?null:Q8(ye),hash:le.hash})}}else{let Be=!0;for(let Ce of pe)if(!Ce.meta?.optional){Be=!1;let g=`p${us(le.subject.locatorHash,un(le.ident),Ce.requester.locatorHash).slice(0,6)}`;f.push({type:0,subject:me,requested:le.ident,requester:Ce.requester,hash:g})}Be||f.push({type:2,node:le,hash:le.hash})}}}function*gat(t){let e=new Map;if("children"in t)e.set(t,t);else for(let r of t.requests.values())e.set(r,r);for(let[r,s]of e){yield{request:r,root:s};for(let a of r.children.values())e.has(a)||e.set(a,s)}}function dat(t,e){let r=[],s=[],a=!1;for(let n of t.peerWarnings)if(!(n.type===1||n.type===0)){if(!t.tryWorkspaceByLocator(n.node.subject)){a=!0;continue}if(n.type===3){let c=t.storedResolutions.get(n.node.provided.descriptorHash);if(typeof c>"u")throw new Error("Assertion failed: Expected the descriptor to be registered");let f=t.storedPackages.get(c);if(typeof f>"u")throw new Error("Assertion failed: Expected the package to be registered");let p=p0(gat(n.node),({request:C,root:S})=>Zf(f.version??"0.0.0",C.descriptor.range)?p0.skip:C===S?$i(t.configuration,C.requester):`${$i(t.configuration,C.requester)} (via ${$i(t.configuration,S.requester)})`),h=[...qB(n.node)].length>1?"and other dependencies request":"requests",E=n.range?iI(t.configuration,n.range):Ht(t.configuration,"but they have non-overlapping ranges!","redBright");r.push(`${$i(t.configuration,n.node.ident)} is listed by your project with version ${jB(t.configuration,f.version??"0.0.0")} (${Ht(t.configuration,n.hash,ht.CODE)}), which doesn't satisfy what ${p} ${h} (${E}).`)}if(n.type===2){let c=n.node.requests.size>1?" and other dependencies":"";s.push(`${Yr(t.configuration,n.node.subject)} doesn't provide ${$i(t.configuration,n.node.ident)} (${Ht(t.configuration,n.hash,ht.CODE)}), requested by ${$i(t.configuration,n.node.requests.values().next().value.requester)}${c}.`)}}e.startSectionSync({reportFooter:()=>{e.reportWarning(86,`Some peer dependencies are incorrectly met by your project; run ${Ht(t.configuration,"yarn explain peer-requirements ",ht.CODE)} for details, where ${Ht(t.configuration,"",ht.CODE)} is the six-letter p-prefixed code.`)},skipIfEmpty:!0},()=>{for(let n of qs(r,c=>JE.default(c)))e.reportWarning(60,n);for(let n of qs(s,c=>JE.default(c)))e.reportWarning(2,n)}),a&&e.reportWarning(86,`Some peer dependencies are incorrectly met by dependencies; run ${Ht(t.configuration,"yarn explain peer-requirements",ht.CODE)} for details.`)}var GR,qR,Bde,XG,zG,ZG,WR,cat,uat,Cde,fat,Aat,pat,$l,KG,YR,wde,Tt,vde=Xe(()=>{Dt();Dt();wc();Yt();GR=Ie("crypto");YG();ql();qR=ut(Ld()),Bde=ut(Ai()),XG=Ie("util"),zG=ut(Ie("v8")),ZG=ut(Ie("zlib"));LG();av();MG();UG();oI();F8();Tc();Ede();Ev();VG();tm();JG();LQ();xc();I0();Pc();gT();zj();Rp();Wo();WR=YE(process.env.YARN_LOCKFILE_VERSION_OVERRIDE??8),cat=3,uat=/ *, */g,Cde=/\/$/,fat=32,Aat=(0,XG.promisify)(ZG.default.gzip),pat=(0,XG.promisify)(ZG.default.gunzip),$l=(r=>(r.UpdateLockfile="update-lockfile",r.SkipBuild="skip-build",r))($l||{}),KG={restoreLinkersCustomData:["linkersCustomData"],restoreResolutions:["accessibleLocators","conditionalLocators","disabledLocators","optionalBuilds","storedDescriptors","storedResolutions","storedPackages","lockFileChecksum"],restoreBuildState:["skippedBuilds","storedBuildState"]},YR=(a=>(a[a.NotProvided=0]="NotProvided",a[a.NotCompatible=1]="NotCompatible",a[a.NodeNotProvided=2]="NodeNotProvided",a[a.NodeNotCompatible=3]="NodeNotCompatible",a))(YR||{}),wde=t=>us(`${cat}`,t),Tt=class t{constructor(e,{configuration:r}){this.resolutionAliases=new Map;this.workspaces=[];this.workspacesByCwd=new Map;this.workspacesByIdent=new Map;this.storedResolutions=new Map;this.storedDescriptors=new Map;this.storedPackages=new Map;this.storedChecksums=new Map;this.storedBuildState=new Map;this.accessibleLocators=new Set;this.conditionalLocators=new Set;this.disabledLocators=new Set;this.originalPackages=new Map;this.optionalBuilds=new Set;this.skippedBuilds=new Set;this.lockfileLastVersion=null;this.lockfileNeedsRefresh=!1;this.peerRequirements=new Map;this.peerWarnings=[];this.peerRequirementNodes=new Map;this.linkersCustomData=new Map;this.lockFileChecksum=null;this.installStateChecksum=null;this.configuration=r,this.cwd=e}static async find(e,r){if(!e.projectCwd)throw new nt(`No project found in ${r}`);let s=e.projectCwd,a=r,n=null;for(;n!==e.projectCwd;){if(n=a,ce.existsSync(J.join(n,Er.manifest))){s=n;break}a=J.dirname(n)}let c=new t(e.projectCwd,{configuration:e});ze.telemetry?.reportProject(c.cwd),await c.setupResolutions(),await c.setupWorkspaces(),ze.telemetry?.reportWorkspaceCount(c.workspaces.length),ze.telemetry?.reportDependencyCount(c.workspaces.reduce((I,R)=>I+R.manifest.dependencies.size+R.manifest.devDependencies.size,0));let f=c.tryWorkspaceByCwd(s);if(f)return{project:c,workspace:f,locator:f.anchoredLocator};let p=await c.findLocatorForLocation(`${s}/`,{strict:!0});if(p)return{project:c,locator:p,workspace:null};let h=Ht(e,c.cwd,ht.PATH),E=Ht(e,J.relative(c.cwd,s),ht.PATH),C=`- If ${h} isn't intended to be a project, remove any yarn.lock and/or package.json file there.`,S=`- If ${h} is intended to be a project, it might be that you forgot to list ${E} in its workspace configuration.`,P=`- Finally, if ${h} is fine and you intend ${E} to be treated as a completely separate project (not even a workspace), create an empty yarn.lock file in it.`;throw new nt(`The nearest package directory (${Ht(e,s,ht.PATH)}) doesn't seem to be part of the project declared in ${Ht(e,c.cwd,ht.PATH)}. + +${[C,S,P].join(` +`)}`)}async setupResolutions(){this.storedResolutions=new Map,this.storedDescriptors=new Map,this.storedPackages=new Map,this.lockFileChecksum=null;let e=J.join(this.cwd,Er.lockfile),r=this.configuration.get("defaultLanguageName");if(ce.existsSync(e)){let s=await ce.readFilePromise(e,"utf8");this.lockFileChecksum=wde(s);let a=ls(s);if(a.__metadata){let n=a.__metadata.version,c=a.__metadata.cacheKey;this.lockfileLastVersion=n,this.lockfileNeedsRefresh=n"u")throw new Error(`Assertion failed: Expected the lockfile entry to have a resolution field (${f})`);let h=Qp(p.resolution,!0),E=new Ut;E.load(p,{yamlCompatibilityMode:!0});let C=E.version,S=E.languageName||r,P=p.linkType.toUpperCase(),I=p.conditions??null,R=E.dependencies,N=E.peerDependencies,U=E.dependenciesMeta,W=E.peerDependenciesMeta,ee=E.bin;if(p.checksum!=null){let ue=typeof c<"u"&&!p.checksum.includes("/")?`${c}/${p.checksum}`:p.checksum;this.storedChecksums.set(h.locatorHash,ue)}let ie={...h,version:C,languageName:S,linkType:P,conditions:I,dependencies:R,peerDependencies:N,dependenciesMeta:U,peerDependenciesMeta:W,bin:ee};this.originalPackages.set(ie.locatorHash,ie);for(let ue of f.split(uat)){let le=C0(ue);n<=6&&(le=this.configuration.normalizeDependency(le),le=On(le,le.range.replace(/^patch:[^@]+@(?!npm(:|%3A))/,"$1npm%3A"))),this.storedDescriptors.set(le.descriptorHash,le),this.storedResolutions.set(le.descriptorHash,h.locatorHash)}}}else s.includes("yarn lockfile v1")&&(this.lockfileLastVersion=-1)}}async setupWorkspaces(){this.workspaces=[],this.workspacesByCwd=new Map,this.workspacesByIdent=new Map;let e=new Set,r=(0,qR.default)(4),s=async(a,n)=>{if(e.has(n))return a;e.add(n);let c=new XI(n,{project:this});await r(()=>c.setup());let f=a.then(()=>{this.addWorkspace(c)});return Array.from(c.workspacesCwds).reduce(s,f)};await s(Promise.resolve(),this.cwd)}addWorkspace(e){let r=this.workspacesByIdent.get(e.anchoredLocator.identHash);if(typeof r<"u")throw new Error(`Duplicate workspace name ${$i(this.configuration,e.anchoredLocator)}: ${fe.fromPortablePath(e.cwd)} conflicts with ${fe.fromPortablePath(r.cwd)}`);this.workspaces.push(e),this.workspacesByCwd.set(e.cwd,e),this.workspacesByIdent.set(e.anchoredLocator.identHash,e)}get topLevelWorkspace(){return this.getWorkspaceByCwd(this.cwd)}tryWorkspaceByCwd(e){J.isAbsolute(e)||(e=J.resolve(this.cwd,e)),e=J.normalize(e).replace(/\/+$/,"");let r=this.workspacesByCwd.get(e);return r||null}getWorkspaceByCwd(e){let r=this.tryWorkspaceByCwd(e);if(!r)throw new Error(`Workspace not found (${e})`);return r}tryWorkspaceByFilePath(e){let r=null;for(let s of this.workspaces)J.relative(s.cwd,e).startsWith("../")||r&&r.cwd.length>=s.cwd.length||(r=s);return r||null}getWorkspaceByFilePath(e){let r=this.tryWorkspaceByFilePath(e);if(!r)throw new Error(`Workspace not found (${e})`);return r}tryWorkspaceByIdent(e){let r=this.workspacesByIdent.get(e.identHash);return typeof r>"u"?null:r}getWorkspaceByIdent(e){let r=this.tryWorkspaceByIdent(e);if(!r)throw new Error(`Workspace not found (${$i(this.configuration,e)})`);return r}tryWorkspaceByDescriptor(e){if(e.range.startsWith(Ei.protocol)){let s=e.range.slice(Ei.protocol.length);if(s!=="^"&&s!=="~"&&s!=="*"&&!cl(s))return this.tryWorkspaceByCwd(s)}let r=this.tryWorkspaceByIdent(e);return r===null||(kp(e)&&(e=MB(e)),!r.accepts(e.range))?null:r}getWorkspaceByDescriptor(e){let r=this.tryWorkspaceByDescriptor(e);if(r===null)throw new Error(`Workspace not found (${ni(this.configuration,e)})`);return r}tryWorkspaceByLocator(e){let r=this.tryWorkspaceByIdent(e);return r===null||(Gu(e)&&(e=rI(e)),r.anchoredLocator.locatorHash!==e.locatorHash)?null:r}getWorkspaceByLocator(e){let r=this.tryWorkspaceByLocator(e);if(!r)throw new Error(`Workspace not found (${Yr(this.configuration,e)})`);return r}deleteDescriptor(e){this.storedResolutions.delete(e),this.storedDescriptors.delete(e)}deleteLocator(e){this.originalPackages.delete(e),this.storedPackages.delete(e),this.accessibleLocators.delete(e)}forgetResolution(e){if("descriptorHash"in e){let r=this.storedResolutions.get(e.descriptorHash);this.deleteDescriptor(e.descriptorHash);let s=new Set(this.storedResolutions.values());typeof r<"u"&&!s.has(r)&&this.deleteLocator(r)}if("locatorHash"in e){this.deleteLocator(e.locatorHash);for(let[r,s]of this.storedResolutions)s===e.locatorHash&&this.deleteDescriptor(r)}}forgetTransientResolutions(){let e=this.configuration.makeResolver(),r=new Map;for(let[s,a]of this.storedResolutions.entries()){let n=r.get(a);n||r.set(a,n=new Set),n.add(s)}for(let s of this.originalPackages.values()){let a;try{a=e.shouldPersistResolution(s,{project:this,resolver:e})}catch{a=!1}if(!a){this.deleteLocator(s.locatorHash);let n=r.get(s.locatorHash);if(n){r.delete(s.locatorHash);for(let c of n)this.deleteDescriptor(c)}}}}forgetVirtualResolutions(){for(let e of this.storedPackages.values())for(let[r,s]of e.dependencies)kp(s)&&e.dependencies.set(r,MB(s))}getDependencyMeta(e,r){let s={},n=this.topLevelWorkspace.manifest.dependenciesMeta.get(un(e));if(!n)return s;let c=n.get(null);if(c&&Object.assign(s,c),r===null||!Bde.default.valid(r))return s;for(let[f,p]of n)f!==null&&f===r&&Object.assign(s,p);return s}async findLocatorForLocation(e,{strict:r=!1}={}){let s=new ki,a=this.configuration.getLinkers(),n={project:this,report:s};for(let c of a){let f=await c.findPackageLocator(e,n);if(f){if(r&&(await c.findPackageLocation(f,n)).replace(Cde,"")!==e.replace(Cde,""))continue;return f}}return null}async loadUserConfig(){let e=J.join(this.cwd,".pnp.cjs");await ce.existsPromise(e)&&Pp(e).setup();let r=J.join(this.cwd,"yarn.config.cjs");return await ce.existsPromise(r)?Pp(r):null}async preparePackage(e,{resolver:r,resolveOptions:s}){let a=await this.configuration.getPackageExtensions(),n=this.configuration.normalizePackage(e,{packageExtensions:a});for(let[c,f]of n.dependencies){let p=await this.configuration.reduceHook(E=>E.reduceDependency,f,this,n,f,{resolver:r,resolveOptions:s});if(!UB(f,p))throw new Error("Assertion failed: The descriptor ident cannot be changed through aliases");let h=r.bindDescriptor(p,n,s);n.dependencies.set(c,h)}return n}async resolveEverything(e){if(!this.workspacesByCwd||!this.workspacesByIdent)throw new Error("Workspaces must have been setup before calling this function");this.forgetVirtualResolutions();let r=new Map(this.originalPackages),s=[];e.lockfileOnly||this.forgetTransientResolutions();let a=e.resolver||this.configuration.makeResolver(),n=new KI(a);await n.setup(this,{report:e.report});let c=e.lockfileOnly?[new jR(a)]:[n,a],f=new rm([new zI(a),...c]),p=new rm([...c]),h=this.configuration.makeFetcher(),E=e.lockfileOnly?{project:this,report:e.report,resolver:f}:{project:this,report:e.report,resolver:f,fetchOptions:{project:this,cache:e.cache,checksums:this.storedChecksums,report:e.report,fetcher:h,cacheOptions:{mirrorWriteOnly:!0}}},C=new Map,S=new Map,P=new Map,I=new Map,R=new Map,N=new Map,U=this.topLevelWorkspace.anchoredLocator,W=new Set,ee=[],ie=uj(),ue=this.configuration.getSupportedArchitectures();await e.report.startProgressPromise(Ao.progressViaTitle(),async se=>{let Z=async rt=>{let Fe=await qE(async()=>await f.resolve(rt,E),ke=>`${Yr(this.configuration,rt)}: ${ke}`);if(!_B(rt,Fe))throw new Error(`Assertion failed: The locator cannot be changed by the resolver (went from ${Yr(this.configuration,rt)} to ${Yr(this.configuration,Fe)})`);I.set(Fe.locatorHash,Fe),!r.delete(Fe.locatorHash)&&!this.tryWorkspaceByLocator(Fe)&&s.push(Fe);let Pe=await this.preparePackage(Fe,{resolver:f,resolveOptions:E}),Ve=Uu([...Pe.dependencies.values()].map(ke=>j(ke)));return ee.push(Ve),Ve.catch(()=>{}),S.set(Pe.locatorHash,Pe),Pe},De=async rt=>{let Fe=R.get(rt.locatorHash);if(typeof Fe<"u")return Fe;let Ne=Promise.resolve().then(()=>Z(rt));return R.set(rt.locatorHash,Ne),Ne},Re=async(rt,Fe)=>{let Ne=await j(Fe);return C.set(rt.descriptorHash,rt),P.set(rt.descriptorHash,Ne.locatorHash),Ne},mt=async rt=>{se.setTitle(ni(this.configuration,rt));let Fe=this.resolutionAliases.get(rt.descriptorHash);if(typeof Fe<"u")return Re(rt,this.storedDescriptors.get(Fe));let Ne=f.getResolutionDependencies(rt,E),Pe=Object.fromEntries(await Uu(Object.entries(Ne).map(async([it,Ue])=>{let x=f.bindDescriptor(Ue,U,E),w=await j(x);return W.add(w.locatorHash),[it,w]}))),ke=(await qE(async()=>await f.getCandidates(rt,Pe,E),it=>`${ni(this.configuration,rt)}: ${it}`))[0];if(typeof ke>"u")throw new jt(82,`${ni(this.configuration,rt)}: No candidates found`);if(e.checkResolutions){let{locators:it}=await p.getSatisfying(rt,Pe,[ke],{...E,resolver:p});if(!it.find(Ue=>Ue.locatorHash===ke.locatorHash))throw new jt(78,`Invalid resolution ${FB(this.configuration,rt,ke)}`)}return C.set(rt.descriptorHash,rt),P.set(rt.descriptorHash,ke.locatorHash),De(ke)},j=rt=>{let Fe=N.get(rt.descriptorHash);if(typeof Fe<"u")return Fe;C.set(rt.descriptorHash,rt);let Ne=Promise.resolve().then(()=>mt(rt));return N.set(rt.descriptorHash,Ne),Ne};for(let rt of this.workspaces){let Fe=rt.anchoredDescriptor;ee.push(j(Fe))}for(;ee.length>0;){let rt=[...ee];ee.length=0,await Uu(rt)}});let le=Wl(r.values(),se=>this.tryWorkspaceByLocator(se)?Wl.skip:se);if(s.length>0||le.length>0){let se=new Set(this.workspaces.flatMap(rt=>{let Fe=S.get(rt.anchoredLocator.locatorHash);if(!Fe)throw new Error("Assertion failed: The workspace should have been resolved");return Array.from(Fe.dependencies.values(),Ne=>{let Pe=P.get(Ne.descriptorHash);if(!Pe)throw new Error("Assertion failed: The resolution should have been registered");return Pe})})),Z=rt=>se.has(rt.locatorHash)?"0":"1",De=rt=>ll(rt),Re=qs(s,[Z,De]),mt=qs(le,[Z,De]),j=e.report.getRecommendedLength();Re.length>0&&e.report.reportInfo(85,`${Ht(this.configuration,"+",ht.ADDED)} ${$k(this.configuration,Re,j)}`),mt.length>0&&e.report.reportInfo(85,`${Ht(this.configuration,"-",ht.REMOVED)} ${$k(this.configuration,mt,j)}`)}let me=new Set(this.resolutionAliases.values()),pe=new Set(S.keys()),Be=new Set,Ce=new Map,g=[],we=new Map;hat({project:this,accessibleLocators:Be,volatileDescriptors:me,optionalBuilds:pe,peerRequirements:Ce,peerWarnings:g,peerRequirementNodes:we,allDescriptors:C,allResolutions:P,allPackages:S});for(let se of W)pe.delete(se);for(let se of me)C.delete(se),P.delete(se);let ye=new Set,Ae=new Set;for(let se of S.values())se.conditions!=null&&pe.has(se.locatorHash)&&(TQ(se,ue)||(TQ(se,ie)&&e.report.reportWarningOnce(77,`${Yr(this.configuration,se)}: Your current architecture (${process.platform}-${process.arch}) is supported by this package, but is missing from the ${Ht(this.configuration,"supportedArchitectures",ht.SETTING)} setting`),Ae.add(se.locatorHash)),ye.add(se.locatorHash));this.storedResolutions=P,this.storedDescriptors=C,this.storedPackages=S,this.accessibleLocators=Be,this.conditionalLocators=ye,this.disabledLocators=Ae,this.originalPackages=I,this.optionalBuilds=pe,this.peerRequirements=Ce,this.peerWarnings=g,this.peerRequirementNodes=we}async fetchEverything({cache:e,report:r,fetcher:s,mode:a,persistProject:n=!0}){let c={mockedPackages:this.disabledLocators,unstablePackages:this.conditionalLocators},f=s||this.configuration.makeFetcher(),p={checksums:this.storedChecksums,project:this,cache:e,fetcher:f,report:r,cacheOptions:c},h=Array.from(new Set(qs(this.storedResolutions.values(),[I=>{let R=this.storedPackages.get(I);if(!R)throw new Error("Assertion failed: The locator should have been registered");return ll(R)}])));a==="update-lockfile"&&(h=h.filter(I=>!this.storedChecksums.has(I)));let E=!1,C=Ao.progressViaCounter(h.length);await r.reportProgress(C);let S=(0,qR.default)(fat);if(await Uu(h.map(I=>S(async()=>{let R=this.storedPackages.get(I);if(!R)throw new Error("Assertion failed: The locator should have been registered");if(Gu(R))return;let N;try{N=await f.fetch(R,p)}catch(U){U.message=`${Yr(this.configuration,R)}: ${U.message}`,r.reportExceptionOnce(U),E=U;return}N.checksum!=null?this.storedChecksums.set(R.locatorHash,N.checksum):this.storedChecksums.delete(R.locatorHash),N.releaseFs&&N.releaseFs()}).finally(()=>{C.tick()}))),E)throw E;let P=n&&a!=="update-lockfile"?await this.cacheCleanup({cache:e,report:r}):null;if(r.cacheMisses.size>0||P){let R=(await Promise.all([...r.cacheMisses].map(async le=>{let me=this.storedPackages.get(le),pe=this.storedChecksums.get(le)??null,Be=e.getLocatorPath(me,pe);return(await ce.statPromise(Be)).size}))).reduce((le,me)=>le+me,0)-(P?.size??0),N=r.cacheMisses.size,U=P?.count??0,W=`${Wk(N,{zero:"No new packages",one:"A package was",more:`${Ht(this.configuration,N,ht.NUMBER)} packages were`})} added to the project`,ee=`${Wk(U,{zero:"none were",one:"one was",more:`${Ht(this.configuration,U,ht.NUMBER)} were`})} removed`,ie=R!==0?` (${Ht(this.configuration,R,ht.SIZE_DIFF)})`:"",ue=U>0?N>0?`${W}, and ${ee}${ie}.`:`${W}, but ${ee}${ie}.`:`${W}${ie}.`;r.reportInfo(13,ue)}}async linkEverything({cache:e,report:r,fetcher:s,mode:a}){let n={mockedPackages:this.disabledLocators,unstablePackages:this.conditionalLocators,skipIntegrityCheck:!0},c=s||this.configuration.makeFetcher(),f={checksums:this.storedChecksums,project:this,cache:e,fetcher:c,report:r,cacheOptions:n},p=this.configuration.getLinkers(),h={project:this,report:r},E=new Map(p.map(ye=>{let Ae=ye.makeInstaller(h),se=ye.getCustomDataKey(),Z=this.linkersCustomData.get(se);return typeof Z<"u"&&Ae.attachCustomData(Z),[ye,Ae]})),C=new Map,S=new Map,P=new Map,I=new Map(await Uu([...this.accessibleLocators].map(async ye=>{let Ae=this.storedPackages.get(ye);if(!Ae)throw new Error("Assertion failed: The locator should have been registered");return[ye,await c.fetch(Ae,f)]}))),R=[],N=new Set,U=[];for(let ye of this.accessibleLocators){let Ae=this.storedPackages.get(ye);if(typeof Ae>"u")throw new Error("Assertion failed: The locator should have been registered");let se=I.get(Ae.locatorHash);if(typeof se>"u")throw new Error("Assertion failed: The fetch result should have been registered");let Z=[],De=mt=>{Z.push(mt)},Re=this.tryWorkspaceByLocator(Ae);if(Re!==null){let mt=[],{scripts:j}=Re.manifest;for(let Fe of["preinstall","install","postinstall"])j.has(Fe)&&mt.push({type:0,script:Fe});try{for(let[Fe,Ne]of E)if(Fe.supportsPackage(Ae,h)&&(await Ne.installPackage(Ae,se,{holdFetchResult:De})).buildRequest!==null)throw new Error("Assertion failed: Linkers can't return build directives for workspaces; this responsibility befalls to the Yarn core")}finally{Z.length===0?se.releaseFs?.():R.push(Uu(Z).catch(()=>{}).then(()=>{se.releaseFs?.()}))}let rt=J.join(se.packageFs.getRealPath(),se.prefixPath);S.set(Ae.locatorHash,rt),!Gu(Ae)&&mt.length>0&&P.set(Ae.locatorHash,{buildDirectives:mt,buildLocations:[rt]})}else{let mt=p.find(Fe=>Fe.supportsPackage(Ae,h));if(!mt)throw new jt(12,`${Yr(this.configuration,Ae)} isn't supported by any available linker`);let j=E.get(mt);if(!j)throw new Error("Assertion failed: The installer should have been registered");let rt;try{rt=await j.installPackage(Ae,se,{holdFetchResult:De})}finally{Z.length===0?se.releaseFs?.():R.push(Uu(Z).then(()=>{}).then(()=>{se.releaseFs?.()}))}C.set(Ae.locatorHash,mt),S.set(Ae.locatorHash,rt.packageLocation),rt.buildRequest&&rt.packageLocation&&(rt.buildRequest.skipped?(N.add(Ae.locatorHash),this.skippedBuilds.has(Ae.locatorHash)||U.push([Ae,rt.buildRequest.explain])):P.set(Ae.locatorHash,{buildDirectives:rt.buildRequest.directives,buildLocations:[rt.packageLocation]}))}}let W=new Map;for(let ye of this.accessibleLocators){let Ae=this.storedPackages.get(ye);if(!Ae)throw new Error("Assertion failed: The locator should have been registered");let se=this.tryWorkspaceByLocator(Ae)!==null,Z=async(De,Re)=>{let mt=S.get(Ae.locatorHash);if(typeof mt>"u")throw new Error(`Assertion failed: The package (${Yr(this.configuration,Ae)}) should have been registered`);let j=[];for(let rt of Ae.dependencies.values()){let Fe=this.storedResolutions.get(rt.descriptorHash);if(typeof Fe>"u")throw new Error(`Assertion failed: The resolution (${ni(this.configuration,rt)}, from ${Yr(this.configuration,Ae)})should have been registered`);let Ne=this.storedPackages.get(Fe);if(typeof Ne>"u")throw new Error(`Assertion failed: The package (${Fe}, resolved from ${ni(this.configuration,rt)}) should have been registered`);let Pe=this.tryWorkspaceByLocator(Ne)===null?C.get(Fe):null;if(typeof Pe>"u")throw new Error(`Assertion failed: The package (${Fe}, resolved from ${ni(this.configuration,rt)}) should have been registered`);Pe===De||Pe===null?S.get(Ne.locatorHash)!==null&&j.push([rt,Ne]):!se&&mt!==null&&xB(W,Fe).push(mt)}mt!==null&&await Re.attachInternalDependencies(Ae,j)};if(se)for(let[De,Re]of E)De.supportsPackage(Ae,h)&&await Z(De,Re);else{let De=C.get(Ae.locatorHash);if(!De)throw new Error("Assertion failed: The linker should have been found");let Re=E.get(De);if(!Re)throw new Error("Assertion failed: The installer should have been registered");await Z(De,Re)}}for(let[ye,Ae]of W){let se=this.storedPackages.get(ye);if(!se)throw new Error("Assertion failed: The package should have been registered");let Z=C.get(se.locatorHash);if(!Z)throw new Error("Assertion failed: The linker should have been found");let De=E.get(Z);if(!De)throw new Error("Assertion failed: The installer should have been registered");await De.attachExternalDependents(se,Ae)}let ee=new Map;for(let[ye,Ae]of E){let se=await Ae.finalizeInstall();for(let Z of se?.records??[])Z.buildRequest.skipped?(N.add(Z.locator.locatorHash),this.skippedBuilds.has(Z.locator.locatorHash)||U.push([Z.locator,Z.buildRequest.explain])):P.set(Z.locator.locatorHash,{buildDirectives:Z.buildRequest.directives,buildLocations:Z.buildLocations});typeof se?.customData<"u"&&ee.set(ye.getCustomDataKey(),se.customData)}if(this.linkersCustomData=ee,await Uu(R),a==="skip-build")return;for(let[,ye]of qs(U,([Ae])=>ll(Ae)))ye(r);let ie=new Set(P.keys()),ue=(0,GR.createHash)("sha512");ue.update(process.versions.node),await this.configuration.triggerHook(ye=>ye.globalHashGeneration,this,ye=>{ue.update("\0"),ue.update(ye)});let le=ue.digest("hex"),me=new Map,pe=ye=>{let Ae=me.get(ye.locatorHash);if(typeof Ae<"u")return Ae;let se=this.storedPackages.get(ye.locatorHash);if(typeof se>"u")throw new Error("Assertion failed: The package should have been registered");let Z=(0,GR.createHash)("sha512");Z.update(ye.locatorHash),me.set(ye.locatorHash,"");for(let De of se.dependencies.values()){let Re=this.storedResolutions.get(De.descriptorHash);if(typeof Re>"u")throw new Error(`Assertion failed: The resolution (${ni(this.configuration,De)}) should have been registered`);let mt=this.storedPackages.get(Re);if(typeof mt>"u")throw new Error("Assertion failed: The package should have been registered");Z.update(pe(mt))}return Ae=Z.digest("hex"),me.set(ye.locatorHash,Ae),Ae},Be=(ye,Ae)=>{let se=(0,GR.createHash)("sha512");se.update(le),se.update(pe(ye));for(let Z of Ae)se.update(Z);return se.digest("hex")},Ce=new Map,g=!1,we=ye=>{let Ae=new Set([ye.locatorHash]);for(let se of Ae){let Z=this.storedPackages.get(se);if(!Z)throw new Error("Assertion failed: The package should have been registered");for(let De of Z.dependencies.values()){let Re=this.storedResolutions.get(De.descriptorHash);if(!Re)throw new Error(`Assertion failed: The resolution (${ni(this.configuration,De)}) should have been registered`);if(Re!==ye.locatorHash&&ie.has(Re))return!1;let mt=this.storedPackages.get(Re);if(!mt)throw new Error("Assertion failed: The package should have been registered");let j=this.tryWorkspaceByLocator(mt);if(j){if(j.anchoredLocator.locatorHash!==ye.locatorHash&&ie.has(j.anchoredLocator.locatorHash))return!1;Ae.add(j.anchoredLocator.locatorHash)}Ae.add(Re)}}return!0};for(;ie.size>0;){let ye=ie.size,Ae=[];for(let se of ie){let Z=this.storedPackages.get(se);if(!Z)throw new Error("Assertion failed: The package should have been registered");if(!we(Z))continue;let De=P.get(Z.locatorHash);if(!De)throw new Error("Assertion failed: The build directive should have been registered");let Re=Be(Z,De.buildLocations);if(this.storedBuildState.get(Z.locatorHash)===Re){Ce.set(Z.locatorHash,Re),ie.delete(se);continue}g||(await this.persistInstallStateFile(),g=!0),this.storedBuildState.has(Z.locatorHash)?r.reportInfo(8,`${Yr(this.configuration,Z)} must be rebuilt because its dependency tree changed`):r.reportInfo(7,`${Yr(this.configuration,Z)} must be built because it never has been before or the last one failed`);let mt=De.buildLocations.map(async j=>{if(!J.isAbsolute(j))throw new Error(`Assertion failed: Expected the build location to be absolute (not ${j})`);for(let rt of De.buildDirectives){let Fe=`# This file contains the result of Yarn building a package (${ll(Z)}) +`;switch(rt.type){case 0:Fe+=`# Script name: ${rt.script} +`;break;case 1:Fe+=`# Script code: ${rt.script} +`;break}let Ne=null;if(!await ce.mktempPromise(async Ve=>{let ke=J.join(Ve,"build.log"),{stdout:it,stderr:Ue}=this.configuration.getSubprocessStreams(ke,{header:Fe,prefix:Yr(this.configuration,Z),report:r}),x;try{switch(rt.type){case 0:x=await LT(Z,rt.script,[],{cwd:j,project:this,stdin:Ne,stdout:it,stderr:Ue});break;case 1:x=await Yj(Z,rt.script,[],{cwd:j,project:this,stdin:Ne,stdout:it,stderr:Ue});break}}catch(y){Ue.write(y.stack),x=1}if(it.end(),Ue.end(),x===0)return!0;ce.detachTemp(Ve);let w=`${Yr(this.configuration,Z)} couldn't be built successfully (exit code ${Ht(this.configuration,x,ht.NUMBER)}, logs can be found here: ${Ht(this.configuration,ke,ht.PATH)})`,b=this.optionalBuilds.has(Z.locatorHash);return b?r.reportInfo(9,w):r.reportError(9,w),ehe&&r.reportFold(fe.fromPortablePath(ke),ce.readFileSync(ke,"utf8")),b}))return!1}return!0});Ae.push(...mt,Promise.allSettled(mt).then(j=>{ie.delete(se),j.every(rt=>rt.status==="fulfilled"&&rt.value===!0)&&Ce.set(Z.locatorHash,Re)}))}if(await Uu(Ae),ye===ie.size){let se=Array.from(ie).map(Z=>{let De=this.storedPackages.get(Z);if(!De)throw new Error("Assertion failed: The package should have been registered");return Yr(this.configuration,De)}).join(", ");r.reportError(3,`Some packages have circular dependencies that make their build order unsatisfiable - as a result they won't be built (affected packages are: ${se})`);break}}this.storedBuildState=Ce,this.skippedBuilds=N}async installWithNewReport(e,r){return(await Ot.start({configuration:this.configuration,json:e.json,stdout:e.stdout,forceSectionAlignment:!0,includeLogs:!e.json&&!e.quiet,includeVersion:!0},async a=>{await this.install({...r,report:a})})).exitCode()}async install(e){let r=this.configuration.get("nodeLinker");ze.telemetry?.reportInstall(r);let s=!1;if(await e.report.startTimerPromise("Project validation",{skipIfEmpty:!0},async()=>{this.configuration.get("enableOfflineMode")&&e.report.reportWarning(90,"Offline work is enabled; Yarn won't fetch packages from the remote registry if it can avoid it"),await this.configuration.triggerHook(E=>E.validateProject,this,{reportWarning:(E,C)=>{e.report.reportWarning(E,C)},reportError:(E,C)=>{e.report.reportError(E,C),s=!0}})}),s)return;let a=await this.configuration.getPackageExtensions();for(let E of a.values())for(let[,C]of E)for(let S of C)S.status="inactive";let n=J.join(this.cwd,Er.lockfile),c=null;if(e.immutable)try{c=await ce.readFilePromise(n,"utf8")}catch(E){throw E.code==="ENOENT"?new jt(28,"The lockfile would have been created by this install, which is explicitly forbidden."):E}await e.report.startTimerPromise("Resolution step",async()=>{await this.resolveEverything(e)}),await e.report.startTimerPromise("Post-resolution validation",{skipIfEmpty:!0},async()=>{dat(this,e.report);for(let[,E]of a)for(let[,C]of E)for(let S of C)if(S.userProvided){let P=Ht(this.configuration,S,ht.PACKAGE_EXTENSION);switch(S.status){case"inactive":e.report.reportWarning(68,`${P}: No matching package in the dependency tree; you may not need this rule anymore.`);break;case"redundant":e.report.reportWarning(69,`${P}: This rule seems redundant when applied on the original package; the extension may have been applied upstream.`);break}}if(c!==null){let E=Ed(c,this.generateLockfile());if(E!==c){let C=yde(n,n,c,E,void 0,void 0,{maxEditLength:100});if(C){e.report.reportSeparator();for(let S of C.hunks){e.report.reportInfo(null,`@@ -${S.oldStart},${S.oldLines} +${S.newStart},${S.newLines} @@`);for(let P of S.lines)P.startsWith("+")?e.report.reportError(28,Ht(this.configuration,P,ht.ADDED)):P.startsWith("-")?e.report.reportError(28,Ht(this.configuration,P,ht.REMOVED)):e.report.reportInfo(null,Ht(this.configuration,P,"grey"))}e.report.reportSeparator()}throw new jt(28,"The lockfile would have been modified by this install, which is explicitly forbidden.")}}});for(let E of a.values())for(let[,C]of E)for(let S of C)S.userProvided&&S.status==="active"&&ze.telemetry?.reportPackageExtension(Xd(S,ht.PACKAGE_EXTENSION));await e.report.startTimerPromise("Fetch step",async()=>{await this.fetchEverything(e)});let f=e.immutable?[...new Set(this.configuration.get("immutablePatterns"))].sort():[],p=await Promise.all(f.map(async E=>DQ(E,{cwd:this.cwd})));(typeof e.persistProject>"u"||e.persistProject)&&await this.persist(),await e.report.startTimerPromise("Link step",async()=>{if(e.mode==="update-lockfile"){e.report.reportWarning(73,`Skipped due to ${Ht(this.configuration,"mode=update-lockfile",ht.CODE)}`);return}await this.linkEverything(e);let E=await Promise.all(f.map(async C=>DQ(C,{cwd:this.cwd})));for(let C=0;C{await this.configuration.triggerHook(E=>E.validateProjectAfterInstall,this,{reportWarning:(E,C)=>{e.report.reportWarning(E,C)},reportError:(E,C)=>{e.report.reportError(E,C),h=!0}})}),!h&&await this.configuration.triggerHook(E=>E.afterAllInstalled,this,e)}generateLockfile(){let e=new Map;for(let[n,c]of this.storedResolutions.entries()){let f=e.get(c);f||e.set(c,f=new Set),f.add(n)}let r={},{cacheKey:s}=Kr.getCacheKey(this.configuration);r.__metadata={version:WR,cacheKey:s};for(let[n,c]of e.entries()){let f=this.originalPackages.get(n);if(!f)continue;let p=[];for(let C of c){let S=this.storedDescriptors.get(C);if(!S)throw new Error("Assertion failed: The descriptor should have been registered");p.push(S)}let h=p.map(C=>al(C)).sort().join(", "),E=new Ut;E.version=f.linkType==="HARD"?f.version:"0.0.0-use.local",E.languageName=f.languageName,E.dependencies=new Map(f.dependencies),E.peerDependencies=new Map(f.peerDependencies),E.dependenciesMeta=new Map(f.dependenciesMeta),E.peerDependenciesMeta=new Map(f.peerDependenciesMeta),E.bin=new Map(f.bin),r[h]={...E.exportTo({},{compatibilityMode:!1}),linkType:f.linkType.toLowerCase(),resolution:ll(f),checksum:this.storedChecksums.get(f.locatorHash),conditions:f.conditions||void 0}}return`${[`# This file is generated by running "yarn install" inside your project. +`,`# Manual changes might be lost - proceed with caution! +`].join("")} +`+nl(r)}async persistLockfile(){let e=J.join(this.cwd,Er.lockfile),r="";try{r=await ce.readFilePromise(e,"utf8")}catch{}let s=this.generateLockfile(),a=Ed(r,s);a!==r&&(await ce.writeFilePromise(e,a),this.lockFileChecksum=wde(a),this.lockfileNeedsRefresh=!1)}async persistInstallStateFile(){let e=[];for(let c of Object.values(KG))e.push(...c);let r=Kd(this,e),s=zG.default.serialize(r),a=us(s);if(this.installStateChecksum===a)return;let n=this.configuration.get("installStatePath");await ce.mkdirPromise(J.dirname(n),{recursive:!0}),await ce.writeFilePromise(n,await Aat(s)),this.installStateChecksum=a}async restoreInstallState({restoreLinkersCustomData:e=!0,restoreResolutions:r=!0,restoreBuildState:s=!0}={}){let a=this.configuration.get("installStatePath"),n;try{let c=await pat(await ce.readFilePromise(a));n=zG.default.deserialize(c),this.installStateChecksum=us(c)}catch{r&&await this.applyLightResolution();return}e&&typeof n.linkersCustomData<"u"&&(this.linkersCustomData=n.linkersCustomData),s&&Object.assign(this,Kd(n,KG.restoreBuildState)),r&&(n.lockFileChecksum===this.lockFileChecksum?Object.assign(this,Kd(n,KG.restoreResolutions)):await this.applyLightResolution())}async applyLightResolution(){await this.resolveEverything({lockfileOnly:!0,report:new ki}),await this.persistInstallStateFile()}async persist(){let e=(0,qR.default)(4);await Promise.all([this.persistLockfile(),...this.workspaces.map(r=>e(()=>r.persistManifest()))])}async cacheCleanup({cache:e,report:r}){if(this.configuration.get("enableGlobalCache"))return null;let s=new Set([".gitignore"]);if(!q8(e.cwd,this.cwd)||!await ce.existsPromise(e.cwd))return null;let a=[];for(let c of await ce.readdirPromise(e.cwd)){if(s.has(c))continue;let f=J.resolve(e.cwd,c);e.markedFiles.has(f)||(e.immutable?r.reportError(56,`${Ht(this.configuration,J.basename(f),"magenta")} appears to be unused and would be marked for deletion, but the cache is immutable`):a.push(ce.lstatPromise(f).then(async p=>(await ce.removePromise(f),p.size))))}if(a.length===0)return null;let n=await Promise.all(a);return{count:a.length,size:n.reduce((c,f)=>c+f,0)}}}});function mat(t){let s=Math.floor(t.timeNow/864e5),a=t.updateInterval*864e5,n=t.state.lastUpdate??t.timeNow+a+Math.floor(a*t.randomInitialInterval),c=n+a,f=t.state.lastTips??s*864e5,p=f+864e5+8*36e5-t.timeZone,h=c<=t.timeNow,E=p<=t.timeNow,C=null;return(h||E||!t.state.lastUpdate||!t.state.lastTips)&&(C={},C.lastUpdate=h?t.timeNow:n,C.lastTips=f,C.blocks=h?{}:t.state.blocks,C.displayedTips=t.state.displayedTips),{nextState:C,triggerUpdate:h,triggerTips:E,nextTips:E?s*864e5:f}}var ZI,Sde=Xe(()=>{Dt();yv();I0();pT();Pc();Rp();ZI=class{constructor(e,r){this.values=new Map;this.hits=new Map;this.enumerators=new Map;this.nextTips=0;this.displayedTips=[];this.shouldCommitTips=!1;this.configuration=e;let s=this.getRegistryPath();this.isNew=!ce.existsSync(s),this.shouldShowTips=!1,this.sendReport(r),this.startBuffer()}commitTips(){this.shouldShowTips&&(this.shouldCommitTips=!0)}selectTip(e){let r=new Set(this.displayedTips),s=f=>f&&fn?Zf(fn,f):!1,a=e.map((f,p)=>p).filter(f=>e[f]&&s(e[f]?.selector));if(a.length===0)return null;let n=a.filter(f=>!r.has(f));if(n.length===0){let f=Math.floor(a.length*.2);this.displayedTips=f>0?this.displayedTips.slice(-f):[],n=a.filter(p=>!r.has(p))}let c=n[Math.floor(Math.random()*n.length)];return this.displayedTips.push(c),this.commitTips(),e[c]}reportVersion(e){this.reportValue("version",e.replace(/-git\..*/,"-git"))}reportCommandName(e){this.reportValue("commandName",e||"")}reportPluginName(e){this.reportValue("pluginName",e)}reportProject(e){this.reportEnumerator("projectCount",e)}reportInstall(e){this.reportHit("installCount",e)}reportPackageExtension(e){this.reportValue("packageExtension",e)}reportWorkspaceCount(e){this.reportValue("workspaceCount",String(e))}reportDependencyCount(e){this.reportValue("dependencyCount",String(e))}reportValue(e,r){bp(this.values,e).add(r)}reportEnumerator(e,r){bp(this.enumerators,e).add(us(r))}reportHit(e,r="*"){let s=q4(this.hits,e),a=Yl(s,r,()=>0);s.set(r,a+1)}getRegistryPath(){let e=this.configuration.get("globalFolder");return J.join(e,"telemetry.json")}sendReport(e){let r=this.getRegistryPath(),s;try{s=ce.readJsonSync(r)}catch{s={}}let{nextState:a,triggerUpdate:n,triggerTips:c,nextTips:f}=mat({state:s,timeNow:Date.now(),timeZone:new Date().getTimezoneOffset()*60*1e3,randomInitialInterval:Math.random(),updateInterval:this.configuration.get("telemetryInterval")});if(this.nextTips=f,this.displayedTips=s.displayedTips??[],a!==null)try{ce.mkdirSync(J.dirname(r),{recursive:!0}),ce.writeJsonSync(r,a)}catch{return!1}if(c&&this.configuration.get("enableTips")&&(this.shouldShowTips=!0),n){let p=s.blocks??{};if(Object.keys(p).length===0){let h=`https://browser-http-intake.logs.datadoghq.eu/v1/input/${e}?ddsource=yarn`,E=C=>cj(h,C,{configuration:this.configuration}).catch(()=>{});for(let[C,S]of Object.entries(s.blocks??{})){if(Object.keys(S).length===0)continue;let P=S;P.userId=C,P.reportType="primary";for(let N of Object.keys(P.enumerators??{}))P.enumerators[N]=P.enumerators[N].length;E(P);let I=new Map,R=20;for(let[N,U]of Object.entries(P.values))U.length>0&&I.set(N,U.slice(0,R));for(;I.size>0;){let N={};N.userId=C,N.reportType="secondary",N.metrics={};for(let[U,W]of I)N.metrics[U]=W.shift(),W.length===0&&I.delete(U);E(N)}}}}return!0}applyChanges(){let e=this.getRegistryPath(),r;try{r=ce.readJsonSync(e)}catch{r={}}let s=this.configuration.get("telemetryUserId")??"*",a=r.blocks=r.blocks??{},n=a[s]=a[s]??{};for(let c of this.hits.keys()){let f=n.hits=n.hits??{},p=f[c]=f[c]??{};for(let[h,E]of this.hits.get(c))p[h]=(p[h]??0)+E}for(let c of["values","enumerators"])for(let f of this[c].keys()){let p=n[c]=n[c]??{};p[f]=[...new Set([...p[f]??[],...this[c].get(f)??[]])]}this.shouldCommitTips&&(r.lastTips=this.nextTips,r.displayedTips=this.displayedTips),ce.mkdirSync(J.dirname(e),{recursive:!0}),ce.writeJsonSync(e,r)}startBuffer(){process.on("exit",()=>{try{this.applyChanges()}catch{}})}}});var jv={};Vt(jv,{BuildDirectiveType:()=>_R,CACHE_CHECKPOINT:()=>OG,CACHE_VERSION:()=>UR,Cache:()=>Kr,Configuration:()=>ze,DEFAULT_RC_FILENAME:()=>dj,DurationUnit:()=>mj,FormatType:()=>upe,InstallMode:()=>$l,LEGACY_PLUGINS:()=>ov,LOCKFILE_VERSION:()=>WR,LegacyMigrationResolver:()=>KI,LightReport:()=>lA,LinkType:()=>VE,LockfileResolver:()=>zI,Manifest:()=>Ut,MessageName:()=>Br,MultiFetcher:()=>aI,PackageExtensionStatus:()=>J4,PackageExtensionType:()=>V4,PeerWarningType:()=>YR,Project:()=>Tt,Report:()=>Ao,ReportError:()=>jt,SettingsType:()=>wI,StreamReport:()=>Ot,TAG_REGEXP:()=>Mp,TelemetryManager:()=>ZI,ThrowReport:()=>ki,VirtualFetcher:()=>lI,WindowsLinkType:()=>IT,Workspace:()=>XI,WorkspaceFetcher:()=>cI,WorkspaceResolver:()=>Ei,YarnVersion:()=>fn,execUtils:()=>qr,folderUtils:()=>OQ,formatUtils:()=>he,hashUtils:()=>Nn,httpUtils:()=>nn,miscUtils:()=>je,nodeUtils:()=>Ui,parseMessageName:()=>jx,reportOptionDeprecations:()=>SI,scriptUtils:()=>In,semverUtils:()=>Fr,stringifyMessageName:()=>Yf,structUtils:()=>G,tgzUtils:()=>ps,treeUtils:()=>xs});var Ge=Xe(()=>{dT();LQ();xc();I0();pT();Pc();gT();zj();Rp();Wo();nde();ude();LG();av();av();pde();MG();hde();UG();oI();Gx();R8();vde();Tc();Ev();Sde();VG();N8();O8();tm();JG();yv();hle()});var Qde=_((WHt,qv)=>{"use strict";var Eat=process.env.TERM_PROGRAM==="Hyper",Iat=process.platform==="win32",Pde=process.platform==="linux",$G={ballotDisabled:"\u2612",ballotOff:"\u2610",ballotOn:"\u2611",bullet:"\u2022",bulletWhite:"\u25E6",fullBlock:"\u2588",heart:"\u2764",identicalTo:"\u2261",line:"\u2500",mark:"\u203B",middot:"\xB7",minus:"\uFF0D",multiplication:"\xD7",obelus:"\xF7",pencilDownRight:"\u270E",pencilRight:"\u270F",pencilUpRight:"\u2710",percent:"%",pilcrow2:"\u2761",pilcrow:"\xB6",plusMinus:"\xB1",section:"\xA7",starsOff:"\u2606",starsOn:"\u2605",upDownArrow:"\u2195"},xde=Object.assign({},$G,{check:"\u221A",cross:"\xD7",ellipsisLarge:"...",ellipsis:"...",info:"i",question:"?",questionSmall:"?",pointer:">",pointerSmall:"\xBB",radioOff:"( )",radioOn:"(*)",warning:"\u203C"}),kde=Object.assign({},$G,{ballotCross:"\u2718",check:"\u2714",cross:"\u2716",ellipsisLarge:"\u22EF",ellipsis:"\u2026",info:"\u2139",question:"?",questionFull:"\uFF1F",questionSmall:"\uFE56",pointer:Pde?"\u25B8":"\u276F",pointerSmall:Pde?"\u2023":"\u203A",radioOff:"\u25EF",radioOn:"\u25C9",warning:"\u26A0"});qv.exports=Iat&&!Eat?xde:kde;Reflect.defineProperty(qv.exports,"common",{enumerable:!1,value:$G});Reflect.defineProperty(qv.exports,"windows",{enumerable:!1,value:xde});Reflect.defineProperty(qv.exports,"other",{enumerable:!1,value:kde})});var Ju=_((YHt,e5)=>{"use strict";var Cat=t=>t!==null&&typeof t=="object"&&!Array.isArray(t),wat=/[\u001b\u009b][[\]#;?()]*(?:(?:(?:[^\W_]*;?[^\W_]*)\u0007)|(?:(?:[0-9]{1,4}(;[0-9]{0,4})*)?[~0-9=<>cf-nqrtyA-PRZ]))/g,Tde=()=>{let t={enabled:!0,visible:!0,styles:{},keys:{}};"FORCE_COLOR"in process.env&&(t.enabled=process.env.FORCE_COLOR!=="0");let e=n=>{let c=n.open=`\x1B[${n.codes[0]}m`,f=n.close=`\x1B[${n.codes[1]}m`,p=n.regex=new RegExp(`\\u001b\\[${n.codes[1]}m`,"g");return n.wrap=(h,E)=>{h.includes(f)&&(h=h.replace(p,f+c));let C=c+h+f;return E?C.replace(/\r*\n/g,`${f}$&${c}`):C},n},r=(n,c,f)=>typeof n=="function"?n(c):n.wrap(c,f),s=(n,c)=>{if(n===""||n==null)return"";if(t.enabled===!1)return n;if(t.visible===!1)return"";let f=""+n,p=f.includes(` +`),h=c.length;for(h>0&&c.includes("unstyle")&&(c=[...new Set(["unstyle",...c])].reverse());h-- >0;)f=r(t.styles[c[h]],f,p);return f},a=(n,c,f)=>{t.styles[n]=e({name:n,codes:c}),(t.keys[f]||(t.keys[f]=[])).push(n),Reflect.defineProperty(t,n,{configurable:!0,enumerable:!0,set(h){t.alias(n,h)},get(){let h=E=>s(E,h.stack);return Reflect.setPrototypeOf(h,t),h.stack=this.stack?this.stack.concat(n):[n],h}})};return a("reset",[0,0],"modifier"),a("bold",[1,22],"modifier"),a("dim",[2,22],"modifier"),a("italic",[3,23],"modifier"),a("underline",[4,24],"modifier"),a("inverse",[7,27],"modifier"),a("hidden",[8,28],"modifier"),a("strikethrough",[9,29],"modifier"),a("black",[30,39],"color"),a("red",[31,39],"color"),a("green",[32,39],"color"),a("yellow",[33,39],"color"),a("blue",[34,39],"color"),a("magenta",[35,39],"color"),a("cyan",[36,39],"color"),a("white",[37,39],"color"),a("gray",[90,39],"color"),a("grey",[90,39],"color"),a("bgBlack",[40,49],"bg"),a("bgRed",[41,49],"bg"),a("bgGreen",[42,49],"bg"),a("bgYellow",[43,49],"bg"),a("bgBlue",[44,49],"bg"),a("bgMagenta",[45,49],"bg"),a("bgCyan",[46,49],"bg"),a("bgWhite",[47,49],"bg"),a("blackBright",[90,39],"bright"),a("redBright",[91,39],"bright"),a("greenBright",[92,39],"bright"),a("yellowBright",[93,39],"bright"),a("blueBright",[94,39],"bright"),a("magentaBright",[95,39],"bright"),a("cyanBright",[96,39],"bright"),a("whiteBright",[97,39],"bright"),a("bgBlackBright",[100,49],"bgBright"),a("bgRedBright",[101,49],"bgBright"),a("bgGreenBright",[102,49],"bgBright"),a("bgYellowBright",[103,49],"bgBright"),a("bgBlueBright",[104,49],"bgBright"),a("bgMagentaBright",[105,49],"bgBright"),a("bgCyanBright",[106,49],"bgBright"),a("bgWhiteBright",[107,49],"bgBright"),t.ansiRegex=wat,t.hasColor=t.hasAnsi=n=>(t.ansiRegex.lastIndex=0,typeof n=="string"&&n!==""&&t.ansiRegex.test(n)),t.alias=(n,c)=>{let f=typeof c=="string"?t[c]:c;if(typeof f!="function")throw new TypeError("Expected alias to be the name of an existing color (string) or a function");f.stack||(Reflect.defineProperty(f,"name",{value:n}),t.styles[n]=f,f.stack=[n]),Reflect.defineProperty(t,n,{configurable:!0,enumerable:!0,set(p){t.alias(n,p)},get(){let p=h=>s(h,p.stack);return Reflect.setPrototypeOf(p,t),p.stack=this.stack?this.stack.concat(f.stack):f.stack,p}})},t.theme=n=>{if(!Cat(n))throw new TypeError("Expected theme to be an object");for(let c of Object.keys(n))t.alias(c,n[c]);return t},t.alias("unstyle",n=>typeof n=="string"&&n!==""?(t.ansiRegex.lastIndex=0,n.replace(t.ansiRegex,"")):""),t.alias("noop",n=>n),t.none=t.clear=t.noop,t.stripColor=t.unstyle,t.symbols=Qde(),t.define=a,t};e5.exports=Tde();e5.exports.create=Tde});var Zo=_(pn=>{"use strict";var Bat=Object.prototype.toString,jc=Ju(),Rde=!1,t5=[],Fde={yellow:"blue",cyan:"red",green:"magenta",black:"white",blue:"yellow",red:"cyan",magenta:"green",white:"black"};pn.longest=(t,e)=>t.reduce((r,s)=>Math.max(r,e?s[e].length:s.length),0);pn.hasColor=t=>!!t&&jc.hasColor(t);var JR=pn.isObject=t=>t!==null&&typeof t=="object"&&!Array.isArray(t);pn.nativeType=t=>Bat.call(t).slice(8,-1).toLowerCase().replace(/\s/g,"");pn.isAsyncFn=t=>pn.nativeType(t)==="asyncfunction";pn.isPrimitive=t=>t!=null&&typeof t!="object"&&typeof t!="function";pn.resolve=(t,e,...r)=>typeof e=="function"?e.call(t,...r):e;pn.scrollDown=(t=[])=>[...t.slice(1),t[0]];pn.scrollUp=(t=[])=>[t.pop(),...t];pn.reorder=(t=[])=>{let e=t.slice();return e.sort((r,s)=>r.index>s.index?1:r.index{let s=t.length,a=r===s?0:r<0?s-1:r,n=t[e];t[e]=t[a],t[a]=n};pn.width=(t,e=80)=>{let r=t&&t.columns?t.columns:e;return t&&typeof t.getWindowSize=="function"&&(r=t.getWindowSize()[0]),process.platform==="win32"?r-1:r};pn.height=(t,e=20)=>{let r=t&&t.rows?t.rows:e;return t&&typeof t.getWindowSize=="function"&&(r=t.getWindowSize()[1]),r};pn.wordWrap=(t,e={})=>{if(!t)return t;typeof e=="number"&&(e={width:e});let{indent:r="",newline:s=` +`+r,width:a=80}=e,n=(s+r).match(/[^\S\n]/g)||[];a-=n.length;let c=`.{1,${a}}([\\s\\u200B]+|$)|[^\\s\\u200B]+?([\\s\\u200B]+|$)`,f=t.trim(),p=new RegExp(c,"g"),h=f.match(p)||[];return h=h.map(E=>E.replace(/\n$/,"")),e.padEnd&&(h=h.map(E=>E.padEnd(a," "))),e.padStart&&(h=h.map(E=>E.padStart(a," "))),r+h.join(s)};pn.unmute=t=>{let e=t.stack.find(s=>jc.keys.color.includes(s));return e?jc[e]:t.stack.find(s=>s.slice(2)==="bg")?jc[e.slice(2)]:s=>s};pn.pascal=t=>t?t[0].toUpperCase()+t.slice(1):"";pn.inverse=t=>{if(!t||!t.stack)return t;let e=t.stack.find(s=>jc.keys.color.includes(s));if(e){let s=jc["bg"+pn.pascal(e)];return s?s.black:t}let r=t.stack.find(s=>s.slice(0,2)==="bg");return r?jc[r.slice(2).toLowerCase()]||t:jc.none};pn.complement=t=>{if(!t||!t.stack)return t;let e=t.stack.find(s=>jc.keys.color.includes(s)),r=t.stack.find(s=>s.slice(0,2)==="bg");if(e&&!r)return jc[Fde[e]||e];if(r){let s=r.slice(2).toLowerCase(),a=Fde[s];return a&&jc["bg"+pn.pascal(a)]||t}return jc.none};pn.meridiem=t=>{let e=t.getHours(),r=t.getMinutes(),s=e>=12?"pm":"am";e=e%12;let a=e===0?12:e,n=r<10?"0"+r:r;return a+":"+n+" "+s};pn.set=(t={},e="",r)=>e.split(".").reduce((s,a,n,c)=>{let f=c.length-1>n?s[a]||{}:r;return!pn.isObject(f)&&n{let s=t[e]==null?e.split(".").reduce((a,n)=>a&&a[n],t):t[e];return s??r};pn.mixin=(t,e)=>{if(!JR(t))return e;if(!JR(e))return t;for(let r of Object.keys(e)){let s=Object.getOwnPropertyDescriptor(e,r);if(s.hasOwnProperty("value"))if(t.hasOwnProperty(r)&&JR(s.value)){let a=Object.getOwnPropertyDescriptor(t,r);JR(a.value)?t[r]=pn.merge({},t[r],e[r]):Reflect.defineProperty(t,r,s)}else Reflect.defineProperty(t,r,s);else Reflect.defineProperty(t,r,s)}return t};pn.merge=(...t)=>{let e={};for(let r of t)pn.mixin(e,r);return e};pn.mixinEmitter=(t,e)=>{let r=e.constructor.prototype;for(let s of Object.keys(r)){let a=r[s];typeof a=="function"?pn.define(t,s,a.bind(e)):pn.define(t,s,a)}};pn.onExit=t=>{let e=(r,s)=>{Rde||(Rde=!0,t5.forEach(a=>a()),r===!0&&process.exit(128+s))};t5.length===0&&(process.once("SIGTERM",e.bind(null,!0,15)),process.once("SIGINT",e.bind(null,!0,2)),process.once("exit",e)),t5.push(t)};pn.define=(t,e,r)=>{Reflect.defineProperty(t,e,{value:r})};pn.defineExport=(t,e,r)=>{let s;Reflect.defineProperty(t,e,{enumerable:!0,configurable:!0,set(a){s=a},get(){return s?s():r()}})}});var Nde=_(rC=>{"use strict";rC.ctrl={a:"first",b:"backward",c:"cancel",d:"deleteForward",e:"last",f:"forward",g:"reset",i:"tab",k:"cutForward",l:"reset",n:"newItem",m:"cancel",j:"submit",p:"search",r:"remove",s:"save",u:"undo",w:"cutLeft",x:"toggleCursor",v:"paste"};rC.shift={up:"shiftUp",down:"shiftDown",left:"shiftLeft",right:"shiftRight",tab:"prev"};rC.fn={up:"pageUp",down:"pageDown",left:"pageLeft",right:"pageRight",delete:"deleteForward"};rC.option={b:"backward",f:"forward",d:"cutRight",left:"cutLeft",up:"altUp",down:"altDown"};rC.keys={pageup:"pageUp",pagedown:"pageDown",home:"home",end:"end",cancel:"cancel",delete:"deleteForward",backspace:"delete",down:"down",enter:"submit",escape:"cancel",left:"left",space:"space",number:"number",return:"submit",right:"right",tab:"next",up:"up"}});var Mde=_((KHt,Lde)=>{"use strict";var Ode=Ie("readline"),vat=Nde(),Sat=/^(?:\x1b)([a-zA-Z0-9])$/,Dat=/^(?:\x1b+)(O|N|\[|\[\[)(?:(\d+)(?:;(\d+))?([~^$])|(?:1;)?(\d+)?([a-zA-Z]))/,bat={OP:"f1",OQ:"f2",OR:"f3",OS:"f4","[11~":"f1","[12~":"f2","[13~":"f3","[14~":"f4","[[A":"f1","[[B":"f2","[[C":"f3","[[D":"f4","[[E":"f5","[15~":"f5","[17~":"f6","[18~":"f7","[19~":"f8","[20~":"f9","[21~":"f10","[23~":"f11","[24~":"f12","[A":"up","[B":"down","[C":"right","[D":"left","[E":"clear","[F":"end","[H":"home",OA:"up",OB:"down",OC:"right",OD:"left",OE:"clear",OF:"end",OH:"home","[1~":"home","[2~":"insert","[3~":"delete","[4~":"end","[5~":"pageup","[6~":"pagedown","[[5~":"pageup","[[6~":"pagedown","[7~":"home","[8~":"end","[a":"up","[b":"down","[c":"right","[d":"left","[e":"clear","[2$":"insert","[3$":"delete","[5$":"pageup","[6$":"pagedown","[7$":"home","[8$":"end",Oa:"up",Ob:"down",Oc:"right",Od:"left",Oe:"clear","[2^":"insert","[3^":"delete","[5^":"pageup","[6^":"pagedown","[7^":"home","[8^":"end","[Z":"tab"};function Pat(t){return["[a","[b","[c","[d","[e","[2$","[3$","[5$","[6$","[7$","[8$","[Z"].includes(t)}function xat(t){return["Oa","Ob","Oc","Od","Oe","[2^","[3^","[5^","[6^","[7^","[8^"].includes(t)}var KR=(t="",e={})=>{let r,s={name:e.name,ctrl:!1,meta:!1,shift:!1,option:!1,sequence:t,raw:t,...e};if(Buffer.isBuffer(t)?t[0]>127&&t[1]===void 0?(t[0]-=128,t="\x1B"+String(t)):t=String(t):t!==void 0&&typeof t!="string"?t=String(t):t||(t=s.sequence||""),s.sequence=s.sequence||t||s.name,t==="\r")s.raw=void 0,s.name="return";else if(t===` +`)s.name="enter";else if(t===" ")s.name="tab";else if(t==="\b"||t==="\x7F"||t==="\x1B\x7F"||t==="\x1B\b")s.name="backspace",s.meta=t.charAt(0)==="\x1B";else if(t==="\x1B"||t==="\x1B\x1B")s.name="escape",s.meta=t.length===2;else if(t===" "||t==="\x1B ")s.name="space",s.meta=t.length===2;else if(t<="")s.name=String.fromCharCode(t.charCodeAt(0)+97-1),s.ctrl=!0;else if(t.length===1&&t>="0"&&t<="9")s.name="number";else if(t.length===1&&t>="a"&&t<="z")s.name=t;else if(t.length===1&&t>="A"&&t<="Z")s.name=t.toLowerCase(),s.shift=!0;else if(r=Sat.exec(t))s.meta=!0,s.shift=/^[A-Z]$/.test(r[1]);else if(r=Dat.exec(t)){let a=[...t];a[0]==="\x1B"&&a[1]==="\x1B"&&(s.option=!0);let n=[r[1],r[2],r[4],r[6]].filter(Boolean).join(""),c=(r[3]||r[5]||1)-1;s.ctrl=!!(c&4),s.meta=!!(c&10),s.shift=!!(c&1),s.code=n,s.name=bat[n],s.shift=Pat(n)||s.shift,s.ctrl=xat(n)||s.ctrl}return s};KR.listen=(t={},e)=>{let{stdin:r}=t;if(!r||r!==process.stdin&&!r.isTTY)throw new Error("Invalid stream passed");let s=Ode.createInterface({terminal:!0,input:r});Ode.emitKeypressEvents(r,s);let a=(f,p)=>e(f,KR(f,p),s),n=r.isRaw;return r.isTTY&&r.setRawMode(!0),r.on("keypress",a),s.resume(),()=>{r.isTTY&&r.setRawMode(n),r.removeListener("keypress",a),s.pause(),s.close()}};KR.action=(t,e,r)=>{let s={...vat,...r};return e.ctrl?(e.action=s.ctrl[e.name],e):e.option&&s.option?(e.action=s.option[e.name],e):e.shift?(e.action=s.shift[e.name],e):(e.action=s.keys[e.name],e)};Lde.exports=KR});var _de=_((zHt,Ude)=>{"use strict";Ude.exports=t=>{t.timers=t.timers||{};let e=t.options.timers;if(e)for(let r of Object.keys(e)){let s=e[r];typeof s=="number"&&(s={interval:s}),kat(t,r,s)}};function kat(t,e,r={}){let s=t.timers[e]={name:e,start:Date.now(),ms:0,tick:0},a=r.interval||120;s.frames=r.frames||[],s.loading=!0;let n=setInterval(()=>{s.ms=Date.now()-s.start,s.tick++,t.render()},a);return s.stop=()=>{s.loading=!1,clearInterval(n)},Reflect.defineProperty(s,"interval",{value:n}),t.once("close",()=>s.stop()),s.stop}});var jde=_((XHt,Hde)=>{"use strict";var{define:Qat,width:Tat}=Zo(),r5=class{constructor(e){let r=e.options;Qat(this,"_prompt",e),this.type=e.type,this.name=e.name,this.message="",this.header="",this.footer="",this.error="",this.hint="",this.input="",this.cursor=0,this.index=0,this.lines=0,this.tick=0,this.prompt="",this.buffer="",this.width=Tat(r.stdout||process.stdout),Object.assign(this,r),this.name=this.name||this.message,this.message=this.message||this.name,this.symbols=e.symbols,this.styles=e.styles,this.required=new Set,this.cancelled=!1,this.submitted=!1}clone(){let e={...this};return e.status=this.status,e.buffer=Buffer.from(e.buffer),delete e.clone,e}set color(e){this._color=e}get color(){let e=this.prompt.styles;if(this.cancelled)return e.cancelled;if(this.submitted)return e.submitted;let r=this._color||e[this.status];return typeof r=="function"?r:e.pending}set loading(e){this._loading=e}get loading(){return typeof this._loading=="boolean"?this._loading:this.loadingChoices?"choices":!1}get status(){return this.cancelled?"cancelled":this.submitted?"submitted":"pending"}};Hde.exports=r5});var qde=_((ZHt,Gde)=>{"use strict";var n5=Zo(),ho=Ju(),i5={default:ho.noop,noop:ho.noop,set inverse(t){this._inverse=t},get inverse(){return this._inverse||n5.inverse(this.primary)},set complement(t){this._complement=t},get complement(){return this._complement||n5.complement(this.primary)},primary:ho.cyan,success:ho.green,danger:ho.magenta,strong:ho.bold,warning:ho.yellow,muted:ho.dim,disabled:ho.gray,dark:ho.dim.gray,underline:ho.underline,set info(t){this._info=t},get info(){return this._info||this.primary},set em(t){this._em=t},get em(){return this._em||this.primary.underline},set heading(t){this._heading=t},get heading(){return this._heading||this.muted.underline},set pending(t){this._pending=t},get pending(){return this._pending||this.primary},set submitted(t){this._submitted=t},get submitted(){return this._submitted||this.success},set cancelled(t){this._cancelled=t},get cancelled(){return this._cancelled||this.danger},set typing(t){this._typing=t},get typing(){return this._typing||this.dim},set placeholder(t){this._placeholder=t},get placeholder(){return this._placeholder||this.primary.dim},set highlight(t){this._highlight=t},get highlight(){return this._highlight||this.inverse}};i5.merge=(t={})=>{t.styles&&typeof t.styles.enabled=="boolean"&&(ho.enabled=t.styles.enabled),t.styles&&typeof t.styles.visible=="boolean"&&(ho.visible=t.styles.visible);let e=n5.merge({},i5,t.styles);delete e.merge;for(let r of Object.keys(ho))e.hasOwnProperty(r)||Reflect.defineProperty(e,r,{get:()=>ho[r]});for(let r of Object.keys(ho.styles))e.hasOwnProperty(r)||Reflect.defineProperty(e,r,{get:()=>ho[r]});return e};Gde.exports=i5});var Yde=_(($Ht,Wde)=>{"use strict";var s5=process.platform==="win32",zp=Ju(),Rat=Zo(),o5={...zp.symbols,upDownDoubleArrow:"\u21D5",upDownDoubleArrow2:"\u2B0D",upDownArrow:"\u2195",asterisk:"*",asterism:"\u2042",bulletWhite:"\u25E6",electricArrow:"\u2301",ellipsisLarge:"\u22EF",ellipsisSmall:"\u2026",fullBlock:"\u2588",identicalTo:"\u2261",indicator:zp.symbols.check,leftAngle:"\u2039",mark:"\u203B",minus:"\u2212",multiplication:"\xD7",obelus:"\xF7",percent:"%",pilcrow:"\xB6",pilcrow2:"\u2761",pencilUpRight:"\u2710",pencilDownRight:"\u270E",pencilRight:"\u270F",plus:"+",plusMinus:"\xB1",pointRight:"\u261E",rightAngle:"\u203A",section:"\xA7",hexagon:{off:"\u2B21",on:"\u2B22",disabled:"\u2B22"},ballot:{on:"\u2611",off:"\u2610",disabled:"\u2612"},stars:{on:"\u2605",off:"\u2606",disabled:"\u2606"},folder:{on:"\u25BC",off:"\u25B6",disabled:"\u25B6"},prefix:{pending:zp.symbols.question,submitted:zp.symbols.check,cancelled:zp.symbols.cross},separator:{pending:zp.symbols.pointerSmall,submitted:zp.symbols.middot,cancelled:zp.symbols.middot},radio:{off:s5?"( )":"\u25EF",on:s5?"(*)":"\u25C9",disabled:s5?"(|)":"\u24BE"},numbers:["\u24EA","\u2460","\u2461","\u2462","\u2463","\u2464","\u2465","\u2466","\u2467","\u2468","\u2469","\u246A","\u246B","\u246C","\u246D","\u246E","\u246F","\u2470","\u2471","\u2472","\u2473","\u3251","\u3252","\u3253","\u3254","\u3255","\u3256","\u3257","\u3258","\u3259","\u325A","\u325B","\u325C","\u325D","\u325E","\u325F","\u32B1","\u32B2","\u32B3","\u32B4","\u32B5","\u32B6","\u32B7","\u32B8","\u32B9","\u32BA","\u32BB","\u32BC","\u32BD","\u32BE","\u32BF"]};o5.merge=t=>{let e=Rat.merge({},zp.symbols,o5,t.symbols);return delete e.merge,e};Wde.exports=o5});var Jde=_((ejt,Vde)=>{"use strict";var Fat=qde(),Nat=Yde(),Oat=Zo();Vde.exports=t=>{t.options=Oat.merge({},t.options.theme,t.options),t.symbols=Nat.merge(t.options),t.styles=Fat.merge(t.options)}});var $de=_((Xde,Zde)=>{"use strict";var Kde=process.env.TERM_PROGRAM==="Apple_Terminal",Lat=Ju(),a5=Zo(),Ku=Zde.exports=Xde,_i="\x1B[",zde="\x07",l5=!1,j0=Ku.code={bell:zde,beep:zde,beginning:`${_i}G`,down:`${_i}J`,esc:_i,getPosition:`${_i}6n`,hide:`${_i}?25l`,line:`${_i}2K`,lineEnd:`${_i}K`,lineStart:`${_i}1K`,restorePosition:_i+(Kde?"8":"u"),savePosition:_i+(Kde?"7":"s"),screen:`${_i}2J`,show:`${_i}?25h`,up:`${_i}1J`},wm=Ku.cursor={get hidden(){return l5},hide(){return l5=!0,j0.hide},show(){return l5=!1,j0.show},forward:(t=1)=>`${_i}${t}C`,backward:(t=1)=>`${_i}${t}D`,nextLine:(t=1)=>`${_i}E`.repeat(t),prevLine:(t=1)=>`${_i}F`.repeat(t),up:(t=1)=>t?`${_i}${t}A`:"",down:(t=1)=>t?`${_i}${t}B`:"",right:(t=1)=>t?`${_i}${t}C`:"",left:(t=1)=>t?`${_i}${t}D`:"",to(t,e){return e?`${_i}${e+1};${t+1}H`:`${_i}${t+1}G`},move(t=0,e=0){let r="";return r+=t<0?wm.left(-t):t>0?wm.right(t):"",r+=e<0?wm.up(-e):e>0?wm.down(e):"",r},restore(t={}){let{after:e,cursor:r,initial:s,input:a,prompt:n,size:c,value:f}=t;if(s=a5.isPrimitive(s)?String(s):"",a=a5.isPrimitive(a)?String(a):"",f=a5.isPrimitive(f)?String(f):"",c){let p=Ku.cursor.up(c)+Ku.cursor.to(n.length),h=a.length-r;return h>0&&(p+=Ku.cursor.left(h)),p}if(f||e){let p=!a&&s?-s.length:-a.length+r;return e&&(p-=e.length),a===""&&s&&!n.includes(s)&&(p+=s.length),Ku.cursor.move(p)}}},c5=Ku.erase={screen:j0.screen,up:j0.up,down:j0.down,line:j0.line,lineEnd:j0.lineEnd,lineStart:j0.lineStart,lines(t){let e="";for(let r=0;r{if(!e)return c5.line+wm.to(0);let r=n=>[...Lat.unstyle(n)].length,s=t.split(/\r?\n/),a=0;for(let n of s)a+=1+Math.floor(Math.max(r(n)-1,0)/e);return(c5.line+wm.prevLine()).repeat(a-1)+c5.line+wm.to(0)}});var nC=_((tjt,tme)=>{"use strict";var Mat=Ie("events"),eme=Ju(),u5=Mde(),Uat=_de(),_at=jde(),Hat=Jde(),pl=Zo(),Bm=$de(),f5=class t extends Mat{constructor(e={}){super(),this.name=e.name,this.type=e.type,this.options=e,Hat(this),Uat(this),this.state=new _at(this),this.initial=[e.initial,e.default].find(r=>r!=null),this.stdout=e.stdout||process.stdout,this.stdin=e.stdin||process.stdin,this.scale=e.scale||1,this.term=this.options.term||process.env.TERM_PROGRAM,this.margin=Gat(this.options.margin),this.setMaxListeners(0),jat(this)}async keypress(e,r={}){this.keypressed=!0;let s=u5.action(e,u5(e,r),this.options.actions);this.state.keypress=s,this.emit("keypress",e,s),this.emit("state",this.state.clone());let a=this.options[s.action]||this[s.action]||this.dispatch;if(typeof a=="function")return await a.call(this,e,s);this.alert()}alert(){delete this.state.alert,this.options.show===!1?this.emit("alert"):this.stdout.write(Bm.code.beep)}cursorHide(){this.stdout.write(Bm.cursor.hide()),pl.onExit(()=>this.cursorShow())}cursorShow(){this.stdout.write(Bm.cursor.show())}write(e){e&&(this.stdout&&this.state.show!==!1&&this.stdout.write(e),this.state.buffer+=e)}clear(e=0){let r=this.state.buffer;this.state.buffer="",!(!r&&!e||this.options.show===!1)&&this.stdout.write(Bm.cursor.down(e)+Bm.clear(r,this.width))}restore(){if(this.state.closed||this.options.show===!1)return;let{prompt:e,after:r,rest:s}=this.sections(),{cursor:a,initial:n="",input:c="",value:f=""}=this,p=this.state.size=s.length,h={after:r,cursor:a,initial:n,input:c,prompt:e,size:p,value:f},E=Bm.cursor.restore(h);E&&this.stdout.write(E)}sections(){let{buffer:e,input:r,prompt:s}=this.state;s=eme.unstyle(s);let a=eme.unstyle(e),n=a.indexOf(s),c=a.slice(0,n),p=a.slice(n).split(` +`),h=p[0],E=p[p.length-1],S=(s+(r?" "+r:"")).length,P=Se.call(this,this.value),this.result=()=>s.call(this,this.value),typeof r.initial=="function"&&(this.initial=await r.initial.call(this,this)),typeof r.onRun=="function"&&await r.onRun.call(this,this),typeof r.onSubmit=="function"){let a=r.onSubmit.bind(this),n=this.submit.bind(this);delete this.options.onSubmit,this.submit=async()=>(await a(this.name,this.value,this),n())}await this.start(),await this.render()}render(){throw new Error("expected prompt to have a custom render method")}run(){return new Promise(async(e,r)=>{if(this.once("submit",e),this.once("cancel",r),await this.skip())return this.render=()=>{},this.submit();await this.initialize(),this.emit("run")})}async element(e,r,s){let{options:a,state:n,symbols:c,timers:f}=this,p=f&&f[e];n.timer=p;let h=a[e]||n[e]||c[e],E=r&&r[e]!=null?r[e]:await h;if(E==="")return E;let C=await this.resolve(E,n,r,s);return!C&&r&&r[e]?this.resolve(h,n,r,s):C}async prefix(){let e=await this.element("prefix")||this.symbols,r=this.timers&&this.timers.prefix,s=this.state;return s.timer=r,pl.isObject(e)&&(e=e[s.status]||e.pending),pl.hasColor(e)?e:(this.styles[s.status]||this.styles.pending)(e)}async message(){let e=await this.element("message");return pl.hasColor(e)?e:this.styles.strong(e)}async separator(){let e=await this.element("separator")||this.symbols,r=this.timers&&this.timers.separator,s=this.state;s.timer=r;let a=e[s.status]||e.pending||s.separator,n=await this.resolve(a,s);return pl.isObject(n)&&(n=n[s.status]||n.pending),pl.hasColor(n)?n:this.styles.muted(n)}async pointer(e,r){let s=await this.element("pointer",e,r);if(typeof s=="string"&&pl.hasColor(s))return s;if(s){let a=this.styles,n=this.index===r,c=n?a.primary:h=>h,f=await this.resolve(s[n?"on":"off"]||s,this.state),p=pl.hasColor(f)?f:c(f);return n?p:" ".repeat(f.length)}}async indicator(e,r){let s=await this.element("indicator",e,r);if(typeof s=="string"&&pl.hasColor(s))return s;if(s){let a=this.styles,n=e.enabled===!0,c=n?a.success:a.dark,f=s[n?"on":"off"]||s;return pl.hasColor(f)?f:c(f)}return""}body(){return null}footer(){if(this.state.status==="pending")return this.element("footer")}header(){if(this.state.status==="pending")return this.element("header")}async hint(){if(this.state.status==="pending"&&!this.isValue(this.state.input)){let e=await this.element("hint");return pl.hasColor(e)?e:this.styles.muted(e)}}error(e){return this.state.submitted?"":e||this.state.error}format(e){return e}result(e){return e}validate(e){return this.options.required===!0?this.isValue(e):!0}isValue(e){return e!=null&&e!==""}resolve(e,...r){return pl.resolve(this,e,...r)}get base(){return t.prototype}get style(){return this.styles[this.state.status]}get height(){return this.options.rows||pl.height(this.stdout,25)}get width(){return this.options.columns||pl.width(this.stdout,80)}get size(){return{width:this.width,height:this.height}}set cursor(e){this.state.cursor=e}get cursor(){return this.state.cursor}set input(e){this.state.input=e}get input(){return this.state.input}set value(e){this.state.value=e}get value(){let{input:e,value:r}=this.state,s=[r,e].find(this.isValue.bind(this));return this.isValue(s)?s:this.initial}static get prompt(){return e=>new this(e).run()}};function jat(t){let e=a=>t[a]===void 0||typeof t[a]=="function",r=["actions","choices","initial","margin","roles","styles","symbols","theme","timers","value"],s=["body","footer","error","header","hint","indicator","message","prefix","separator","skip"];for(let a of Object.keys(t.options)){if(r.includes(a)||/^on[A-Z]/.test(a))continue;let n=t.options[a];typeof n=="function"&&e(a)?s.includes(a)||(t[a]=n.bind(t)):typeof t[a]!="function"&&(t[a]=n)}}function Gat(t){typeof t=="number"&&(t=[t,t,t,t]);let e=[].concat(t||[]),r=a=>a%2===0?` +`:" ",s=[];for(let a=0;a<4;a++){let n=r(a);e[a]?s.push(n.repeat(e[a])):s.push("")}return s}tme.exports=f5});var ime=_((rjt,nme)=>{"use strict";var qat=Zo(),rme={default(t,e){return e},checkbox(t,e){throw new Error("checkbox role is not implemented yet")},editable(t,e){throw new Error("editable role is not implemented yet")},expandable(t,e){throw new Error("expandable role is not implemented yet")},heading(t,e){return e.disabled="",e.indicator=[e.indicator," "].find(r=>r!=null),e.message=e.message||"",e},input(t,e){throw new Error("input role is not implemented yet")},option(t,e){return rme.default(t,e)},radio(t,e){throw new Error("radio role is not implemented yet")},separator(t,e){return e.disabled="",e.indicator=[e.indicator," "].find(r=>r!=null),e.message=e.message||t.symbols.line.repeat(5),e},spacer(t,e){return e}};nme.exports=(t,e={})=>{let r=qat.merge({},rme,e.roles);return r[t]||r.default}});var Wv=_((njt,ame)=>{"use strict";var Wat=Ju(),Yat=nC(),Vat=ime(),zR=Zo(),{reorder:A5,scrollUp:Jat,scrollDown:Kat,isObject:sme,swap:zat}=zR,p5=class extends Yat{constructor(e){super(e),this.cursorHide(),this.maxSelected=e.maxSelected||1/0,this.multiple=e.multiple||!1,this.initial=e.initial||0,this.delay=e.delay||0,this.longest=0,this.num=""}async initialize(){typeof this.options.initial=="function"&&(this.initial=await this.options.initial.call(this)),await this.reset(!0),await super.initialize()}async reset(){let{choices:e,initial:r,autofocus:s,suggest:a}=this.options;if(this.state._choices=[],this.state.choices=[],this.choices=await Promise.all(await this.toChoices(e)),this.choices.forEach(n=>n.enabled=!1),typeof a!="function"&&this.selectable.length===0)throw new Error("At least one choice must be selectable");sme(r)&&(r=Object.keys(r)),Array.isArray(r)?(s!=null&&(this.index=this.findIndex(s)),r.forEach(n=>this.enable(this.find(n))),await this.render()):(s!=null&&(r=s),typeof r=="string"&&(r=this.findIndex(r)),typeof r=="number"&&r>-1&&(this.index=Math.max(0,Math.min(r,this.choices.length)),this.enable(this.find(this.index)))),this.isDisabled(this.focused)&&await this.down()}async toChoices(e,r){this.state.loadingChoices=!0;let s=[],a=0,n=async(c,f)=>{typeof c=="function"&&(c=await c.call(this)),c instanceof Promise&&(c=await c);for(let p=0;p(this.state.loadingChoices=!1,c))}async toChoice(e,r,s){if(typeof e=="function"&&(e=await e.call(this,this)),e instanceof Promise&&(e=await e),typeof e=="string"&&(e={name:e}),e.normalized)return e;e.normalized=!0;let a=e.value;if(e=Vat(e.role,this.options)(this,e),typeof e.disabled=="string"&&!e.hint&&(e.hint=e.disabled,e.disabled=!0),e.disabled===!0&&e.hint==null&&(e.hint="(disabled)"),e.index!=null)return e;e.name=e.name||e.key||e.title||e.value||e.message,e.message=e.message||e.name||"",e.value=[e.value,e.name].find(this.isValue.bind(this)),e.input="",e.index=r,e.cursor=0,zR.define(e,"parent",s),e.level=s?s.level+1:1,e.indent==null&&(e.indent=s?s.indent+" ":e.indent||""),e.path=s?s.path+"."+e.name:e.name,e.enabled=!!(this.multiple&&!this.isDisabled(e)&&(e.enabled||this.isSelected(e))),this.isDisabled(e)||(this.longest=Math.max(this.longest,Wat.unstyle(e.message).length));let c={...e};return e.reset=(f=c.input,p=c.value)=>{for(let h of Object.keys(c))e[h]=c[h];e.input=f,e.value=p},a==null&&typeof e.initial=="function"&&(e.input=await e.initial.call(this,this.state,e,r)),e}async onChoice(e,r){this.emit("choice",e,r,this),typeof e.onChoice=="function"&&await e.onChoice.call(this,this.state,e,r)}async addChoice(e,r,s){let a=await this.toChoice(e,r,s);return this.choices.push(a),this.index=this.choices.length-1,this.limit=this.choices.length,a}async newItem(e,r,s){let a={name:"New choice name?",editable:!0,newChoice:!0,...e},n=await this.addChoice(a,r,s);return n.updateChoice=()=>{delete n.newChoice,n.name=n.message=n.input,n.input="",n.cursor=0},this.render()}indent(e){return e.indent==null?e.level>1?" ".repeat(e.level-1):"":e.indent}dispatch(e,r){if(this.multiple&&this[r.name])return this[r.name]();this.alert()}focus(e,r){return typeof r!="boolean"&&(r=e.enabled),r&&!e.enabled&&this.selected.length>=this.maxSelected?this.alert():(this.index=e.index,e.enabled=r&&!this.isDisabled(e),e)}space(){return this.multiple?(this.toggle(this.focused),this.render()):this.alert()}a(){if(this.maxSelectedr.enabled);return this.choices.forEach(r=>r.enabled=!e),this.render()}i(){return this.choices.length-this.selected.length>this.maxSelected?this.alert():(this.choices.forEach(e=>e.enabled=!e.enabled),this.render())}g(e=this.focused){return this.choices.some(r=>!!r.parent)?(this.toggle(e.parent&&!e.choices?e.parent:e),this.render()):this.a()}toggle(e,r){if(!e.enabled&&this.selected.length>=this.maxSelected)return this.alert();typeof r!="boolean"&&(r=!e.enabled),e.enabled=r,e.choices&&e.choices.forEach(a=>this.toggle(a,r));let s=e.parent;for(;s;){let a=s.choices.filter(n=>this.isDisabled(n));s.enabled=a.every(n=>n.enabled===!0),s=s.parent}return ome(this,this.choices),this.emit("toggle",e,this),e}enable(e){return this.selected.length>=this.maxSelected?this.alert():(e.enabled=!this.isDisabled(e),e.choices&&e.choices.forEach(this.enable.bind(this)),e)}disable(e){return e.enabled=!1,e.choices&&e.choices.forEach(this.disable.bind(this)),e}number(e){this.num+=e;let r=s=>{let a=Number(s);if(a>this.choices.length-1)return this.alert();let n=this.focused,c=this.choices.find(f=>a===f.index);if(!c.enabled&&this.selected.length>=this.maxSelected)return this.alert();if(this.visible.indexOf(c)===-1){let f=A5(this.choices),p=f.indexOf(c);if(n.index>p){let h=f.slice(p,p+this.limit),E=f.filter(C=>!h.includes(C));this.choices=h.concat(E)}else{let h=p-this.limit+1;this.choices=f.slice(h).concat(f.slice(0,h))}}return this.index=this.choices.indexOf(c),this.toggle(this.focused),this.render()};return clearTimeout(this.numberTimeout),new Promise(s=>{let a=this.choices.length,n=this.num,c=(f=!1,p)=>{clearTimeout(this.numberTimeout),f&&(p=r(n)),this.num="",s(p)};if(n==="0"||n.length===1&&+(n+"0")>a)return c(!0);if(Number(n)>a)return c(!1,this.alert());this.numberTimeout=setTimeout(()=>c(!0),this.delay)})}home(){return this.choices=A5(this.choices),this.index=0,this.render()}end(){let e=this.choices.length-this.limit,r=A5(this.choices);return this.choices=r.slice(e).concat(r.slice(0,e)),this.index=this.limit-1,this.render()}first(){return this.index=0,this.render()}last(){return this.index=this.visible.length-1,this.render()}prev(){return this.visible.length<=1?this.alert():this.up()}next(){return this.visible.length<=1?this.alert():this.down()}right(){return this.cursor>=this.input.length?this.alert():(this.cursor++,this.render())}left(){return this.cursor<=0?this.alert():(this.cursor--,this.render())}up(){let e=this.choices.length,r=this.visible.length,s=this.index;return this.options.scroll===!1&&s===0?this.alert():e>r&&s===0?this.scrollUp():(this.index=(s-1%e+e)%e,this.isDisabled()?this.up():this.render())}down(){let e=this.choices.length,r=this.visible.length,s=this.index;return this.options.scroll===!1&&s===r-1?this.alert():e>r&&s===r-1?this.scrollDown():(this.index=(s+1)%e,this.isDisabled()?this.down():this.render())}scrollUp(e=0){return this.choices=Jat(this.choices),this.index=e,this.isDisabled()?this.up():this.render()}scrollDown(e=this.visible.length-1){return this.choices=Kat(this.choices),this.index=e,this.isDisabled()?this.down():this.render()}async shiftUp(){if(this.options.sort===!0){this.sorting=!0,this.swap(this.index-1),await this.up(),this.sorting=!1;return}return this.scrollUp(this.index)}async shiftDown(){if(this.options.sort===!0){this.sorting=!0,this.swap(this.index+1),await this.down(),this.sorting=!1;return}return this.scrollDown(this.index)}pageUp(){return this.visible.length<=1?this.alert():(this.limit=Math.max(this.limit-1,0),this.index=Math.min(this.limit-1,this.index),this._limit=this.limit,this.isDisabled()?this.up():this.render())}pageDown(){return this.visible.length>=this.choices.length?this.alert():(this.index=Math.max(0,this.index),this.limit=Math.min(this.limit+1,this.choices.length),this._limit=this.limit,this.isDisabled()?this.down():this.render())}swap(e){zat(this.choices,this.index,e)}isDisabled(e=this.focused){return e&&["disabled","collapsed","hidden","completing","readonly"].some(s=>e[s]===!0)?!0:e&&e.role==="heading"}isEnabled(e=this.focused){if(Array.isArray(e))return e.every(r=>this.isEnabled(r));if(e.choices){let r=e.choices.filter(s=>!this.isDisabled(s));return e.enabled&&r.every(s=>this.isEnabled(s))}return e.enabled&&!this.isDisabled(e)}isChoice(e,r){return e.name===r||e.index===Number(r)}isSelected(e){return Array.isArray(this.initial)?this.initial.some(r=>this.isChoice(e,r)):this.isChoice(e,this.initial)}map(e=[],r="value"){return[].concat(e||[]).reduce((s,a)=>(s[a]=this.find(a,r),s),{})}filter(e,r){let a=typeof e=="function"?e:(f,p)=>[f.name,p].includes(e),c=(this.options.multiple?this.state._choices:this.choices).filter(a);return r?c.map(f=>f[r]):c}find(e,r){if(sme(e))return r?e[r]:e;let a=typeof e=="function"?e:(c,f)=>[c.name,f].includes(e),n=this.choices.find(a);if(n)return r?n[r]:n}findIndex(e){return this.choices.indexOf(this.find(e))}async submit(){let e=this.focused;if(!e)return this.alert();if(e.newChoice)return e.input?(e.updateChoice(),this.render()):this.alert();if(this.choices.some(c=>c.newChoice))return this.alert();let{reorder:r,sort:s}=this.options,a=this.multiple===!0,n=this.selected;return n===void 0?this.alert():(Array.isArray(n)&&r!==!1&&s!==!0&&(n=zR.reorder(n)),this.value=a?n.map(c=>c.name):n.name,super.submit())}set choices(e=[]){this.state._choices=this.state._choices||[],this.state.choices=e;for(let r of e)this.state._choices.some(s=>s.name===r.name)||this.state._choices.push(r);if(!this._initial&&this.options.initial){this._initial=!0;let r=this.initial;if(typeof r=="string"||typeof r=="number"){let s=this.find(r);s&&(this.initial=s.index,this.focus(s,!0))}}}get choices(){return ome(this,this.state.choices||[])}set visible(e){this.state.visible=e}get visible(){return(this.state.visible||this.choices).slice(0,this.limit)}set limit(e){this.state.limit=e}get limit(){let{state:e,options:r,choices:s}=this,a=e.limit||this._limit||r.limit||s.length;return Math.min(a,this.height)}set value(e){super.value=e}get value(){return typeof super.value!="string"&&super.value===this.initial?this.input:super.value}set index(e){this.state.index=e}get index(){return Math.max(0,this.state?this.state.index:0)}get enabled(){return this.filter(this.isEnabled.bind(this))}get focused(){let e=this.choices[this.index];return e&&this.state.submitted&&this.multiple!==!0&&(e.enabled=!0),e}get selectable(){return this.choices.filter(e=>!this.isDisabled(e))}get selected(){return this.multiple?this.enabled:this.focused}};function ome(t,e){if(e instanceof Promise)return e;if(typeof e=="function"){if(zR.isAsyncFn(e))return e;e=e.call(t,t)}for(let r of e){if(Array.isArray(r.choices)){let s=r.choices.filter(a=>!t.isDisabled(a));r.enabled=s.every(a=>a.enabled===!0)}t.isDisabled(r)===!0&&delete r.enabled}return e}ame.exports=p5});var G0=_((ijt,lme)=>{"use strict";var Xat=Wv(),h5=Zo(),g5=class extends Xat{constructor(e){super(e),this.emptyError=this.options.emptyError||"No items were selected"}async dispatch(e,r){if(this.multiple)return this[r.name]?await this[r.name](e,r):await super.dispatch(e,r);this.alert()}separator(){if(this.options.separator)return super.separator();let e=this.styles.muted(this.symbols.ellipsis);return this.state.submitted?super.separator():e}pointer(e,r){return!this.multiple||this.options.pointer?super.pointer(e,r):""}indicator(e,r){return this.multiple?super.indicator(e,r):""}choiceMessage(e,r){let s=this.resolve(e.message,this.state,e,r);return e.role==="heading"&&!h5.hasColor(s)&&(s=this.styles.strong(s)),this.resolve(s,this.state,e,r)}choiceSeparator(){return":"}async renderChoice(e,r){await this.onChoice(e,r);let s=this.index===r,a=await this.pointer(e,r),n=await this.indicator(e,r)+(e.pad||""),c=await this.resolve(e.hint,this.state,e,r);c&&!h5.hasColor(c)&&(c=this.styles.muted(c));let f=this.indent(e),p=await this.choiceMessage(e,r),h=()=>[this.margin[3],f+a+n,p,this.margin[1],c].filter(Boolean).join(" ");return e.role==="heading"?h():e.disabled?(h5.hasColor(p)||(p=this.styles.disabled(p)),h()):(s&&(p=this.styles.em(p)),h())}async renderChoices(){if(this.state.loading==="choices")return this.styles.warning("Loading choices");if(this.state.submitted)return"";let e=this.visible.map(async(n,c)=>await this.renderChoice(n,c)),r=await Promise.all(e);r.length||r.push(this.styles.danger("No matching choices"));let s=this.margin[0]+r.join(` +`),a;return this.options.choicesHeader&&(a=await this.resolve(this.options.choicesHeader,this.state)),[a,s].filter(Boolean).join(` +`)}format(){return!this.state.submitted||this.state.cancelled?"":Array.isArray(this.selected)?this.selected.map(e=>this.styles.primary(e.name)).join(", "):this.styles.primary(this.selected.name)}async render(){let{submitted:e,size:r}=this.state,s="",a=await this.header(),n=await this.prefix(),c=await this.separator(),f=await this.message();this.options.promptLine!==!1&&(s=[n,f,c,""].join(" "),this.state.prompt=s);let p=await this.format(),h=await this.error()||await this.hint(),E=await this.renderChoices(),C=await this.footer();p&&(s+=p),h&&!s.includes(h)&&(s+=" "+h),e&&!p&&!E.trim()&&this.multiple&&this.emptyError!=null&&(s+=this.styles.danger(this.emptyError)),this.clear(r),this.write([a,s,E,C].filter(Boolean).join(` +`)),this.write(this.margin[2]),this.restore()}};lme.exports=g5});var ume=_((sjt,cme)=>{"use strict";var Zat=G0(),$at=(t,e)=>{let r=t.toLowerCase();return s=>{let n=s.toLowerCase().indexOf(r),c=e(s.slice(n,n+r.length));return n>=0?s.slice(0,n)+c+s.slice(n+r.length):s}},d5=class extends Zat{constructor(e){super(e),this.cursorShow()}moveCursor(e){this.state.cursor+=e}dispatch(e){return this.append(e)}space(e){return this.options.multiple?super.space(e):this.append(e)}append(e){let{cursor:r,input:s}=this.state;return this.input=s.slice(0,r)+e+s.slice(r),this.moveCursor(1),this.complete()}delete(){let{cursor:e,input:r}=this.state;return r?(this.input=r.slice(0,e-1)+r.slice(e),this.moveCursor(-1),this.complete()):this.alert()}deleteForward(){let{cursor:e,input:r}=this.state;return r[e]===void 0?this.alert():(this.input=`${r}`.slice(0,e)+`${r}`.slice(e+1),this.complete())}number(e){return this.append(e)}async complete(){this.completing=!0,this.choices=await this.suggest(this.input,this.state._choices),this.state.limit=void 0,this.index=Math.min(Math.max(this.visible.length-1,0),this.index),await this.render(),this.completing=!1}suggest(e=this.input,r=this.state._choices){if(typeof this.options.suggest=="function")return this.options.suggest.call(this,e,r);let s=e.toLowerCase();return r.filter(a=>a.message.toLowerCase().includes(s))}pointer(){return""}format(){if(!this.focused)return this.input;if(this.options.multiple&&this.state.submitted)return this.selected.map(e=>this.styles.primary(e.message)).join(", ");if(this.state.submitted){let e=this.value=this.input=this.focused.value;return this.styles.primary(e)}return this.input}async render(){if(this.state.status!=="pending")return super.render();let e=this.options.highlight?this.options.highlight.bind(this):this.styles.placeholder,r=$at(this.input,e),s=this.choices;this.choices=s.map(a=>({...a,message:r(a.message)})),await super.render(),this.choices=s}submit(){return this.options.multiple&&(this.value=this.selected.map(e=>e.name)),super.submit()}};cme.exports=d5});var y5=_((ojt,fme)=>{"use strict";var m5=Zo();fme.exports=(t,e={})=>{t.cursorHide();let{input:r="",initial:s="",pos:a,showCursor:n=!0,color:c}=e,f=c||t.styles.placeholder,p=m5.inverse(t.styles.primary),h=R=>p(t.styles.black(R)),E=r,C=" ",S=h(C);if(t.blink&&t.blink.off===!0&&(h=R=>R,S=""),n&&a===0&&s===""&&r==="")return h(C);if(n&&a===0&&(r===s||r===""))return h(s[0])+f(s.slice(1));s=m5.isPrimitive(s)?`${s}`:"",r=m5.isPrimitive(r)?`${r}`:"";let P=s&&s.startsWith(r)&&s!==r,I=P?h(s[r.length]):S;if(a!==r.length&&n===!0&&(E=r.slice(0,a)+h(r[a])+r.slice(a+1),I=""),n===!1&&(I=""),P){let R=t.styles.unstyle(E+I);return E+I+f(s.slice(R.length))}return E+I}});var XR=_((ajt,Ame)=>{"use strict";var elt=Ju(),tlt=G0(),rlt=y5(),E5=class extends tlt{constructor(e){super({...e,multiple:!0}),this.type="form",this.initial=this.options.initial,this.align=[this.options.align,"right"].find(r=>r!=null),this.emptyError="",this.values={}}async reset(e){return await super.reset(),e===!0&&(this._index=this.index),this.index=this._index,this.values={},this.choices.forEach(r=>r.reset&&r.reset()),this.render()}dispatch(e){return!!e&&this.append(e)}append(e){let r=this.focused;if(!r)return this.alert();let{cursor:s,input:a}=r;return r.value=r.input=a.slice(0,s)+e+a.slice(s),r.cursor++,this.render()}delete(){let e=this.focused;if(!e||e.cursor<=0)return this.alert();let{cursor:r,input:s}=e;return e.value=e.input=s.slice(0,r-1)+s.slice(r),e.cursor--,this.render()}deleteForward(){let e=this.focused;if(!e)return this.alert();let{cursor:r,input:s}=e;if(s[r]===void 0)return this.alert();let a=`${s}`.slice(0,r)+`${s}`.slice(r+1);return e.value=e.input=a,this.render()}right(){let e=this.focused;return e?e.cursor>=e.input.length?this.alert():(e.cursor++,this.render()):this.alert()}left(){let e=this.focused;return e?e.cursor<=0?this.alert():(e.cursor--,this.render()):this.alert()}space(e,r){return this.dispatch(e,r)}number(e,r){return this.dispatch(e,r)}next(){let e=this.focused;if(!e)return this.alert();let{initial:r,input:s}=e;return r&&r.startsWith(s)&&s!==r?(e.value=e.input=r,e.cursor=e.value.length,this.render()):super.next()}prev(){let e=this.focused;return e?e.cursor===0?super.prev():(e.value=e.input="",e.cursor=0,this.render()):this.alert()}separator(){return""}format(e){return this.state.submitted?"":super.format(e)}pointer(){return""}indicator(e){return e.input?"\u29BF":"\u2299"}async choiceSeparator(e,r){let s=await this.resolve(e.separator,this.state,e,r)||":";return s?" "+this.styles.disabled(s):""}async renderChoice(e,r){await this.onChoice(e,r);let{state:s,styles:a}=this,{cursor:n,initial:c="",name:f,hint:p,input:h=""}=e,{muted:E,submitted:C,primary:S,danger:P}=a,I=p,R=this.index===r,N=e.validate||(()=>!0),U=await this.choiceSeparator(e,r),W=e.message;this.align==="right"&&(W=W.padStart(this.longest+1," ")),this.align==="left"&&(W=W.padEnd(this.longest+1," "));let ee=this.values[f]=h||c,ie=h?"success":"dark";await N.call(e,ee,this.state)!==!0&&(ie="danger");let ue=a[ie],le=ue(await this.indicator(e,r))+(e.pad||""),me=this.indent(e),pe=()=>[me,le,W+U,h,I].filter(Boolean).join(" ");if(s.submitted)return W=elt.unstyle(W),h=C(h),I="",pe();if(e.format)h=await e.format.call(this,h,e,r);else{let Be=this.styles.muted;h=rlt(this,{input:h,initial:c,pos:n,showCursor:R,color:Be})}return this.isValue(h)||(h=this.styles.muted(this.symbols.ellipsis)),e.result&&(this.values[f]=await e.result.call(this,ee,e,r)),R&&(W=S(W)),e.error?h+=(h?" ":"")+P(e.error.trim()):e.hint&&(h+=(h?" ":"")+E(e.hint.trim())),pe()}async submit(){return this.value=this.values,super.base.submit.call(this)}};Ame.exports=E5});var I5=_((ljt,hme)=>{"use strict";var nlt=XR(),ilt=()=>{throw new Error("expected prompt to have a custom authenticate method")},pme=(t=ilt)=>{class e extends nlt{constructor(s){super(s)}async submit(){this.value=await t.call(this,this.values,this.state),super.base.submit.call(this)}static create(s){return pme(s)}}return e};hme.exports=pme()});var mme=_((cjt,dme)=>{"use strict";var slt=I5();function olt(t,e){return t.username===this.options.username&&t.password===this.options.password}var gme=(t=olt)=>{let e=[{name:"username",message:"username"},{name:"password",message:"password",format(s){return this.options.showPassword?s:(this.state.submitted?this.styles.primary:this.styles.muted)(this.symbols.asterisk.repeat(s.length))}}];class r extends slt.create(t){constructor(a){super({...a,choices:e})}static create(a){return gme(a)}}return r};dme.exports=gme()});var ZR=_((ujt,yme)=>{"use strict";var alt=nC(),{isPrimitive:llt,hasColor:clt}=Zo(),C5=class extends alt{constructor(e){super(e),this.cursorHide()}async initialize(){let e=await this.resolve(this.initial,this.state);this.input=await this.cast(e),await super.initialize()}dispatch(e){return this.isValue(e)?(this.input=e,this.submit()):this.alert()}format(e){let{styles:r,state:s}=this;return s.submitted?r.success(e):r.primary(e)}cast(e){return this.isTrue(e)}isTrue(e){return/^[ty1]/i.test(e)}isFalse(e){return/^[fn0]/i.test(e)}isValue(e){return llt(e)&&(this.isTrue(e)||this.isFalse(e))}async hint(){if(this.state.status==="pending"){let e=await this.element("hint");return clt(e)?e:this.styles.muted(e)}}async render(){let{input:e,size:r}=this.state,s=await this.prefix(),a=await this.separator(),n=await this.message(),c=this.styles.muted(this.default),f=[s,n,c,a].filter(Boolean).join(" ");this.state.prompt=f;let p=await this.header(),h=this.value=this.cast(e),E=await this.format(h),C=await this.error()||await this.hint(),S=await this.footer();C&&!f.includes(C)&&(E+=" "+C),f+=" "+E,this.clear(r),this.write([p,f,S].filter(Boolean).join(` +`)),this.restore()}set value(e){super.value=e}get value(){return this.cast(super.value)}};yme.exports=C5});var Ime=_((fjt,Eme)=>{"use strict";var ult=ZR(),w5=class extends ult{constructor(e){super(e),this.default=this.options.default||(this.initial?"(Y/n)":"(y/N)")}};Eme.exports=w5});var wme=_((Ajt,Cme)=>{"use strict";var flt=G0(),Alt=XR(),iC=Alt.prototype,B5=class extends flt{constructor(e){super({...e,multiple:!0}),this.align=[this.options.align,"left"].find(r=>r!=null),this.emptyError="",this.values={}}dispatch(e,r){let s=this.focused,a=s.parent||{};return!s.editable&&!a.editable&&(e==="a"||e==="i")?super[e]():iC.dispatch.call(this,e,r)}append(e,r){return iC.append.call(this,e,r)}delete(e,r){return iC.delete.call(this,e,r)}space(e){return this.focused.editable?this.append(e):super.space()}number(e){return this.focused.editable?this.append(e):super.number(e)}next(){return this.focused.editable?iC.next.call(this):super.next()}prev(){return this.focused.editable?iC.prev.call(this):super.prev()}async indicator(e,r){let s=e.indicator||"",a=e.editable?s:super.indicator(e,r);return await this.resolve(a,this.state,e,r)||""}indent(e){return e.role==="heading"?"":e.editable?" ":" "}async renderChoice(e,r){return e.indent="",e.editable?iC.renderChoice.call(this,e,r):super.renderChoice(e,r)}error(){return""}footer(){return this.state.error}async validate(){let e=!0;for(let r of this.choices){if(typeof r.validate!="function"||r.role==="heading")continue;let s=r.parent?this.value[r.parent.name]:this.value;if(r.editable?s=r.value===r.name?r.initial||"":r.value:this.isDisabled(r)||(s=r.enabled===!0),e=await r.validate(s,this.state),e!==!0)break}return e!==!0&&(this.state.error=typeof e=="string"?e:"Invalid Input"),e}submit(){if(this.focused.newChoice===!0)return super.submit();if(this.choices.some(e=>e.newChoice))return this.alert();this.value={};for(let e of this.choices){let r=e.parent?this.value[e.parent.name]:this.value;if(e.role==="heading"){this.value[e.name]={};continue}e.editable?r[e.name]=e.value===e.name?e.initial||"":e.value:this.isDisabled(e)||(r[e.name]=e.enabled===!0)}return this.base.submit.call(this)}};Cme.exports=B5});var vm=_((pjt,Bme)=>{"use strict";var plt=nC(),hlt=y5(),{isPrimitive:glt}=Zo(),v5=class extends plt{constructor(e){super(e),this.initial=glt(this.initial)?String(this.initial):"",this.initial&&this.cursorHide(),this.state.prevCursor=0,this.state.clipboard=[]}async keypress(e,r={}){let s=this.state.prevKeypress;return this.state.prevKeypress=r,this.options.multiline===!0&&r.name==="return"&&(!s||s.name!=="return")?this.append(` +`,r):super.keypress(e,r)}moveCursor(e){this.cursor+=e}reset(){return this.input=this.value="",this.cursor=0,this.render()}dispatch(e,r){if(!e||r.ctrl||r.code)return this.alert();this.append(e)}append(e){let{cursor:r,input:s}=this.state;this.input=`${s}`.slice(0,r)+e+`${s}`.slice(r),this.moveCursor(String(e).length),this.render()}insert(e){this.append(e)}delete(){let{cursor:e,input:r}=this.state;if(e<=0)return this.alert();this.input=`${r}`.slice(0,e-1)+`${r}`.slice(e),this.moveCursor(-1),this.render()}deleteForward(){let{cursor:e,input:r}=this.state;if(r[e]===void 0)return this.alert();this.input=`${r}`.slice(0,e)+`${r}`.slice(e+1),this.render()}cutForward(){let e=this.cursor;if(this.input.length<=e)return this.alert();this.state.clipboard.push(this.input.slice(e)),this.input=this.input.slice(0,e),this.render()}cutLeft(){let e=this.cursor;if(e===0)return this.alert();let r=this.input.slice(0,e),s=this.input.slice(e),a=r.split(" ");this.state.clipboard.push(a.pop()),this.input=a.join(" "),this.cursor=this.input.length,this.input+=s,this.render()}paste(){if(!this.state.clipboard.length)return this.alert();this.insert(this.state.clipboard.pop()),this.render()}toggleCursor(){this.state.prevCursor?(this.cursor=this.state.prevCursor,this.state.prevCursor=0):(this.state.prevCursor=this.cursor,this.cursor=0),this.render()}first(){this.cursor=0,this.render()}last(){this.cursor=this.input.length-1,this.render()}next(){let e=this.initial!=null?String(this.initial):"";if(!e||!e.startsWith(this.input))return this.alert();this.input=this.initial,this.cursor=this.initial.length,this.render()}prev(){if(!this.input)return this.alert();this.reset()}backward(){return this.left()}forward(){return this.right()}right(){return this.cursor>=this.input.length?this.alert():(this.moveCursor(1),this.render())}left(){return this.cursor<=0?this.alert():(this.moveCursor(-1),this.render())}isValue(e){return!!e}async format(e=this.value){let r=await this.resolve(this.initial,this.state);return this.state.submitted?this.styles.submitted(e||r):hlt(this,{input:e,initial:r,pos:this.cursor})}async render(){let e=this.state.size,r=await this.prefix(),s=await this.separator(),a=await this.message(),n=[r,a,s].filter(Boolean).join(" ");this.state.prompt=n;let c=await this.header(),f=await this.format(),p=await this.error()||await this.hint(),h=await this.footer();p&&!f.includes(p)&&(f+=" "+p),n+=" "+f,this.clear(e),this.write([c,n,h].filter(Boolean).join(` +`)),this.restore()}};Bme.exports=v5});var Sme=_((hjt,vme)=>{"use strict";var dlt=t=>t.filter((e,r)=>t.lastIndexOf(e)===r),$R=t=>dlt(t).filter(Boolean);vme.exports=(t,e={},r="")=>{let{past:s=[],present:a=""}=e,n,c;switch(t){case"prev":case"undo":return n=s.slice(0,s.length-1),c=s[s.length-1]||"",{past:$R([r,...n]),present:c};case"next":case"redo":return n=s.slice(1),c=s[0]||"",{past:$R([...n,r]),present:c};case"save":return{past:$R([...s,r]),present:""};case"remove":return c=$R(s.filter(f=>f!==r)),a="",c.length&&(a=c.pop()),{past:c,present:a};default:throw new Error(`Invalid action: "${t}"`)}}});var D5=_((gjt,bme)=>{"use strict";var mlt=vm(),Dme=Sme(),S5=class extends mlt{constructor(e){super(e);let r=this.options.history;if(r&&r.store){let s=r.values||this.initial;this.autosave=!!r.autosave,this.store=r.store,this.data=this.store.get("values")||{past:[],present:s},this.initial=this.data.present||this.data.past[this.data.past.length-1]}}completion(e){return this.store?(this.data=Dme(e,this.data,this.input),this.data.present?(this.input=this.data.present,this.cursor=this.input.length,this.render()):this.alert()):this.alert()}altUp(){return this.completion("prev")}altDown(){return this.completion("next")}prev(){return this.save(),super.prev()}save(){this.store&&(this.data=Dme("save",this.data,this.input),this.store.set("values",this.data))}submit(){return this.store&&this.autosave===!0&&this.save(),super.submit()}};bme.exports=S5});var xme=_((djt,Pme)=>{"use strict";var ylt=vm(),b5=class extends ylt{format(){return""}};Pme.exports=b5});var Qme=_((mjt,kme)=>{"use strict";var Elt=vm(),P5=class extends Elt{constructor(e={}){super(e),this.sep=this.options.separator||/, */,this.initial=e.initial||""}split(e=this.value){return e?String(e).split(this.sep):[]}format(){let e=this.state.submitted?this.styles.primary:r=>r;return this.list.map(e).join(", ")}async submit(e){let r=this.state.error||await this.validate(this.list,this.state);return r!==!0?(this.state.error=r,super.submit()):(this.value=this.list,super.submit())}get list(){return this.split()}};kme.exports=P5});var Rme=_((yjt,Tme)=>{"use strict";var Ilt=G0(),x5=class extends Ilt{constructor(e){super({...e,multiple:!0})}};Tme.exports=x5});var Q5=_((Ejt,Fme)=>{"use strict";var Clt=vm(),k5=class extends Clt{constructor(e={}){super({style:"number",...e}),this.min=this.isValue(e.min)?this.toNumber(e.min):-1/0,this.max=this.isValue(e.max)?this.toNumber(e.max):1/0,this.delay=e.delay!=null?e.delay:1e3,this.float=e.float!==!1,this.round=e.round===!0||e.float===!1,this.major=e.major||10,this.minor=e.minor||1,this.initial=e.initial!=null?e.initial:"",this.input=String(this.initial),this.cursor=this.input.length,this.cursorShow()}append(e){return!/[-+.]/.test(e)||e==="."&&this.input.includes(".")?this.alert("invalid number"):super.append(e)}number(e){return super.append(e)}next(){return this.input&&this.input!==this.initial?this.alert():this.isValue(this.initial)?(this.input=this.initial,this.cursor=String(this.initial).length,this.render()):this.alert()}up(e){let r=e||this.minor,s=this.toNumber(this.input);return s>this.max+r?this.alert():(this.input=`${s+r}`,this.render())}down(e){let r=e||this.minor,s=this.toNumber(this.input);return sthis.isValue(r));return this.value=this.toNumber(e||0),super.submit()}};Fme.exports=k5});var Ome=_((Ijt,Nme)=>{Nme.exports=Q5()});var Mme=_((Cjt,Lme)=>{"use strict";var wlt=vm(),T5=class extends wlt{constructor(e){super(e),this.cursorShow()}format(e=this.input){return this.keypressed?(this.state.submitted?this.styles.primary:this.styles.muted)(this.symbols.asterisk.repeat(e.length)):""}};Lme.exports=T5});var Hme=_((wjt,_me)=>{"use strict";var Blt=Ju(),vlt=Wv(),Ume=Zo(),R5=class extends vlt{constructor(e={}){super(e),this.widths=[].concat(e.messageWidth||50),this.align=[].concat(e.align||"left"),this.linebreak=e.linebreak||!1,this.edgeLength=e.edgeLength||3,this.newline=e.newline||` + `;let r=e.startNumber||1;typeof this.scale=="number"&&(this.scaleKey=!1,this.scale=Array(this.scale).fill(0).map((s,a)=>({name:a+r})))}async reset(){return this.tableized=!1,await super.reset(),this.render()}tableize(){if(this.tableized===!0)return;this.tableized=!0;let e=0;for(let r of this.choices){e=Math.max(e,r.message.length),r.scaleIndex=r.initial||2,r.scale=[];for(let s=0;s=this.scale.length-1?this.alert():(e.scaleIndex++,this.render())}left(){let e=this.focused;return e.scaleIndex<=0?this.alert():(e.scaleIndex--,this.render())}indent(){return""}format(){return this.state.submitted?this.choices.map(r=>this.styles.info(r.index)).join(", "):""}pointer(){return""}renderScaleKey(){return this.scaleKey===!1||this.state.submitted?"":["",...this.scale.map(s=>` ${s.name} - ${s.message}`)].map(s=>this.styles.muted(s)).join(` +`)}renderScaleHeading(e){let r=this.scale.map(p=>p.name);typeof this.options.renderScaleHeading=="function"&&(r=this.options.renderScaleHeading.call(this,e));let s=this.scaleLength-r.join("").length,a=Math.round(s/(r.length-1)),c=r.map(p=>this.styles.strong(p)).join(" ".repeat(a)),f=" ".repeat(this.widths[0]);return this.margin[3]+f+this.margin[1]+c}scaleIndicator(e,r,s){if(typeof this.options.scaleIndicator=="function")return this.options.scaleIndicator.call(this,e,r,s);let a=e.scaleIndex===r.index;return r.disabled?this.styles.hint(this.symbols.radio.disabled):a?this.styles.success(this.symbols.radio.on):this.symbols.radio.off}renderScale(e,r){let s=e.scale.map(n=>this.scaleIndicator(e,n,r)),a=this.term==="Hyper"?"":" ";return s.join(a+this.symbols.line.repeat(this.edgeLength))}async renderChoice(e,r){await this.onChoice(e,r);let s=this.index===r,a=await this.pointer(e,r),n=await e.hint;n&&!Ume.hasColor(n)&&(n=this.styles.muted(n));let c=I=>this.margin[3]+I.replace(/\s+$/,"").padEnd(this.widths[0]," "),f=this.newline,p=this.indent(e),h=await this.resolve(e.message,this.state,e,r),E=await this.renderScale(e,r),C=this.margin[1]+this.margin[3];this.scaleLength=Blt.unstyle(E).length,this.widths[0]=Math.min(this.widths[0],this.width-this.scaleLength-C.length);let P=Ume.wordWrap(h,{width:this.widths[0],newline:f}).split(` +`).map(I=>c(I)+this.margin[1]);return s&&(E=this.styles.info(E),P=P.map(I=>this.styles.info(I))),P[0]+=E,this.linebreak&&P.push(""),[p+a,P.join(` +`)].filter(Boolean)}async renderChoices(){if(this.state.submitted)return"";this.tableize();let e=this.visible.map(async(a,n)=>await this.renderChoice(a,n)),r=await Promise.all(e),s=await this.renderScaleHeading();return this.margin[0]+[s,...r.map(a=>a.join(" "))].join(` +`)}async render(){let{submitted:e,size:r}=this.state,s=await this.prefix(),a=await this.separator(),n=await this.message(),c="";this.options.promptLine!==!1&&(c=[s,n,a,""].join(" "),this.state.prompt=c);let f=await this.header(),p=await this.format(),h=await this.renderScaleKey(),E=await this.error()||await this.hint(),C=await this.renderChoices(),S=await this.footer(),P=this.emptyError;p&&(c+=p),E&&!c.includes(E)&&(c+=" "+E),e&&!p&&!C.trim()&&this.multiple&&P!=null&&(c+=this.styles.danger(P)),this.clear(r),this.write([f,c,h,C,S].filter(Boolean).join(` +`)),this.state.submitted||this.write(this.margin[2]),this.restore()}submit(){this.value={};for(let e of this.choices)this.value[e.name]=e.scaleIndex;return this.base.submit.call(this)}};_me.exports=R5});var qme=_((Bjt,Gme)=>{"use strict";var jme=Ju(),Slt=(t="")=>typeof t=="string"?t.replace(/^['"]|['"]$/g,""):"",N5=class{constructor(e){this.name=e.key,this.field=e.field||{},this.value=Slt(e.initial||this.field.initial||""),this.message=e.message||this.name,this.cursor=0,this.input="",this.lines=[]}},Dlt=async(t={},e={},r=s=>s)=>{let s=new Set,a=t.fields||[],n=t.template,c=[],f=[],p=[],h=1;typeof n=="function"&&(n=await n());let E=-1,C=()=>n[++E],S=()=>n[E+1],P=I=>{I.line=h,c.push(I)};for(P({type:"bos",value:""});Eie.name===U.key);U.field=a.find(ie=>ie.name===U.key),ee||(ee=new N5(U),f.push(ee)),ee.lines.push(U.line-1);continue}let R=c[c.length-1];R.type==="text"&&R.line===h?R.value+=I:P({type:"text",value:I})}return P({type:"eos",value:""}),{input:n,tabstops:c,unique:s,keys:p,items:f}};Gme.exports=async t=>{let e=t.options,r=new Set(e.required===!0?[]:e.required||[]),s={...e.values,...e.initial},{tabstops:a,items:n,keys:c}=await Dlt(e,s),f=F5("result",t,e),p=F5("format",t,e),h=F5("validate",t,e,!0),E=t.isValue.bind(t);return async(C={},S=!1)=>{let P=0;C.required=r,C.items=n,C.keys=c,C.output="";let I=async(W,ee,ie,ue)=>{let le=await h(W,ee,ie,ue);return le===!1?"Invalid field "+ie.name:le};for(let W of a){let ee=W.value,ie=W.key;if(W.type!=="template"){ee&&(C.output+=ee);continue}if(W.type==="template"){let ue=n.find(Ce=>Ce.name===ie);e.required===!0&&C.required.add(ue.name);let le=[ue.input,C.values[ue.value],ue.value,ee].find(E),pe=(ue.field||{}).message||W.inner;if(S){let Ce=await I(C.values[ie],C,ue,P);if(Ce&&typeof Ce=="string"||Ce===!1){C.invalid.set(ie,Ce);continue}C.invalid.delete(ie);let g=await f(C.values[ie],C,ue,P);C.output+=jme.unstyle(g);continue}ue.placeholder=!1;let Be=ee;ee=await p(ee,C,ue,P),le!==ee?(C.values[ie]=le,ee=t.styles.typing(le),C.missing.delete(pe)):(C.values[ie]=void 0,le=`<${pe}>`,ee=t.styles.primary(le),ue.placeholder=!0,C.required.has(ie)&&C.missing.add(pe)),C.missing.has(pe)&&C.validating&&(ee=t.styles.warning(le)),C.invalid.has(ie)&&C.validating&&(ee=t.styles.danger(le)),P===C.index&&(Be!==ee?ee=t.styles.underline(ee):ee=t.styles.heading(jme.unstyle(ee))),P++}ee&&(C.output+=ee)}let R=C.output.split(` +`).map(W=>" "+W),N=n.length,U=0;for(let W of n)C.invalid.has(W.name)&&W.lines.forEach(ee=>{R[ee][0]===" "&&(R[ee]=C.styles.danger(C.symbols.bullet)+R[ee].slice(1))}),t.isValue(C.values[W.name])&&U++;return C.completed=(U/N*100).toFixed(0),C.output=R.join(` +`),C.output}};function F5(t,e,r,s){return(a,n,c,f)=>typeof c.field[t]=="function"?c.field[t].call(e,a,n,c,f):[s,a].find(p=>e.isValue(p))}});var Yme=_((vjt,Wme)=>{"use strict";var blt=Ju(),Plt=qme(),xlt=nC(),O5=class extends xlt{constructor(e){super(e),this.cursorHide(),this.reset(!0)}async initialize(){this.interpolate=await Plt(this),await super.initialize()}async reset(e){this.state.keys=[],this.state.invalid=new Map,this.state.missing=new Set,this.state.completed=0,this.state.values={},e!==!0&&(await this.initialize(),await this.render())}moveCursor(e){let r=this.getItem();this.cursor+=e,r.cursor+=e}dispatch(e,r){if(!r.code&&!r.ctrl&&e!=null&&this.getItem()){this.append(e,r);return}this.alert()}append(e,r){let s=this.getItem(),a=s.input.slice(0,this.cursor),n=s.input.slice(this.cursor);this.input=s.input=`${a}${e}${n}`,this.moveCursor(1),this.render()}delete(){let e=this.getItem();if(this.cursor<=0||!e.input)return this.alert();let r=e.input.slice(this.cursor),s=e.input.slice(0,this.cursor-1);this.input=e.input=`${s}${r}`,this.moveCursor(-1),this.render()}increment(e){return e>=this.state.keys.length-1?0:e+1}decrement(e){return e<=0?this.state.keys.length-1:e-1}first(){this.state.index=0,this.render()}last(){this.state.index=this.state.keys.length-1,this.render()}right(){if(this.cursor>=this.input.length)return this.alert();this.moveCursor(1),this.render()}left(){if(this.cursor<=0)return this.alert();this.moveCursor(-1),this.render()}prev(){this.state.index=this.decrement(this.state.index),this.getItem(),this.render()}next(){this.state.index=this.increment(this.state.index),this.getItem(),this.render()}up(){this.prev()}down(){this.next()}format(e){let r=this.state.completed<100?this.styles.warning:this.styles.success;return this.state.submitted===!0&&this.state.completed!==100&&(r=this.styles.danger),r(`${this.state.completed}% completed`)}async render(){let{index:e,keys:r=[],submitted:s,size:a}=this.state,n=[this.options.newline,` +`].find(W=>W!=null),c=await this.prefix(),f=await this.separator(),p=await this.message(),h=[c,p,f].filter(Boolean).join(" ");this.state.prompt=h;let E=await this.header(),C=await this.error()||"",S=await this.hint()||"",P=s?"":await this.interpolate(this.state),I=this.state.key=r[e]||"",R=await this.format(I),N=await this.footer();R&&(h+=" "+R),S&&!R&&this.state.completed===0&&(h+=" "+S),this.clear(a);let U=[E,h,P,N,C.trim()];this.write(U.filter(Boolean).join(n)),this.restore()}getItem(e){let{items:r,keys:s,index:a}=this.state,n=r.find(c=>c.name===s[a]);return n&&n.input!=null&&(this.input=n.input,this.cursor=n.cursor),n}async submit(){typeof this.interpolate!="function"&&await this.initialize(),await this.interpolate(this.state,!0);let{invalid:e,missing:r,output:s,values:a}=this.state;if(e.size){let f="";for(let[p,h]of e)f+=`Invalid ${p}: ${h} +`;return this.state.error=f,super.submit()}if(r.size)return this.state.error="Required: "+[...r.keys()].join(", "),super.submit();let c=blt.unstyle(s).split(` +`).map(f=>f.slice(1)).join(` +`);return this.value={values:a,result:c},super.submit()}};Wme.exports=O5});var Jme=_((Sjt,Vme)=>{"use strict";var klt="(Use + to sort)",Qlt=G0(),L5=class extends Qlt{constructor(e){super({...e,reorder:!1,sort:!0,multiple:!0}),this.state.hint=[this.options.hint,klt].find(this.isValue.bind(this))}indicator(){return""}async renderChoice(e,r){let s=await super.renderChoice(e,r),a=this.symbols.identicalTo+" ",n=this.index===r&&this.sorting?this.styles.muted(a):" ";return this.options.drag===!1&&(n=""),this.options.numbered===!0?n+`${r+1} - `+s:n+s}get selected(){return this.choices}submit(){return this.value=this.choices.map(e=>e.value),super.submit()}};Vme.exports=L5});var zme=_((Djt,Kme)=>{"use strict";var Tlt=Wv(),M5=class extends Tlt{constructor(e={}){if(super(e),this.emptyError=e.emptyError||"No items were selected",this.term=process.env.TERM_PROGRAM,!this.options.header){let r=["","4 - Strongly Agree","3 - Agree","2 - Neutral","1 - Disagree","0 - Strongly Disagree",""];r=r.map(s=>this.styles.muted(s)),this.state.header=r.join(` + `)}}async toChoices(...e){if(this.createdScales)return!1;this.createdScales=!0;let r=await super.toChoices(...e);for(let s of r)s.scale=Rlt(5,this.options),s.scaleIdx=2;return r}dispatch(){this.alert()}space(){let e=this.focused,r=e.scale[e.scaleIdx],s=r.selected;return e.scale.forEach(a=>a.selected=!1),r.selected=!s,this.render()}indicator(){return""}pointer(){return""}separator(){return this.styles.muted(this.symbols.ellipsis)}right(){let e=this.focused;return e.scaleIdx>=e.scale.length-1?this.alert():(e.scaleIdx++,this.render())}left(){let e=this.focused;return e.scaleIdx<=0?this.alert():(e.scaleIdx--,this.render())}indent(){return" "}async renderChoice(e,r){await this.onChoice(e,r);let s=this.index===r,a=this.term==="Hyper",n=a?9:8,c=a?"":" ",f=this.symbols.line.repeat(n),p=" ".repeat(n+(a?0:1)),h=ee=>(ee?this.styles.success("\u25C9"):"\u25EF")+c,E=r+1+".",C=s?this.styles.heading:this.styles.noop,S=await this.resolve(e.message,this.state,e,r),P=this.indent(e),I=P+e.scale.map((ee,ie)=>h(ie===e.scaleIdx)).join(f),R=ee=>ee===e.scaleIdx?C(ee):ee,N=P+e.scale.map((ee,ie)=>R(ie)).join(p),U=()=>[E,S].filter(Boolean).join(" "),W=()=>[U(),I,N," "].filter(Boolean).join(` +`);return s&&(I=this.styles.cyan(I),N=this.styles.cyan(N)),W()}async renderChoices(){if(this.state.submitted)return"";let e=this.visible.map(async(s,a)=>await this.renderChoice(s,a)),r=await Promise.all(e);return r.length||r.push(this.styles.danger("No matching choices")),r.join(` +`)}format(){return this.state.submitted?this.choices.map(r=>this.styles.info(r.scaleIdx)).join(", "):""}async render(){let{submitted:e,size:r}=this.state,s=await this.prefix(),a=await this.separator(),n=await this.message(),c=[s,n,a].filter(Boolean).join(" ");this.state.prompt=c;let f=await this.header(),p=await this.format(),h=await this.error()||await this.hint(),E=await this.renderChoices(),C=await this.footer();(p||!h)&&(c+=" "+p),h&&!c.includes(h)&&(c+=" "+h),e&&!p&&!E&&this.multiple&&this.type!=="form"&&(c+=this.styles.danger(this.emptyError)),this.clear(r),this.write([c,f,E,C].filter(Boolean).join(` +`)),this.restore()}submit(){this.value={};for(let e of this.choices)this.value[e.name]=e.scaleIdx;return this.base.submit.call(this)}};function Rlt(t,e={}){if(Array.isArray(e.scale))return e.scale.map(s=>({...s}));let r=[];for(let s=1;s{Xme.exports=D5()});var eye=_((Pjt,$me)=>{"use strict";var Flt=ZR(),U5=class extends Flt{async initialize(){await super.initialize(),this.value=this.initial=!!this.options.initial,this.disabled=this.options.disabled||"no",this.enabled=this.options.enabled||"yes",await this.render()}reset(){this.value=this.initial,this.render()}delete(){this.alert()}toggle(){this.value=!this.value,this.render()}enable(){if(this.value===!0)return this.alert();this.value=!0,this.render()}disable(){if(this.value===!1)return this.alert();this.value=!1,this.render()}up(){this.toggle()}down(){this.toggle()}right(){this.toggle()}left(){this.toggle()}next(){this.toggle()}prev(){this.toggle()}dispatch(e="",r){switch(e.toLowerCase()){case" ":return this.toggle();case"1":case"y":case"t":return this.enable();case"0":case"n":case"f":return this.disable();default:return this.alert()}}format(){let e=s=>this.styles.primary.underline(s);return[this.value?this.disabled:e(this.disabled),this.value?e(this.enabled):this.enabled].join(this.styles.muted(" / "))}async render(){let{size:e}=this.state,r=await this.header(),s=await this.prefix(),a=await this.separator(),n=await this.message(),c=await this.format(),f=await this.error()||await this.hint(),p=await this.footer(),h=[s,n,a,c].join(" ");this.state.prompt=h,f&&!h.includes(f)&&(h+=" "+f),this.clear(e),this.write([r,h,p].filter(Boolean).join(` +`)),this.write(this.margin[2]),this.restore()}};$me.exports=U5});var rye=_((xjt,tye)=>{"use strict";var Nlt=G0(),_5=class extends Nlt{constructor(e){if(super(e),typeof this.options.correctChoice!="number"||this.options.correctChoice<0)throw new Error("Please specify the index of the correct answer from the list of choices")}async toChoices(e,r){let s=await super.toChoices(e,r);if(s.length<2)throw new Error("Please give at least two choices to the user");if(this.options.correctChoice>s.length)throw new Error("Please specify the index of the correct answer from the list of choices");return s}check(e){return e.index===this.options.correctChoice}async result(e){return{selectedAnswer:e,correctAnswer:this.options.choices[this.options.correctChoice].value,correct:await this.check(this.state)}}};tye.exports=_5});var iye=_(H5=>{"use strict";var nye=Zo(),ks=(t,e)=>{nye.defineExport(H5,t,e),nye.defineExport(H5,t.toLowerCase(),e)};ks("AutoComplete",()=>ume());ks("BasicAuth",()=>mme());ks("Confirm",()=>Ime());ks("Editable",()=>wme());ks("Form",()=>XR());ks("Input",()=>D5());ks("Invisible",()=>xme());ks("List",()=>Qme());ks("MultiSelect",()=>Rme());ks("Numeral",()=>Ome());ks("Password",()=>Mme());ks("Scale",()=>Hme());ks("Select",()=>G0());ks("Snippet",()=>Yme());ks("Sort",()=>Jme());ks("Survey",()=>zme());ks("Text",()=>Zme());ks("Toggle",()=>eye());ks("Quiz",()=>rye())});var oye=_((Qjt,sye)=>{sye.exports={ArrayPrompt:Wv(),AuthPrompt:I5(),BooleanPrompt:ZR(),NumberPrompt:Q5(),StringPrompt:vm()}});var Vv=_((Tjt,lye)=>{"use strict";var aye=Ie("assert"),G5=Ie("events"),q0=Zo(),zu=class extends G5{constructor(e,r){super(),this.options=q0.merge({},e),this.answers={...r}}register(e,r){if(q0.isObject(e)){for(let a of Object.keys(e))this.register(a,e[a]);return this}aye.equal(typeof r,"function","expected a function");let s=e.toLowerCase();return r.prototype instanceof this.Prompt?this.prompts[s]=r:this.prompts[s]=r(this.Prompt,this),this}async prompt(e=[]){for(let r of[].concat(e))try{typeof r=="function"&&(r=await r.call(this)),await this.ask(q0.merge({},this.options,r))}catch(s){return Promise.reject(s)}return this.answers}async ask(e){typeof e=="function"&&(e=await e.call(this));let r=q0.merge({},this.options,e),{type:s,name:a}=e,{set:n,get:c}=q0;if(typeof s=="function"&&(s=await s.call(this,e,this.answers)),!s)return this.answers[a];aye(this.prompts[s],`Prompt "${s}" is not registered`);let f=new this.prompts[s](r),p=c(this.answers,a);f.state.answers=this.answers,f.enquirer=this,a&&f.on("submit",E=>{this.emit("answer",a,E,f),n(this.answers,a,E)});let h=f.emit.bind(f);return f.emit=(...E)=>(this.emit.call(this,...E),h(...E)),this.emit("prompt",f,this),r.autofill&&p!=null?(f.value=f.input=p,r.autofill==="show"&&await f.submit()):p=f.value=await f.run(),p}use(e){return e.call(this,this),this}set Prompt(e){this._Prompt=e}get Prompt(){return this._Prompt||this.constructor.Prompt}get prompts(){return this.constructor.prompts}static set Prompt(e){this._Prompt=e}static get Prompt(){return this._Prompt||nC()}static get prompts(){return iye()}static get types(){return oye()}static get prompt(){let e=(r,...s)=>{let a=new this(...s),n=a.emit.bind(a);return a.emit=(...c)=>(e.emit(...c),n(...c)),a.prompt(r)};return q0.mixinEmitter(e,new G5),e}};q0.mixinEmitter(zu,new G5);var j5=zu.prompts;for(let t of Object.keys(j5)){let e=t.toLowerCase(),r=s=>new j5[t](s).run();zu.prompt[e]=r,zu[e]=r,zu[t]||Reflect.defineProperty(zu,t,{get:()=>j5[t]})}var Yv=t=>{q0.defineExport(zu,t,()=>zu.types[t])};Yv("ArrayPrompt");Yv("AuthPrompt");Yv("BooleanPrompt");Yv("NumberPrompt");Yv("StringPrompt");lye.exports=zu});var dye=_((tGt,qlt)=>{qlt.exports={name:"@yarnpkg/cli",version:"4.12.0",license:"BSD-2-Clause",main:"./sources/index.ts",exports:{".":"./sources/index.ts","./polyfills":"./sources/polyfills.ts","./package.json":"./package.json"},dependencies:{"@yarnpkg/core":"workspace:^","@yarnpkg/fslib":"workspace:^","@yarnpkg/libzip":"workspace:^","@yarnpkg/parsers":"workspace:^","@yarnpkg/plugin-catalog":"workspace:^","@yarnpkg/plugin-compat":"workspace:^","@yarnpkg/plugin-constraints":"workspace:^","@yarnpkg/plugin-dlx":"workspace:^","@yarnpkg/plugin-essentials":"workspace:^","@yarnpkg/plugin-exec":"workspace:^","@yarnpkg/plugin-file":"workspace:^","@yarnpkg/plugin-git":"workspace:^","@yarnpkg/plugin-github":"workspace:^","@yarnpkg/plugin-http":"workspace:^","@yarnpkg/plugin-init":"workspace:^","@yarnpkg/plugin-interactive-tools":"workspace:^","@yarnpkg/plugin-jsr":"workspace:^","@yarnpkg/plugin-link":"workspace:^","@yarnpkg/plugin-nm":"workspace:^","@yarnpkg/plugin-npm":"workspace:^","@yarnpkg/plugin-npm-cli":"workspace:^","@yarnpkg/plugin-pack":"workspace:^","@yarnpkg/plugin-patch":"workspace:^","@yarnpkg/plugin-pnp":"workspace:^","@yarnpkg/plugin-pnpm":"workspace:^","@yarnpkg/plugin-stage":"workspace:^","@yarnpkg/plugin-typescript":"workspace:^","@yarnpkg/plugin-version":"workspace:^","@yarnpkg/plugin-workspace-tools":"workspace:^","@yarnpkg/shell":"workspace:^","ci-info":"^4.0.0",clipanion:"^4.0.0-rc.2",semver:"^7.1.2",tslib:"^2.4.0",typanion:"^3.14.0"},devDependencies:{"@types/semver":"^7.1.0","@yarnpkg/builder":"workspace:^","@yarnpkg/monorepo":"workspace:^","@yarnpkg/pnpify":"workspace:^"},peerDependencies:{"@yarnpkg/core":"workspace:^"},scripts:{postpack:"rm -rf lib",prepack:'run build:compile "$(pwd)"',"build:cli+hook":"run build:pnp:hook && builder build bundle","build:cli":"builder build bundle","run:cli":"builder run","update-local":"run build:cli --no-git-hash && rsync -a --delete bundles/ bin/"},publishConfig:{main:"./lib/index.js",bin:null,exports:{".":"./lib/index.js","./package.json":"./package.json"}},files:["/lib/**/*","!/lib/pluginConfiguration.*","!/lib/cli.*"],"@yarnpkg/builder":{bundles:{standard:["@yarnpkg/plugin-essentials","@yarnpkg/plugin-catalog","@yarnpkg/plugin-compat","@yarnpkg/plugin-constraints","@yarnpkg/plugin-dlx","@yarnpkg/plugin-exec","@yarnpkg/plugin-file","@yarnpkg/plugin-git","@yarnpkg/plugin-github","@yarnpkg/plugin-http","@yarnpkg/plugin-init","@yarnpkg/plugin-interactive-tools","@yarnpkg/plugin-jsr","@yarnpkg/plugin-link","@yarnpkg/plugin-nm","@yarnpkg/plugin-npm","@yarnpkg/plugin-npm-cli","@yarnpkg/plugin-pack","@yarnpkg/plugin-patch","@yarnpkg/plugin-pnp","@yarnpkg/plugin-pnpm","@yarnpkg/plugin-stage","@yarnpkg/plugin-typescript","@yarnpkg/plugin-version","@yarnpkg/plugin-workspace-tools"]}},repository:{type:"git",url:"git+https://github.com/yarnpkg/berry.git",directory:"packages/yarnpkg-cli"},engines:{node:">=18.12.0"}}});var iq=_((R9t,Pye)=>{"use strict";Pye.exports=function(e,r){r===!0&&(r=0);var s="";if(typeof e=="string")try{s=new URL(e).protocol}catch{}else e&&e.constructor===URL&&(s=e.protocol);var a=s.split(/\:|\+/).filter(Boolean);return typeof r=="number"?a[r]:a}});var kye=_((F9t,xye)=>{"use strict";var uct=iq();function fct(t){var e={protocols:[],protocol:null,port:null,resource:"",host:"",user:"",password:"",pathname:"",hash:"",search:"",href:t,query:{},parse_failed:!1};try{var r=new URL(t);e.protocols=uct(r),e.protocol=e.protocols[0],e.port=r.port,e.resource=r.hostname,e.host=r.host,e.user=r.username||"",e.password=r.password||"",e.pathname=r.pathname,e.hash=r.hash.slice(1),e.search=r.search.slice(1),e.href=r.href,e.query=Object.fromEntries(r.searchParams)}catch{e.protocols=["file"],e.protocol=e.protocols[0],e.port="",e.resource="",e.user="",e.pathname="",e.hash="",e.search="",e.href=t,e.query={},e.parse_failed=!0}return e}xye.exports=fct});var Rye=_((N9t,Tye)=>{"use strict";var Act=kye();function pct(t){return t&&typeof t=="object"&&"default"in t?t:{default:t}}var hct=pct(Act),gct="text/plain",dct="us-ascii",Qye=(t,e)=>e.some(r=>r instanceof RegExp?r.test(t):r===t),mct=(t,{stripHash:e})=>{let r=/^data:(?[^,]*?),(?[^#]*?)(?:#(?.*))?$/.exec(t);if(!r)throw new Error(`Invalid URL: ${t}`);let{type:s,data:a,hash:n}=r.groups,c=s.split(";");n=e?"":n;let f=!1;c[c.length-1]==="base64"&&(c.pop(),f=!0);let p=(c.shift()||"").toLowerCase(),E=[...c.map(C=>{let[S,P=""]=C.split("=").map(I=>I.trim());return S==="charset"&&(P=P.toLowerCase(),P===dct)?"":`${S}${P?`=${P}`:""}`}).filter(Boolean)];return f&&E.push("base64"),(E.length>0||p&&p!==gct)&&E.unshift(p),`data:${E.join(";")},${f?a.trim():a}${n?`#${n}`:""}`};function yct(t,e){if(e={defaultProtocol:"http:",normalizeProtocol:!0,forceHttp:!1,forceHttps:!1,stripAuthentication:!0,stripHash:!1,stripTextFragment:!0,stripWWW:!0,removeQueryParameters:[/^utm_\w+/i],removeTrailingSlash:!0,removeSingleSlash:!0,removeDirectoryIndex:!1,sortQueryParameters:!0,...e},t=t.trim(),/^data:/i.test(t))return mct(t,e);if(/^view-source:/i.test(t))throw new Error("`view-source:` is not supported as it is a non-standard protocol");let r=t.startsWith("//");!r&&/^\.*\//.test(t)||(t=t.replace(/^(?!(?:\w+:)?\/\/)|^\/\//,e.defaultProtocol));let a=new URL(t);if(e.forceHttp&&e.forceHttps)throw new Error("The `forceHttp` and `forceHttps` options cannot be used together");if(e.forceHttp&&a.protocol==="https:"&&(a.protocol="http:"),e.forceHttps&&a.protocol==="http:"&&(a.protocol="https:"),e.stripAuthentication&&(a.username="",a.password=""),e.stripHash?a.hash="":e.stripTextFragment&&(a.hash=a.hash.replace(/#?:~:text.*?$/i,"")),a.pathname){let c=/\b[a-z][a-z\d+\-.]{1,50}:\/\//g,f=0,p="";for(;;){let E=c.exec(a.pathname);if(!E)break;let C=E[0],S=E.index,P=a.pathname.slice(f,S);p+=P.replace(/\/{2,}/g,"/"),p+=C,f=S+C.length}let h=a.pathname.slice(f,a.pathname.length);p+=h.replace(/\/{2,}/g,"/"),a.pathname=p}if(a.pathname)try{a.pathname=decodeURI(a.pathname)}catch{}if(e.removeDirectoryIndex===!0&&(e.removeDirectoryIndex=[/^index\.[a-z]+$/]),Array.isArray(e.removeDirectoryIndex)&&e.removeDirectoryIndex.length>0){let c=a.pathname.split("/"),f=c[c.length-1];Qye(f,e.removeDirectoryIndex)&&(c=c.slice(0,-1),a.pathname=c.slice(1).join("/")+"/")}if(a.hostname&&(a.hostname=a.hostname.replace(/\.$/,""),e.stripWWW&&/^www\.(?!www\.)[a-z\-\d]{1,63}\.[a-z.\-\d]{2,63}$/.test(a.hostname)&&(a.hostname=a.hostname.replace(/^www\./,""))),Array.isArray(e.removeQueryParameters))for(let c of[...a.searchParams.keys()])Qye(c,e.removeQueryParameters)&&a.searchParams.delete(c);if(e.removeQueryParameters===!0&&(a.search=""),e.sortQueryParameters){a.searchParams.sort();try{a.search=decodeURIComponent(a.search)}catch{}}e.removeTrailingSlash&&(a.pathname=a.pathname.replace(/\/$/,""));let n=t;return t=a.toString(),!e.removeSingleSlash&&a.pathname==="/"&&!n.endsWith("/")&&a.hash===""&&(t=t.replace(/\/$/,"")),(e.removeTrailingSlash||a.pathname==="/")&&a.hash===""&&e.removeSingleSlash&&(t=t.replace(/\/$/,"")),r&&!e.normalizeProtocol&&(t=t.replace(/^http:\/\//,"//")),e.stripProtocol&&(t=t.replace(/^(?:https?:)?\/\//,"")),t}var sq=(t,e=!1)=>{let r=/^(?:([a-z_][a-z0-9_-]{0,31})@|https?:\/\/)([\w\.\-@]+)[\/:]([\~,\.\w,\-,\_,\/]+?(?:\.git|\/)?)$/,s=n=>{let c=new Error(n);throw c.subject_url=t,c};(typeof t!="string"||!t.trim())&&s("Invalid url."),t.length>sq.MAX_INPUT_LENGTH&&s("Input exceeds maximum length. If needed, change the value of parseUrl.MAX_INPUT_LENGTH."),e&&(typeof e!="object"&&(e={stripHash:!1}),t=yct(t,e));let a=hct.default(t);if(a.parse_failed){let n=a.href.match(r);n?(a.protocols=["ssh"],a.protocol="ssh",a.resource=n[2],a.host=n[2],a.user=n[1],a.pathname=`/${n[3]}`,a.parse_failed=!1):s("URL parsing failed.")}return a};sq.MAX_INPUT_LENGTH=2048;Tye.exports=sq});var Oye=_((O9t,Nye)=>{"use strict";var Ect=iq();function Fye(t){if(Array.isArray(t))return t.indexOf("ssh")!==-1||t.indexOf("rsync")!==-1;if(typeof t!="string")return!1;var e=Ect(t);if(t=t.substring(t.indexOf("://")+3),Fye(e))return!0;var r=new RegExp(".([a-zA-Z\\d]+):(\\d+)/");return!t.match(r)&&t.indexOf("@"){"use strict";var Ict=Rye(),Lye=Oye();function Cct(t){var e=Ict(t);return e.token="",e.password==="x-oauth-basic"?e.token=e.user:e.user==="x-token-auth"&&(e.token=e.password),Lye(e.protocols)||e.protocols.length===0&&Lye(t)?e.protocol="ssh":e.protocols.length?e.protocol=e.protocols[0]:(e.protocol="file",e.protocols=["file"]),e.href=e.href.replace(/\/$/,""),e}Mye.exports=Cct});var Hye=_((M9t,_ye)=>{"use strict";var wct=Uye();function oq(t){if(typeof t!="string")throw new Error("The url must be a string.");var e=/^([a-z\d-]{1,39})\/([-\.\w]{1,100})$/i;e.test(t)&&(t="https://github.com/"+t);var r=wct(t),s=r.resource.split("."),a=null;switch(r.toString=function(N){return oq.stringify(this,N)},r.source=s.length>2?s.slice(1-s.length).join("."):r.source=r.resource,r.git_suffix=/\.git$/.test(r.pathname),r.name=decodeURIComponent((r.pathname||r.href).replace(/(^\/)|(\/$)/g,"").replace(/\.git$/,"")),r.owner=decodeURIComponent(r.user),r.source){case"git.cloudforge.com":r.owner=r.user,r.organization=s[0],r.source="cloudforge.com";break;case"visualstudio.com":if(r.resource==="vs-ssh.visualstudio.com"){a=r.name.split("/"),a.length===4&&(r.organization=a[1],r.owner=a[2],r.name=a[3],r.full_name=a[2]+"/"+a[3]);break}else{a=r.name.split("/"),a.length===2?(r.owner=a[1],r.name=a[1],r.full_name="_git/"+r.name):a.length===3?(r.name=a[2],a[0]==="DefaultCollection"?(r.owner=a[2],r.organization=a[0],r.full_name=r.organization+"/_git/"+r.name):(r.owner=a[0],r.full_name=r.owner+"/_git/"+r.name)):a.length===4&&(r.organization=a[0],r.owner=a[1],r.name=a[3],r.full_name=r.organization+"/"+r.owner+"/_git/"+r.name);break}case"dev.azure.com":case"azure.com":if(r.resource==="ssh.dev.azure.com"){a=r.name.split("/"),a.length===4&&(r.organization=a[1],r.owner=a[2],r.name=a[3]);break}else{a=r.name.split("/"),a.length===5?(r.organization=a[0],r.owner=a[1],r.name=a[4],r.full_name="_git/"+r.name):a.length===3?(r.name=a[2],a[0]==="DefaultCollection"?(r.owner=a[2],r.organization=a[0],r.full_name=r.organization+"/_git/"+r.name):(r.owner=a[0],r.full_name=r.owner+"/_git/"+r.name)):a.length===4&&(r.organization=a[0],r.owner=a[1],r.name=a[3],r.full_name=r.organization+"/"+r.owner+"/_git/"+r.name),r.query&&r.query.path&&(r.filepath=r.query.path.replace(/^\/+/g,"")),r.query&&r.query.version&&(r.ref=r.query.version.replace(/^GB/,""));break}default:a=r.name.split("/");var n=a.length-1;if(a.length>=2){var c=a.indexOf("-",2),f=a.indexOf("blob",2),p=a.indexOf("tree",2),h=a.indexOf("commit",2),E=a.indexOf("src",2),C=a.indexOf("raw",2),S=a.indexOf("edit",2);n=c>0?c-1:f>0?f-1:p>0?p-1:h>0?h-1:E>0?E-1:C>0?C-1:S>0?S-1:n,r.owner=a.slice(0,n).join("/"),r.name=a[n],h&&(r.commit=a[n+2])}r.ref="",r.filepathtype="",r.filepath="";var P=a.length>n&&a[n+1]==="-"?n+1:n;a.length>P+2&&["raw","src","blob","tree","edit"].indexOf(a[P+1])>=0&&(r.filepathtype=a[P+1],r.ref=a[P+2],a.length>P+3&&(r.filepath=a.slice(P+3).join("/"))),r.organization=r.owner;break}r.full_name||(r.full_name=r.owner,r.name&&(r.full_name&&(r.full_name+="/"),r.full_name+=r.name)),r.owner.startsWith("scm/")&&(r.source="bitbucket-server",r.owner=r.owner.replace("scm/",""),r.organization=r.owner,r.full_name=r.owner+"/"+r.name);var I=/(projects|users)\/(.*?)\/repos\/(.*?)((\/.*$)|$)/,R=I.exec(r.pathname);return R!=null&&(r.source="bitbucket-server",R[1]==="users"?r.owner="~"+R[2]:r.owner=R[2],r.organization=r.owner,r.name=R[3],a=R[4].split("/"),a.length>1&&(["raw","browse"].indexOf(a[1])>=0?(r.filepathtype=a[1],a.length>2&&(r.filepath=a.slice(2).join("/"))):a[1]==="commits"&&a.length>2&&(r.commit=a[2])),r.full_name=r.owner+"/"+r.name,r.query.at?r.ref=r.query.at:r.ref=""),r}oq.stringify=function(t,e){e=e||(t.protocols&&t.protocols.length?t.protocols.join("+"):t.protocol);var r=t.port?":"+t.port:"",s=t.user||"git",a=t.git_suffix?".git":"";switch(e){case"ssh":return r?"ssh://"+s+"@"+t.resource+r+"/"+t.full_name+a:s+"@"+t.resource+":"+t.full_name+a;case"git+ssh":case"ssh+git":case"ftp":case"ftps":return e+"://"+s+"@"+t.resource+r+"/"+t.full_name+a;case"http":case"https":var n=t.token?Bct(t):t.user&&(t.protocols.includes("http")||t.protocols.includes("https"))?t.user+"@":"";return e+"://"+n+t.resource+r+"/"+vct(t)+a;default:return t.href}};function Bct(t){switch(t.source){case"bitbucket.org":return"x-token-auth:"+t.token+"@";default:return t.token+"@"}}function vct(t){switch(t.source){case"bitbucket-server":return"scm/"+t.full_name;default:return""+t.full_name}}_ye.exports=oq});function jct(t,e){return e===1&&Hct.has(t[0])}function nS(t){let e=Array.isArray(t)?t:Mu(t);return e.map((s,a)=>Uct.test(s)?`[${s}]`:_ct.test(s)&&!jct(e,a)?`.${s}`:`[${JSON.stringify(s)}]`).join("").replace(/^\./,"")}function Gct(t,e){let r=[];if(e.methodName!==null&&r.push(he.pretty(t,e.methodName,he.Type.CODE)),e.file!==null){let s=[];s.push(he.pretty(t,e.file,he.Type.PATH)),e.line!==null&&(s.push(he.pretty(t,e.line,he.Type.NUMBER)),e.column!==null&&s.push(he.pretty(t,e.column,he.Type.NUMBER))),r.push(`(${s.join(he.pretty(t,":","grey"))})`)}return r.join(" ")}function iF(t,{manifestUpdates:e,reportedErrors:r},{fix:s}={}){let a=new Map,n=new Map,c=[...r.keys()].map(f=>[f,new Map]);for(let[f,p]of[...c,...e]){let h=r.get(f)?.map(P=>({text:P,fixable:!1}))??[],E=!1,C=t.getWorkspaceByCwd(f),S=C.manifest.exportTo({});for(let[P,I]of p){if(I.size>1){let R=[...I].map(([N,U])=>{let W=he.pretty(t.configuration,N,he.Type.INSPECT),ee=U.size>0?Gct(t.configuration,U.values().next().value):null;return ee!==null?` +${W} at ${ee}`:` +${W}`}).join("");h.push({text:`Conflict detected in constraint targeting ${he.pretty(t.configuration,P,he.Type.CODE)}; conflicting values are:${R}`,fixable:!1})}else{let[[R]]=I,N=va(S,P);if(JSON.stringify(N)===JSON.stringify(R))continue;if(!s){let U=typeof N>"u"?`Missing field ${he.pretty(t.configuration,P,he.Type.CODE)}; expected ${he.pretty(t.configuration,R,he.Type.INSPECT)}`:typeof R>"u"?`Extraneous field ${he.pretty(t.configuration,P,he.Type.CODE)} currently set to ${he.pretty(t.configuration,N,he.Type.INSPECT)}`:`Invalid field ${he.pretty(t.configuration,P,he.Type.CODE)}; expected ${he.pretty(t.configuration,R,he.Type.INSPECT)}, found ${he.pretty(t.configuration,N,he.Type.INSPECT)}`;h.push({text:U,fixable:!0});continue}typeof R>"u"?A0(S,P):Jd(S,P,R),E=!0}E&&a.set(C,S)}h.length>0&&n.set(C,h)}return{changedWorkspaces:a,remainingErrors:n}}function rEe(t,{configuration:e}){let r={children:[]};for(let[s,a]of t){let n=[];for(let f of a){let p=f.text.split(/\n/);f.fixable&&(p[0]=`${he.pretty(e,"\u2699","gray")} ${p[0]}`),n.push({value:he.tuple(he.Type.NO_HINT,p[0]),children:p.slice(1).map(h=>({value:he.tuple(he.Type.NO_HINT,h)}))})}let c={value:he.tuple(he.Type.LOCATOR,s.anchoredLocator),children:je.sortMap(n,f=>f.value[1])};r.children.push(c)}return r.children=je.sortMap(r.children,s=>s.value[1]),r}var WC,Uct,_ct,Hct,iS=Xe(()=>{Ge();ql();WC=class{constructor(e){this.indexedFields=e;this.items=[];this.indexes={};this.clear()}clear(){this.items=[];for(let e of this.indexedFields)this.indexes[e]=new Map}insert(e){this.items.push(e);for(let r of this.indexedFields){let s=Object.hasOwn(e,r)?e[r]:void 0;if(typeof s>"u")continue;je.getArrayWithDefault(this.indexes[r],s).push(e)}return e}find(e){if(typeof e>"u")return this.items;let r=Object.entries(e);if(r.length===0)return this.items;let s=[],a;for(let[c,f]of r){let p=c,h=Object.hasOwn(this.indexes,p)?this.indexes[p]:void 0;if(typeof h>"u"){s.push([p,f]);continue}let E=new Set(h.get(f)??[]);if(E.size===0)return[];if(typeof a>"u")a=E;else for(let C of a)E.has(C)||a.delete(C);if(a.size===0)break}let n=[...a??[]];return s.length>0&&(n=n.filter(c=>{for(let[f,p]of s)if(!(typeof p<"u"?Object.hasOwn(c,f)&&c[f]===p:Object.hasOwn(c,f)===!1))return!1;return!0})),n}},Uct=/^[0-9]+$/,_ct=/^[a-zA-Z0-9_]+$/,Hct=new Set(["scripts",...Ut.allDependencies])});var nEe=_((_Yt,vq)=>{var qct;(function(t){var e=function(){return{"append/2":[new t.type.Rule(new t.type.Term("append",[new t.type.Var("X"),new t.type.Var("L")]),new t.type.Term("foldl",[new t.type.Term("append",[]),new t.type.Var("X"),new t.type.Term("[]",[]),new t.type.Var("L")]))],"append/3":[new t.type.Rule(new t.type.Term("append",[new t.type.Term("[]",[]),new t.type.Var("X"),new t.type.Var("X")]),null),new t.type.Rule(new t.type.Term("append",[new t.type.Term(".",[new t.type.Var("H"),new t.type.Var("T")]),new t.type.Var("X"),new t.type.Term(".",[new t.type.Var("H"),new t.type.Var("S")])]),new t.type.Term("append",[new t.type.Var("T"),new t.type.Var("X"),new t.type.Var("S")]))],"member/2":[new t.type.Rule(new t.type.Term("member",[new t.type.Var("X"),new t.type.Term(".",[new t.type.Var("X"),new t.type.Var("_")])]),null),new t.type.Rule(new t.type.Term("member",[new t.type.Var("X"),new t.type.Term(".",[new t.type.Var("_"),new t.type.Var("Xs")])]),new t.type.Term("member",[new t.type.Var("X"),new t.type.Var("Xs")]))],"permutation/2":[new t.type.Rule(new t.type.Term("permutation",[new t.type.Term("[]",[]),new t.type.Term("[]",[])]),null),new t.type.Rule(new t.type.Term("permutation",[new t.type.Term(".",[new t.type.Var("H"),new t.type.Var("T")]),new t.type.Var("S")]),new t.type.Term(",",[new t.type.Term("permutation",[new t.type.Var("T"),new t.type.Var("P")]),new t.type.Term(",",[new t.type.Term("append",[new t.type.Var("X"),new t.type.Var("Y"),new t.type.Var("P")]),new t.type.Term("append",[new t.type.Var("X"),new t.type.Term(".",[new t.type.Var("H"),new t.type.Var("Y")]),new t.type.Var("S")])])]))],"maplist/2":[new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("_"),new t.type.Term("[]",[])]),null),new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("P"),new t.type.Term(".",[new t.type.Var("X"),new t.type.Var("Xs")])]),new t.type.Term(",",[new t.type.Term("call",[new t.type.Var("P"),new t.type.Var("X")]),new t.type.Term("maplist",[new t.type.Var("P"),new t.type.Var("Xs")])]))],"maplist/3":[new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("_"),new t.type.Term("[]",[]),new t.type.Term("[]",[])]),null),new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("P"),new t.type.Term(".",[new t.type.Var("A"),new t.type.Var("As")]),new t.type.Term(".",[new t.type.Var("B"),new t.type.Var("Bs")])]),new t.type.Term(",",[new t.type.Term("call",[new t.type.Var("P"),new t.type.Var("A"),new t.type.Var("B")]),new t.type.Term("maplist",[new t.type.Var("P"),new t.type.Var("As"),new t.type.Var("Bs")])]))],"maplist/4":[new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("_"),new t.type.Term("[]",[]),new t.type.Term("[]",[]),new t.type.Term("[]",[])]),null),new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("P"),new t.type.Term(".",[new t.type.Var("A"),new t.type.Var("As")]),new t.type.Term(".",[new t.type.Var("B"),new t.type.Var("Bs")]),new t.type.Term(".",[new t.type.Var("C"),new t.type.Var("Cs")])]),new t.type.Term(",",[new t.type.Term("call",[new t.type.Var("P"),new t.type.Var("A"),new t.type.Var("B"),new t.type.Var("C")]),new t.type.Term("maplist",[new t.type.Var("P"),new t.type.Var("As"),new t.type.Var("Bs"),new t.type.Var("Cs")])]))],"maplist/5":[new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("_"),new t.type.Term("[]",[]),new t.type.Term("[]",[]),new t.type.Term("[]",[]),new t.type.Term("[]",[])]),null),new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("P"),new t.type.Term(".",[new t.type.Var("A"),new t.type.Var("As")]),new t.type.Term(".",[new t.type.Var("B"),new t.type.Var("Bs")]),new t.type.Term(".",[new t.type.Var("C"),new t.type.Var("Cs")]),new t.type.Term(".",[new t.type.Var("D"),new t.type.Var("Ds")])]),new t.type.Term(",",[new t.type.Term("call",[new t.type.Var("P"),new t.type.Var("A"),new t.type.Var("B"),new t.type.Var("C"),new t.type.Var("D")]),new t.type.Term("maplist",[new t.type.Var("P"),new t.type.Var("As"),new t.type.Var("Bs"),new t.type.Var("Cs"),new t.type.Var("Ds")])]))],"maplist/6":[new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("_"),new t.type.Term("[]",[]),new t.type.Term("[]",[]),new t.type.Term("[]",[]),new t.type.Term("[]",[]),new t.type.Term("[]",[])]),null),new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("P"),new t.type.Term(".",[new t.type.Var("A"),new t.type.Var("As")]),new t.type.Term(".",[new t.type.Var("B"),new t.type.Var("Bs")]),new t.type.Term(".",[new t.type.Var("C"),new t.type.Var("Cs")]),new t.type.Term(".",[new t.type.Var("D"),new t.type.Var("Ds")]),new t.type.Term(".",[new t.type.Var("E"),new t.type.Var("Es")])]),new t.type.Term(",",[new t.type.Term("call",[new t.type.Var("P"),new t.type.Var("A"),new t.type.Var("B"),new t.type.Var("C"),new t.type.Var("D"),new t.type.Var("E")]),new t.type.Term("maplist",[new t.type.Var("P"),new t.type.Var("As"),new t.type.Var("Bs"),new t.type.Var("Cs"),new t.type.Var("Ds"),new t.type.Var("Es")])]))],"maplist/7":[new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("_"),new t.type.Term("[]",[]),new t.type.Term("[]",[]),new t.type.Term("[]",[]),new t.type.Term("[]",[]),new t.type.Term("[]",[]),new t.type.Term("[]",[])]),null),new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("P"),new t.type.Term(".",[new t.type.Var("A"),new t.type.Var("As")]),new t.type.Term(".",[new t.type.Var("B"),new t.type.Var("Bs")]),new t.type.Term(".",[new t.type.Var("C"),new t.type.Var("Cs")]),new t.type.Term(".",[new t.type.Var("D"),new t.type.Var("Ds")]),new t.type.Term(".",[new t.type.Var("E"),new t.type.Var("Es")]),new t.type.Term(".",[new t.type.Var("F"),new t.type.Var("Fs")])]),new t.type.Term(",",[new t.type.Term("call",[new t.type.Var("P"),new t.type.Var("A"),new t.type.Var("B"),new t.type.Var("C"),new t.type.Var("D"),new t.type.Var("E"),new t.type.Var("F")]),new t.type.Term("maplist",[new t.type.Var("P"),new t.type.Var("As"),new t.type.Var("Bs"),new t.type.Var("Cs"),new t.type.Var("Ds"),new t.type.Var("Es"),new t.type.Var("Fs")])]))],"maplist/8":[new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("_"),new t.type.Term("[]",[]),new t.type.Term("[]",[]),new t.type.Term("[]",[]),new t.type.Term("[]",[]),new t.type.Term("[]",[]),new t.type.Term("[]",[]),new t.type.Term("[]",[])]),null),new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("P"),new t.type.Term(".",[new t.type.Var("A"),new t.type.Var("As")]),new t.type.Term(".",[new t.type.Var("B"),new t.type.Var("Bs")]),new t.type.Term(".",[new t.type.Var("C"),new t.type.Var("Cs")]),new t.type.Term(".",[new t.type.Var("D"),new t.type.Var("Ds")]),new t.type.Term(".",[new t.type.Var("E"),new t.type.Var("Es")]),new t.type.Term(".",[new t.type.Var("F"),new t.type.Var("Fs")]),new t.type.Term(".",[new t.type.Var("G"),new t.type.Var("Gs")])]),new t.type.Term(",",[new t.type.Term("call",[new t.type.Var("P"),new t.type.Var("A"),new t.type.Var("B"),new t.type.Var("C"),new t.type.Var("D"),new t.type.Var("E"),new t.type.Var("F"),new t.type.Var("G")]),new t.type.Term("maplist",[new t.type.Var("P"),new t.type.Var("As"),new t.type.Var("Bs"),new t.type.Var("Cs"),new t.type.Var("Ds"),new t.type.Var("Es"),new t.type.Var("Fs"),new t.type.Var("Gs")])]))],"include/3":[new t.type.Rule(new t.type.Term("include",[new t.type.Var("_"),new t.type.Term("[]",[]),new t.type.Term("[]",[])]),null),new t.type.Rule(new t.type.Term("include",[new t.type.Var("P"),new t.type.Term(".",[new t.type.Var("H"),new t.type.Var("T")]),new t.type.Var("L")]),new t.type.Term(",",[new t.type.Term("=..",[new t.type.Var("P"),new t.type.Var("A")]),new t.type.Term(",",[new t.type.Term("append",[new t.type.Var("A"),new t.type.Term(".",[new t.type.Var("H"),new t.type.Term("[]",[])]),new t.type.Var("B")]),new t.type.Term(",",[new t.type.Term("=..",[new t.type.Var("F"),new t.type.Var("B")]),new t.type.Term(",",[new t.type.Term(";",[new t.type.Term(",",[new t.type.Term("call",[new t.type.Var("F")]),new t.type.Term(",",[new t.type.Term("=",[new t.type.Var("L"),new t.type.Term(".",[new t.type.Var("H"),new t.type.Var("S")])]),new t.type.Term("!",[])])]),new t.type.Term("=",[new t.type.Var("L"),new t.type.Var("S")])]),new t.type.Term("include",[new t.type.Var("P"),new t.type.Var("T"),new t.type.Var("S")])])])])]))],"exclude/3":[new t.type.Rule(new t.type.Term("exclude",[new t.type.Var("_"),new t.type.Term("[]",[]),new t.type.Term("[]",[])]),null),new t.type.Rule(new t.type.Term("exclude",[new t.type.Var("P"),new t.type.Term(".",[new t.type.Var("H"),new t.type.Var("T")]),new t.type.Var("S")]),new t.type.Term(",",[new t.type.Term("exclude",[new t.type.Var("P"),new t.type.Var("T"),new t.type.Var("E")]),new t.type.Term(",",[new t.type.Term("=..",[new t.type.Var("P"),new t.type.Var("L")]),new t.type.Term(",",[new t.type.Term("append",[new t.type.Var("L"),new t.type.Term(".",[new t.type.Var("H"),new t.type.Term("[]",[])]),new t.type.Var("Q")]),new t.type.Term(",",[new t.type.Term("=..",[new t.type.Var("R"),new t.type.Var("Q")]),new t.type.Term(";",[new t.type.Term(",",[new t.type.Term("call",[new t.type.Var("R")]),new t.type.Term(",",[new t.type.Term("!",[]),new t.type.Term("=",[new t.type.Var("S"),new t.type.Var("E")])])]),new t.type.Term("=",[new t.type.Var("S"),new t.type.Term(".",[new t.type.Var("H"),new t.type.Var("E")])])])])])])]))],"foldl/4":[new t.type.Rule(new t.type.Term("foldl",[new t.type.Var("_"),new t.type.Term("[]",[]),new t.type.Var("I"),new t.type.Var("I")]),null),new t.type.Rule(new t.type.Term("foldl",[new t.type.Var("P"),new t.type.Term(".",[new t.type.Var("H"),new t.type.Var("T")]),new t.type.Var("I"),new t.type.Var("R")]),new t.type.Term(",",[new t.type.Term("=..",[new t.type.Var("P"),new t.type.Var("L")]),new t.type.Term(",",[new t.type.Term("append",[new t.type.Var("L"),new t.type.Term(".",[new t.type.Var("I"),new t.type.Term(".",[new t.type.Var("H"),new t.type.Term(".",[new t.type.Var("X"),new t.type.Term("[]",[])])])]),new t.type.Var("L2")]),new t.type.Term(",",[new t.type.Term("=..",[new t.type.Var("P2"),new t.type.Var("L2")]),new t.type.Term(",",[new t.type.Term("call",[new t.type.Var("P2")]),new t.type.Term("foldl",[new t.type.Var("P"),new t.type.Var("T"),new t.type.Var("X"),new t.type.Var("R")])])])])]))],"select/3":[new t.type.Rule(new t.type.Term("select",[new t.type.Var("E"),new t.type.Term(".",[new t.type.Var("E"),new t.type.Var("Xs")]),new t.type.Var("Xs")]),null),new t.type.Rule(new t.type.Term("select",[new t.type.Var("E"),new t.type.Term(".",[new t.type.Var("X"),new t.type.Var("Xs")]),new t.type.Term(".",[new t.type.Var("X"),new t.type.Var("Ys")])]),new t.type.Term("select",[new t.type.Var("E"),new t.type.Var("Xs"),new t.type.Var("Ys")]))],"sum_list/2":[new t.type.Rule(new t.type.Term("sum_list",[new t.type.Term("[]",[]),new t.type.Num(0,!1)]),null),new t.type.Rule(new t.type.Term("sum_list",[new t.type.Term(".",[new t.type.Var("X"),new t.type.Var("Xs")]),new t.type.Var("S")]),new t.type.Term(",",[new t.type.Term("sum_list",[new t.type.Var("Xs"),new t.type.Var("Y")]),new t.type.Term("is",[new t.type.Var("S"),new t.type.Term("+",[new t.type.Var("X"),new t.type.Var("Y")])])]))],"max_list/2":[new t.type.Rule(new t.type.Term("max_list",[new t.type.Term(".",[new t.type.Var("X"),new t.type.Term("[]",[])]),new t.type.Var("X")]),null),new t.type.Rule(new t.type.Term("max_list",[new t.type.Term(".",[new t.type.Var("X"),new t.type.Var("Xs")]),new t.type.Var("S")]),new t.type.Term(",",[new t.type.Term("max_list",[new t.type.Var("Xs"),new t.type.Var("Y")]),new t.type.Term(";",[new t.type.Term(",",[new t.type.Term(">=",[new t.type.Var("X"),new t.type.Var("Y")]),new t.type.Term(",",[new t.type.Term("=",[new t.type.Var("S"),new t.type.Var("X")]),new t.type.Term("!",[])])]),new t.type.Term("=",[new t.type.Var("S"),new t.type.Var("Y")])])]))],"min_list/2":[new t.type.Rule(new t.type.Term("min_list",[new t.type.Term(".",[new t.type.Var("X"),new t.type.Term("[]",[])]),new t.type.Var("X")]),null),new t.type.Rule(new t.type.Term("min_list",[new t.type.Term(".",[new t.type.Var("X"),new t.type.Var("Xs")]),new t.type.Var("S")]),new t.type.Term(",",[new t.type.Term("min_list",[new t.type.Var("Xs"),new t.type.Var("Y")]),new t.type.Term(";",[new t.type.Term(",",[new t.type.Term("=<",[new t.type.Var("X"),new t.type.Var("Y")]),new t.type.Term(",",[new t.type.Term("=",[new t.type.Var("S"),new t.type.Var("X")]),new t.type.Term("!",[])])]),new t.type.Term("=",[new t.type.Var("S"),new t.type.Var("Y")])])]))],"prod_list/2":[new t.type.Rule(new t.type.Term("prod_list",[new t.type.Term("[]",[]),new t.type.Num(1,!1)]),null),new t.type.Rule(new t.type.Term("prod_list",[new t.type.Term(".",[new t.type.Var("X"),new t.type.Var("Xs")]),new t.type.Var("S")]),new t.type.Term(",",[new t.type.Term("prod_list",[new t.type.Var("Xs"),new t.type.Var("Y")]),new t.type.Term("is",[new t.type.Var("S"),new t.type.Term("*",[new t.type.Var("X"),new t.type.Var("Y")])])]))],"last/2":[new t.type.Rule(new t.type.Term("last",[new t.type.Term(".",[new t.type.Var("X"),new t.type.Term("[]",[])]),new t.type.Var("X")]),null),new t.type.Rule(new t.type.Term("last",[new t.type.Term(".",[new t.type.Var("_"),new t.type.Var("Xs")]),new t.type.Var("X")]),new t.type.Term("last",[new t.type.Var("Xs"),new t.type.Var("X")]))],"prefix/2":[new t.type.Rule(new t.type.Term("prefix",[new t.type.Var("Part"),new t.type.Var("Whole")]),new t.type.Term("append",[new t.type.Var("Part"),new t.type.Var("_"),new t.type.Var("Whole")]))],"nth0/3":[new t.type.Rule(new t.type.Term("nth0",[new t.type.Var("X"),new t.type.Var("Y"),new t.type.Var("Z")]),new t.type.Term(";",[new t.type.Term("->",[new t.type.Term("var",[new t.type.Var("X")]),new t.type.Term("nth",[new t.type.Num(0,!1),new t.type.Var("X"),new t.type.Var("Y"),new t.type.Var("Z"),new t.type.Var("_")])]),new t.type.Term(",",[new t.type.Term(">=",[new t.type.Var("X"),new t.type.Num(0,!1)]),new t.type.Term(",",[new t.type.Term("nth",[new t.type.Num(0,!1),new t.type.Var("X"),new t.type.Var("Y"),new t.type.Var("Z"),new t.type.Var("_")]),new t.type.Term("!",[])])])]))],"nth1/3":[new t.type.Rule(new t.type.Term("nth1",[new t.type.Var("X"),new t.type.Var("Y"),new t.type.Var("Z")]),new t.type.Term(";",[new t.type.Term("->",[new t.type.Term("var",[new t.type.Var("X")]),new t.type.Term("nth",[new t.type.Num(1,!1),new t.type.Var("X"),new t.type.Var("Y"),new t.type.Var("Z"),new t.type.Var("_")])]),new t.type.Term(",",[new t.type.Term(">",[new t.type.Var("X"),new t.type.Num(0,!1)]),new t.type.Term(",",[new t.type.Term("nth",[new t.type.Num(1,!1),new t.type.Var("X"),new t.type.Var("Y"),new t.type.Var("Z"),new t.type.Var("_")]),new t.type.Term("!",[])])])]))],"nth0/4":[new t.type.Rule(new t.type.Term("nth0",[new t.type.Var("X"),new t.type.Var("Y"),new t.type.Var("Z"),new t.type.Var("W")]),new t.type.Term(";",[new t.type.Term("->",[new t.type.Term("var",[new t.type.Var("X")]),new t.type.Term("nth",[new t.type.Num(0,!1),new t.type.Var("X"),new t.type.Var("Y"),new t.type.Var("Z"),new t.type.Var("W")])]),new t.type.Term(",",[new t.type.Term(">=",[new t.type.Var("X"),new t.type.Num(0,!1)]),new t.type.Term(",",[new t.type.Term("nth",[new t.type.Num(0,!1),new t.type.Var("X"),new t.type.Var("Y"),new t.type.Var("Z"),new t.type.Var("W")]),new t.type.Term("!",[])])])]))],"nth1/4":[new t.type.Rule(new t.type.Term("nth1",[new t.type.Var("X"),new t.type.Var("Y"),new t.type.Var("Z"),new t.type.Var("W")]),new t.type.Term(";",[new t.type.Term("->",[new t.type.Term("var",[new t.type.Var("X")]),new t.type.Term("nth",[new t.type.Num(1,!1),new t.type.Var("X"),new t.type.Var("Y"),new t.type.Var("Z"),new t.type.Var("W")])]),new t.type.Term(",",[new t.type.Term(">",[new t.type.Var("X"),new t.type.Num(0,!1)]),new t.type.Term(",",[new t.type.Term("nth",[new t.type.Num(1,!1),new t.type.Var("X"),new t.type.Var("Y"),new t.type.Var("Z"),new t.type.Var("W")]),new t.type.Term("!",[])])])]))],"nth/5":[new t.type.Rule(new t.type.Term("nth",[new t.type.Var("N"),new t.type.Var("N"),new t.type.Term(".",[new t.type.Var("X"),new t.type.Var("Xs")]),new t.type.Var("X"),new t.type.Var("Xs")]),null),new t.type.Rule(new t.type.Term("nth",[new t.type.Var("N"),new t.type.Var("O"),new t.type.Term(".",[new t.type.Var("X"),new t.type.Var("Xs")]),new t.type.Var("Y"),new t.type.Term(".",[new t.type.Var("X"),new t.type.Var("Ys")])]),new t.type.Term(",",[new t.type.Term("is",[new t.type.Var("M"),new t.type.Term("+",[new t.type.Var("N"),new t.type.Num(1,!1)])]),new t.type.Term("nth",[new t.type.Var("M"),new t.type.Var("O"),new t.type.Var("Xs"),new t.type.Var("Y"),new t.type.Var("Ys")])]))],"length/2":function(s,a,n){var c=n.args[0],f=n.args[1];if(!t.type.is_variable(f)&&!t.type.is_integer(f))s.throw_error(t.error.type("integer",f,n.indicator));else if(t.type.is_integer(f)&&f.value<0)s.throw_error(t.error.domain("not_less_than_zero",f,n.indicator));else{var p=new t.type.Term("length",[c,new t.type.Num(0,!1),f]);t.type.is_integer(f)&&(p=new t.type.Term(",",[p,new t.type.Term("!",[])])),s.prepend([new t.type.State(a.goal.replace(p),a.substitution,a)])}},"length/3":[new t.type.Rule(new t.type.Term("length",[new t.type.Term("[]",[]),new t.type.Var("N"),new t.type.Var("N")]),null),new t.type.Rule(new t.type.Term("length",[new t.type.Term(".",[new t.type.Var("_"),new t.type.Var("X")]),new t.type.Var("A"),new t.type.Var("N")]),new t.type.Term(",",[new t.type.Term("succ",[new t.type.Var("A"),new t.type.Var("B")]),new t.type.Term("length",[new t.type.Var("X"),new t.type.Var("B"),new t.type.Var("N")])]))],"replicate/3":function(s,a,n){var c=n.args[0],f=n.args[1],p=n.args[2];if(t.type.is_variable(f))s.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_integer(f))s.throw_error(t.error.type("integer",f,n.indicator));else if(f.value<0)s.throw_error(t.error.domain("not_less_than_zero",f,n.indicator));else if(!t.type.is_variable(p)&&!t.type.is_list(p))s.throw_error(t.error.type("list",p,n.indicator));else{for(var h=new t.type.Term("[]"),E=0;E0;C--)E[C].equals(E[C-1])&&E.splice(C,1);for(var S=new t.type.Term("[]"),C=E.length-1;C>=0;C--)S=new t.type.Term(".",[E[C],S]);s.prepend([new t.type.State(a.goal.replace(new t.type.Term("=",[S,f])),a.substitution,a)])}}},"msort/2":function(s,a,n){var c=n.args[0],f=n.args[1];if(t.type.is_variable(c))s.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_variable(f)&&!t.type.is_fully_list(f))s.throw_error(t.error.type("list",f,n.indicator));else{for(var p=[],h=c;h.indicator==="./2";)p.push(h.args[0]),h=h.args[1];if(t.type.is_variable(h))s.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_empty_list(h))s.throw_error(t.error.type("list",c,n.indicator));else{for(var E=p.sort(t.compare),C=new t.type.Term("[]"),S=E.length-1;S>=0;S--)C=new t.type.Term(".",[E[S],C]);s.prepend([new t.type.State(a.goal.replace(new t.type.Term("=",[C,f])),a.substitution,a)])}}},"keysort/2":function(s,a,n){var c=n.args[0],f=n.args[1];if(t.type.is_variable(c))s.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_variable(f)&&!t.type.is_fully_list(f))s.throw_error(t.error.type("list",f,n.indicator));else{for(var p=[],h,E=c;E.indicator==="./2";){if(h=E.args[0],t.type.is_variable(h)){s.throw_error(t.error.instantiation(n.indicator));return}else if(!t.type.is_term(h)||h.indicator!=="-/2"){s.throw_error(t.error.type("pair",h,n.indicator));return}h.args[0].pair=h.args[1],p.push(h.args[0]),E=E.args[1]}if(t.type.is_variable(E))s.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_empty_list(E))s.throw_error(t.error.type("list",c,n.indicator));else{for(var C=p.sort(t.compare),S=new t.type.Term("[]"),P=C.length-1;P>=0;P--)S=new t.type.Term(".",[new t.type.Term("-",[C[P],C[P].pair]),S]),delete C[P].pair;s.prepend([new t.type.State(a.goal.replace(new t.type.Term("=",[S,f])),a.substitution,a)])}}},"take/3":function(s,a,n){var c=n.args[0],f=n.args[1],p=n.args[2];if(t.type.is_variable(f)||t.type.is_variable(c))s.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_list(f))s.throw_error(t.error.type("list",f,n.indicator));else if(!t.type.is_integer(c))s.throw_error(t.error.type("integer",c,n.indicator));else if(!t.type.is_variable(p)&&!t.type.is_list(p))s.throw_error(t.error.type("list",p,n.indicator));else{for(var h=c.value,E=[],C=f;h>0&&C.indicator==="./2";)E.push(C.args[0]),C=C.args[1],h--;if(h===0){for(var S=new t.type.Term("[]"),h=E.length-1;h>=0;h--)S=new t.type.Term(".",[E[h],S]);s.prepend([new t.type.State(a.goal.replace(new t.type.Term("=",[S,p])),a.substitution,a)])}}},"drop/3":function(s,a,n){var c=n.args[0],f=n.args[1],p=n.args[2];if(t.type.is_variable(f)||t.type.is_variable(c))s.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_list(f))s.throw_error(t.error.type("list",f,n.indicator));else if(!t.type.is_integer(c))s.throw_error(t.error.type("integer",c,n.indicator));else if(!t.type.is_variable(p)&&!t.type.is_list(p))s.throw_error(t.error.type("list",p,n.indicator));else{for(var h=c.value,E=[],C=f;h>0&&C.indicator==="./2";)E.push(C.args[0]),C=C.args[1],h--;h===0&&s.prepend([new t.type.State(a.goal.replace(new t.type.Term("=",[C,p])),a.substitution,a)])}},"reverse/2":function(s,a,n){var c=n.args[0],f=n.args[1],p=t.type.is_instantiated_list(c),h=t.type.is_instantiated_list(f);if(t.type.is_variable(c)&&t.type.is_variable(f))s.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_variable(c)&&!t.type.is_fully_list(c))s.throw_error(t.error.type("list",c,n.indicator));else if(!t.type.is_variable(f)&&!t.type.is_fully_list(f))s.throw_error(t.error.type("list",f,n.indicator));else if(!p&&!h)s.throw_error(t.error.instantiation(n.indicator));else{for(var E=p?c:f,C=new t.type.Term("[]",[]);E.indicator==="./2";)C=new t.type.Term(".",[E.args[0],C]),E=E.args[1];s.prepend([new t.type.State(a.goal.replace(new t.type.Term("=",[C,p?f:c])),a.substitution,a)])}},"list_to_set/2":function(s,a,n){var c=n.args[0],f=n.args[1];if(t.type.is_variable(c))s.throw_error(t.error.instantiation(n.indicator));else{for(var p=c,h=[];p.indicator==="./2";)h.push(p.args[0]),p=p.args[1];if(t.type.is_variable(p))s.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_term(p)||p.indicator!=="[]/0")s.throw_error(t.error.type("list",c,n.indicator));else{for(var E=[],C=new t.type.Term("[]",[]),S,P=0;P=0;P--)C=new t.type.Term(".",[E[P],C]);s.prepend([new t.type.State(a.goal.replace(new t.type.Term("=",[f,C])),a.substitution,a)])}}}}},r=["append/2","append/3","member/2","permutation/2","maplist/2","maplist/3","maplist/4","maplist/5","maplist/6","maplist/7","maplist/8","include/3","exclude/3","foldl/4","sum_list/2","max_list/2","min_list/2","prod_list/2","last/2","prefix/2","nth0/3","nth1/3","nth0/4","nth1/4","length/2","replicate/3","select/3","sort/2","msort/2","keysort/2","take/3","drop/3","reverse/2","list_to_set/2"];typeof vq<"u"?vq.exports=function(s){t=s,new t.type.Module("lists",e(),r)}:new t.type.Module("lists",e(),r)})(qct)});var yEe=_($r=>{"use strict";var bm=process.platform==="win32",Sq="aes-256-cbc",Wct="sha256",oEe="The current environment doesn't support interactive reading from TTY.",si=Ie("fs"),iEe=process.binding("tty_wrap").TTY,bq=Ie("child_process"),V0=Ie("path"),Pq={prompt:"> ",hideEchoBack:!1,mask:"*",limit:[],limitMessage:"Input another, please.$<( [)limit(])>",defaultInput:"",trueValue:[],falseValue:[],caseSensitive:!1,keepWhitespace:!1,encoding:"utf8",bufferSize:1024,print:void 0,history:!0,cd:!1,phContent:void 0,preCheck:void 0},Xp="none",Zu,VC,sEe=!1,Y0,oF,Dq,Yct=0,Rq="",Dm=[],aF,aEe=!1,xq=!1,sS=!1;function lEe(t){function e(r){return r.replace(/[^\w\u0080-\uFFFF]/g,function(s){return"#"+s.charCodeAt(0)+";"})}return oF.concat(function(r){var s=[];return Object.keys(r).forEach(function(a){r[a]==="boolean"?t[a]&&s.push("--"+a):r[a]==="string"&&t[a]&&s.push("--"+a,e(t[a]))}),s}({display:"string",displayOnly:"boolean",keyIn:"boolean",hideEchoBack:"boolean",mask:"string",limit:"string",caseSensitive:"boolean"}))}function Vct(t,e){function r(U){var W,ee="",ie;for(Dq=Dq||Ie("os").tmpdir();;){W=V0.join(Dq,U+ee);try{ie=si.openSync(W,"wx")}catch(ue){if(ue.code==="EEXIST"){ee++;continue}else throw ue}si.closeSync(ie);break}return W}var s,a,n,c={},f,p,h=r("readline-sync.stdout"),E=r("readline-sync.stderr"),C=r("readline-sync.exit"),S=r("readline-sync.done"),P=Ie("crypto"),I,R,N;I=P.createHash(Wct),I.update(""+process.pid+Yct+++Math.random()),N=I.digest("hex"),R=P.createDecipher(Sq,N),s=lEe(t),bm?(a=process.env.ComSpec||"cmd.exe",process.env.Q='"',n=["/V:ON","/S","/C","(%Q%"+a+"%Q% /V:ON /S /C %Q%%Q%"+Y0+"%Q%"+s.map(function(U){return" %Q%"+U+"%Q%"}).join("")+" & (echo !ERRORLEVEL!)>%Q%"+C+"%Q%%Q%) 2>%Q%"+E+"%Q% |%Q%"+process.execPath+"%Q% %Q%"+__dirname+"\\encrypt.js%Q% %Q%"+Sq+"%Q% %Q%"+N+"%Q% >%Q%"+h+"%Q% & (echo 1)>%Q%"+S+"%Q%"]):(a="/bin/sh",n=["-c",'("'+Y0+'"'+s.map(function(U){return" '"+U.replace(/'/g,"'\\''")+"'"}).join("")+'; echo $?>"'+C+'") 2>"'+E+'" |"'+process.execPath+'" "'+__dirname+'/encrypt.js" "'+Sq+'" "'+N+'" >"'+h+'"; echo 1 >"'+S+'"']),sS&&sS("_execFileSync",s);try{bq.spawn(a,n,e)}catch(U){c.error=new Error(U.message),c.error.method="_execFileSync - spawn",c.error.program=a,c.error.args=n}for(;si.readFileSync(S,{encoding:t.encoding}).trim()!=="1";);return(f=si.readFileSync(C,{encoding:t.encoding}).trim())==="0"?c.input=R.update(si.readFileSync(h,{encoding:"binary"}),"hex",t.encoding)+R.final(t.encoding):(p=si.readFileSync(E,{encoding:t.encoding}).trim(),c.error=new Error(oEe+(p?` +`+p:"")),c.error.method="_execFileSync",c.error.program=a,c.error.args=n,c.error.extMessage=p,c.error.exitCode=+f),si.unlinkSync(h),si.unlinkSync(E),si.unlinkSync(C),si.unlinkSync(S),c}function Jct(t){var e,r={},s,a={env:process.env,encoding:t.encoding};if(Y0||(bm?process.env.PSModulePath?(Y0="powershell.exe",oF=["-ExecutionPolicy","Bypass","-File",__dirname+"\\read.ps1"]):(Y0="cscript.exe",oF=["//nologo",__dirname+"\\read.cs.js"]):(Y0="/bin/sh",oF=[__dirname+"/read.sh"])),bm&&!process.env.PSModulePath&&(a.stdio=[process.stdin]),bq.execFileSync){e=lEe(t),sS&&sS("execFileSync",e);try{r.input=bq.execFileSync(Y0,e,a)}catch(n){s=n.stderr?(n.stderr+"").trim():"",r.error=new Error(oEe+(s?` +`+s:"")),r.error.method="execFileSync",r.error.program=Y0,r.error.args=e,r.error.extMessage=s,r.error.exitCode=n.status,r.error.code=n.code,r.error.signal=n.signal}}else r=Vct(t,a);return r.error||(r.input=r.input.replace(/^\s*'|'\s*$/g,""),t.display=""),r}function kq(t){var e="",r=t.display,s=!t.display&&t.keyIn&&t.hideEchoBack&&!t.mask;function a(){var n=Jct(t);if(n.error)throw n.error;return n.input}return xq&&xq(t),function(){var n,c,f;function p(){return n||(n=process.binding("fs"),c=process.binding("constants")),n}if(typeof Xp=="string")if(Xp=null,bm){if(f=function(h){var E=h.replace(/^\D+/,"").split("."),C=0;return(E[0]=+E[0])&&(C+=E[0]*1e4),(E[1]=+E[1])&&(C+=E[1]*100),(E[2]=+E[2])&&(C+=E[2]),C}(process.version),!(f>=20302&&f<40204||f>=5e4&&f<50100||f>=50600&&f<60200)&&process.stdin.isTTY)process.stdin.pause(),Xp=process.stdin.fd,VC=process.stdin._handle;else try{Xp=p().open("CONIN$",c.O_RDWR,parseInt("0666",8)),VC=new iEe(Xp,!0)}catch{}if(process.stdout.isTTY)Zu=process.stdout.fd;else{try{Zu=si.openSync("\\\\.\\CON","w")}catch{}if(typeof Zu!="number")try{Zu=p().open("CONOUT$",c.O_RDWR,parseInt("0666",8))}catch{}}}else{if(process.stdin.isTTY){process.stdin.pause();try{Xp=si.openSync("/dev/tty","r"),VC=process.stdin._handle}catch{}}else try{Xp=si.openSync("/dev/tty","r"),VC=new iEe(Xp,!1)}catch{}if(process.stdout.isTTY)Zu=process.stdout.fd;else try{Zu=si.openSync("/dev/tty","w")}catch{}}}(),function(){var n,c,f=!t.hideEchoBack&&!t.keyIn,p,h,E,C,S;aF="";function P(I){return I===sEe?!0:VC.setRawMode(I)!==0?!1:(sEe=I,!0)}if(aEe||!VC||typeof Zu!="number"&&(t.display||!f)){e=a();return}if(t.display&&(si.writeSync(Zu,t.display),t.display=""),!t.displayOnly){if(!P(!f)){e=a();return}for(h=t.keyIn?1:t.bufferSize,p=Buffer.allocUnsafe&&Buffer.alloc?Buffer.alloc(h):new Buffer(h),t.keyIn&&t.limit&&(c=new RegExp("[^"+t.limit+"]","g"+(t.caseSensitive?"":"i")));;){E=0;try{E=si.readSync(Xp,p,0,h)}catch(I){if(I.code!=="EOF"){P(!1),e+=a();return}}if(E>0?(C=p.toString(t.encoding,0,E),aF+=C):(C=` +`,aF+="\0"),C&&typeof(S=(C.match(/^(.*?)[\r\n]/)||[])[1])=="string"&&(C=S,n=!0),C&&(C=C.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g,"")),C&&c&&(C=C.replace(c,"")),C&&(f||(t.hideEchoBack?t.mask&&si.writeSync(Zu,new Array(C.length+1).join(t.mask)):si.writeSync(Zu,C)),e+=C),!t.keyIn&&n||t.keyIn&&e.length>=h)break}!f&&!s&&si.writeSync(Zu,` +`),P(!1)}}(),t.print&&!s&&t.print(r+(t.displayOnly?"":(t.hideEchoBack?new Array(e.length+1).join(t.mask):e)+` +`),t.encoding),t.displayOnly?"":Rq=t.keepWhitespace||t.keyIn?e:e.trim()}function Kct(t,e){var r=[];function s(a){a!=null&&(Array.isArray(a)?a.forEach(s):(!e||e(a))&&r.push(a))}return s(t),r}function Fq(t){return t.replace(/[\x00-\x7f]/g,function(e){return"\\x"+("00"+e.charCodeAt().toString(16)).substr(-2)})}function Vs(){var t=Array.prototype.slice.call(arguments),e,r;return t.length&&typeof t[0]=="boolean"&&(r=t.shift(),r&&(e=Object.keys(Pq),t.unshift(Pq))),t.reduce(function(s,a){return a==null||(a.hasOwnProperty("noEchoBack")&&!a.hasOwnProperty("hideEchoBack")&&(a.hideEchoBack=a.noEchoBack,delete a.noEchoBack),a.hasOwnProperty("noTrim")&&!a.hasOwnProperty("keepWhitespace")&&(a.keepWhitespace=a.noTrim,delete a.noTrim),r||(e=Object.keys(a)),e.forEach(function(n){var c;if(a.hasOwnProperty(n))switch(c=a[n],n){case"mask":case"limitMessage":case"defaultInput":case"encoding":c=c!=null?c+"":"",c&&n!=="limitMessage"&&(c=c.replace(/[\r\n]/g,"")),s[n]=c;break;case"bufferSize":!isNaN(c=parseInt(c,10))&&typeof c=="number"&&(s[n]=c);break;case"displayOnly":case"keyIn":case"hideEchoBack":case"caseSensitive":case"keepWhitespace":case"history":case"cd":s[n]=!!c;break;case"limit":case"trueValue":case"falseValue":s[n]=Kct(c,function(f){var p=typeof f;return p==="string"||p==="number"||p==="function"||f instanceof RegExp}).map(function(f){return typeof f=="string"?f.replace(/[\r\n]/g,""):f});break;case"print":case"phContent":case"preCheck":s[n]=typeof c=="function"?c:void 0;break;case"prompt":case"display":s[n]=c??"";break}})),s},{})}function Qq(t,e,r){return e.some(function(s){var a=typeof s;return a==="string"?r?t===s:t.toLowerCase()===s.toLowerCase():a==="number"?parseFloat(t)===s:a==="function"?s(t):s instanceof RegExp?s.test(t):!1})}function Nq(t,e){var r=V0.normalize(bm?(process.env.HOMEDRIVE||"")+(process.env.HOMEPATH||""):process.env.HOME||"").replace(/[\/\\]+$/,"");return t=V0.normalize(t),e?t.replace(/^~(?=\/|\\|$)/,r):t.replace(new RegExp("^"+Fq(r)+"(?=\\/|\\\\|$)",bm?"i":""),"~")}function JC(t,e){var r="(?:\\(([\\s\\S]*?)\\))?(\\w+|.-.)(?:\\(([\\s\\S]*?)\\))?",s=new RegExp("(\\$)?(\\$<"+r+">)","g"),a=new RegExp("(\\$)?(\\$\\{"+r+"\\})","g");function n(c,f,p,h,E,C){var S;return f||typeof(S=e(E))!="string"?p:S?(h||"")+S+(C||""):""}return t.replace(s,n).replace(a,n)}function cEe(t,e,r){var s,a=[],n=-1,c=0,f="",p;function h(E,C){return C.length>3?(E.push(C[0]+"..."+C[C.length-1]),p=!0):C.length&&(E=E.concat(C)),E}return s=t.reduce(function(E,C){return E.concat((C+"").split(""))},[]).reduce(function(E,C){var S,P;return e||(C=C.toLowerCase()),S=/^\d$/.test(C)?1:/^[A-Z]$/.test(C)?2:/^[a-z]$/.test(C)?3:0,r&&S===0?f+=C:(P=C.charCodeAt(0),S&&S===n&&P===c+1?a.push(C):(E=h(E,a),a=[C],n=S),c=P),E},[]),s=h(s,a),f&&(s.push(f),p=!0),{values:s,suppressed:p}}function uEe(t,e){return t.join(t.length>2?", ":e?" / ":"/")}function fEe(t,e){var r,s,a={},n;if(e.phContent&&(r=e.phContent(t,e)),typeof r!="string")switch(t){case"hideEchoBack":case"mask":case"defaultInput":case"caseSensitive":case"keepWhitespace":case"encoding":case"bufferSize":case"history":case"cd":r=e.hasOwnProperty(t)?typeof e[t]=="boolean"?e[t]?"on":"off":e[t]+"":"";break;case"limit":case"trueValue":case"falseValue":s=e[e.hasOwnProperty(t+"Src")?t+"Src":t],e.keyIn?(a=cEe(s,e.caseSensitive),s=a.values):s=s.filter(function(c){var f=typeof c;return f==="string"||f==="number"}),r=uEe(s,a.suppressed);break;case"limitCount":case"limitCountNotZero":r=e[e.hasOwnProperty("limitSrc")?"limitSrc":"limit"].length,r=r||t!=="limitCountNotZero"?r+"":"";break;case"lastInput":r=Rq;break;case"cwd":case"CWD":case"cwdHome":r=process.cwd(),t==="CWD"?r=V0.basename(r):t==="cwdHome"&&(r=Nq(r));break;case"date":case"time":case"localeDate":case"localeTime":r=new Date()["to"+t.replace(/^./,function(c){return c.toUpperCase()})+"String"]();break;default:typeof(n=(t.match(/^history_m(\d+)$/)||[])[1])=="string"&&(r=Dm[Dm.length-n]||"")}return r}function AEe(t){var e=/^(.)-(.)$/.exec(t),r="",s,a,n,c;if(!e)return null;for(s=e[1].charCodeAt(0),a=e[2].charCodeAt(0),c=s +And the length must be: $`,trueValue:null,falseValue:null,caseSensitive:!0},e,{history:!1,cd:!1,phContent:function(P){return P==="charlist"?r.text:P==="length"?s+"..."+a:null}}),c,f,p,h,E,C,S;for(e=e||{},c=JC(e.charlist?e.charlist+"":"$",AEe),(isNaN(s=parseInt(e.min,10))||typeof s!="number")&&(s=12),(isNaN(a=parseInt(e.max,10))||typeof a!="number")&&(a=24),h=new RegExp("^["+Fq(c)+"]{"+s+","+a+"}$"),r=cEe([c],n.caseSensitive,!0),r.text=uEe(r.values,r.suppressed),f=e.confirmMessage!=null?e.confirmMessage:"Reinput a same one to confirm it: ",p=e.unmatchMessage!=null?e.unmatchMessage:"It differs from first one. Hit only the Enter key if you want to retry from first one.",t==null&&(t="Input new password: "),E=n.limitMessage;!S;)n.limit=h,n.limitMessage=E,C=$r.question(t,n),n.limit=[C,""],n.limitMessage=p,S=$r.question(f,n);return C};function gEe(t,e,r){var s;function a(n){return s=r(n),!isNaN(s)&&typeof s=="number"}return $r.question(t,Vs({limitMessage:"Input valid number, please."},e,{limit:a,cd:!1})),s}$r.questionInt=function(t,e){return gEe(t,e,function(r){return parseInt(r,10)})};$r.questionFloat=function(t,e){return gEe(t,e,parseFloat)};$r.questionPath=function(t,e){var r,s="",a=Vs({hideEchoBack:!1,limitMessage:`$Input valid path, please.$<( Min:)min>$<( Max:)max>`,history:!0,cd:!0},e,{keepWhitespace:!1,limit:function(n){var c,f,p;n=Nq(n,!0),s="";function h(E){E.split(/\/|\\/).reduce(function(C,S){var P=V0.resolve(C+=S+V0.sep);if(!si.existsSync(P))si.mkdirSync(P);else if(!si.statSync(P).isDirectory())throw new Error("Non directory already exists: "+P);return C},"")}try{if(c=si.existsSync(n),r=c?si.realpathSync(n):V0.resolve(n),!e.hasOwnProperty("exists")&&!c||typeof e.exists=="boolean"&&e.exists!==c)return s=(c?"Already exists":"No such file or directory")+": "+r,!1;if(!c&&e.create&&(e.isDirectory?h(r):(h(V0.dirname(r)),si.closeSync(si.openSync(r,"w"))),r=si.realpathSync(r)),c&&(e.min||e.max||e.isFile||e.isDirectory)){if(f=si.statSync(r),e.isFile&&!f.isFile())return s="Not file: "+r,!1;if(e.isDirectory&&!f.isDirectory())return s="Not directory: "+r,!1;if(e.min&&f.size<+e.min||e.max&&f.size>+e.max)return s="Size "+f.size+" is out of range: "+r,!1}if(typeof e.validate=="function"&&(p=e.validate(r))!==!0)return typeof p=="string"&&(s=p),!1}catch(E){return s=E+"",!1}return!0},phContent:function(n){return n==="error"?s:n!=="min"&&n!=="max"?null:e.hasOwnProperty(n)?e[n]+"":""}});return e=e||{},t==null&&(t='Input path (you can "cd" and "pwd"): '),$r.question(t,a),r};function dEe(t,e){var r={},s={};return typeof t=="object"?(Object.keys(t).forEach(function(a){typeof t[a]=="function"&&(s[e.caseSensitive?a:a.toLowerCase()]=t[a])}),r.preCheck=function(a){var n;return r.args=Tq(a),n=r.args[0]||"",e.caseSensitive||(n=n.toLowerCase()),r.hRes=n!=="_"&&s.hasOwnProperty(n)?s[n].apply(a,r.args.slice(1)):s.hasOwnProperty("_")?s._.apply(a,r.args):null,{res:a,forceNext:!1}},s.hasOwnProperty("_")||(r.limit=function(){var a=r.args[0]||"";return e.caseSensitive||(a=a.toLowerCase()),s.hasOwnProperty(a)})):r.preCheck=function(a){return r.args=Tq(a),r.hRes=typeof t=="function"?t.apply(a,r.args):!0,{res:a,forceNext:!1}},r}$r.promptCL=function(t,e){var r=Vs({hideEchoBack:!1,limitMessage:"Requested command is not available.",caseSensitive:!1,history:!0},e),s=dEe(t,r);return r.limit=s.limit,r.preCheck=s.preCheck,$r.prompt(r),s.args};$r.promptLoop=function(t,e){for(var r=Vs({hideEchoBack:!1,trueValue:null,falseValue:null,caseSensitive:!1,history:!0},e);!t($r.prompt(r)););};$r.promptCLLoop=function(t,e){var r=Vs({hideEchoBack:!1,limitMessage:"Requested command is not available.",caseSensitive:!1,history:!0},e),s=dEe(t,r);for(r.limit=s.limit,r.preCheck=s.preCheck;$r.prompt(r),!s.hRes;);};$r.promptSimShell=function(t){return $r.prompt(Vs({hideEchoBack:!1,history:!0},t,{prompt:function(){return bm?"$>":(process.env.USER||"")+(process.env.HOSTNAME?"@"+process.env.HOSTNAME.replace(/\..*$/,""):"")+":$$ "}()}))};function mEe(t,e,r){var s;return t==null&&(t="Are you sure? "),(!e||e.guide!==!1)&&(t+="")&&(t=t.replace(/\s*:?\s*$/,"")+" [y/n]: "),s=$r.keyIn(t,Vs(e,{hideEchoBack:!1,limit:r,trueValue:"y",falseValue:"n",caseSensitive:!1})),typeof s=="boolean"?s:""}$r.keyInYN=function(t,e){return mEe(t,e)};$r.keyInYNStrict=function(t,e){return mEe(t,e,"yn")};$r.keyInPause=function(t,e){t==null&&(t="Continue..."),(!e||e.guide!==!1)&&(t+="")&&(t=t.replace(/\s+$/,"")+" (Hit any key)"),$r.keyIn(t,Vs({limit:null},e,{hideEchoBack:!0,mask:""}))};$r.keyInSelect=function(t,e,r){var s=Vs({hideEchoBack:!1},r,{trueValue:null,falseValue:null,caseSensitive:!1,phContent:function(p){return p==="itemsCount"?t.length+"":p==="firstItem"?(t[0]+"").trim():p==="lastItem"?(t[t.length-1]+"").trim():null}}),a="",n={},c=49,f=` +`;if(!Array.isArray(t)||!t.length||t.length>35)throw"`items` must be Array (max length: 35).";return t.forEach(function(p,h){var E=String.fromCharCode(c);a+=E,n[E]=h,f+="["+E+"] "+(p+"").trim()+` +`,c=c===57?97:c+1}),(!r||r.cancel!==!1)&&(a+="0",n[0]=-1,f+="[0] "+(r&&r.cancel!=null&&typeof r.cancel!="boolean"?(r.cancel+"").trim():"CANCEL")+` +`),s.limit=a,f+=` +`,e==null&&(e="Choose one from list: "),(e+="")&&((!r||r.guide!==!1)&&(e=e.replace(/\s*:?\s*$/,"")+" [$]: "),f+=e),n[$r.keyIn(f,s).toLowerCase()]};$r.getRawInput=function(){return aF};function oS(t,e){var r;return e.length&&(r={},r[t]=e[0]),$r.setDefaultOptions(r)[t]}$r.setPrint=function(){return oS("print",arguments)};$r.setPrompt=function(){return oS("prompt",arguments)};$r.setEncoding=function(){return oS("encoding",arguments)};$r.setMask=function(){return oS("mask",arguments)};$r.setBufferSize=function(){return oS("bufferSize",arguments)}});var Oq=_((jYt,ec)=>{(function(){var t={major:0,minor:2,patch:66,status:"beta"};tau_file_system={files:{},open:function(w,b,y){var F=tau_file_system.files[w];if(!F){if(y==="read")return null;F={path:w,text:"",type:b,get:function(z,X){return X===this.text.length||X>this.text.length?"end_of_file":this.text.substring(X,X+z)},put:function(z,X){return X==="end_of_file"?(this.text+=z,!0):X==="past_end_of_file"?null:(this.text=this.text.substring(0,X)+z+this.text.substring(X+z.length),!0)},get_byte:function(z){if(z==="end_of_stream")return-1;var X=Math.floor(z/2);if(this.text.length<=X)return-1;var $=n(this.text[Math.floor(z/2)],0);return z%2===0?$&255:$/256>>>0},put_byte:function(z,X){var $=X==="end_of_stream"?this.text.length:Math.floor(X/2);if(this.text.length<$)return null;var oe=this.text.length===$?-1:n(this.text[Math.floor(X/2)],0);return X%2===0?(oe=oe/256>>>0,oe=(oe&255)<<8|z&255):(oe=oe&255,oe=(z&255)<<8|oe&255),this.text.length===$?this.text+=c(oe):this.text=this.text.substring(0,$)+c(oe)+this.text.substring($+1),!0},flush:function(){return!0},close:function(){var z=tau_file_system.files[this.path];return z?!0:null}},tau_file_system.files[w]=F}return y==="write"&&(F.text=""),F}},tau_user_input={buffer:"",get:function(w,b){for(var y;tau_user_input.buffer.length\?\@\^\~\\]+|'(?:[^']*?(?:\\(?:x?\d+)?\\)*(?:'')*(?:\\')*)*')/,number:/^(?:0o[0-7]+|0x[0-9a-fA-F]+|0b[01]+|0'(?:''|\\[abfnrtv\\'"`]|\\x?\d+\\|[^\\])|\d+(?:\.\d+(?:[eE][+-]?\d+)?)?)/,string:/^(?:"([^"]|""|\\")*"|`([^`]|``|\\`)*`)/,l_brace:/^(?:\[)/,r_brace:/^(?:\])/,l_bracket:/^(?:\{)/,r_bracket:/^(?:\})/,bar:/^(?:\|)/,l_paren:/^(?:\()/,r_paren:/^(?:\))/};function N(w,b){return w.get_flag("char_conversion").id==="on"?b.replace(/./g,function(y){return w.get_char_conversion(y)}):b}function U(w){this.thread=w,this.text="",this.tokens=[]}U.prototype.set_last_tokens=function(w){return this.tokens=w},U.prototype.new_text=function(w){this.text=w,this.tokens=[]},U.prototype.get_tokens=function(w){var b,y=0,F=0,z=0,X=[],$=!1;if(w){var oe=this.tokens[w-1];y=oe.len,b=N(this.thread,this.text.substr(oe.len)),F=oe.line,z=oe.start}else b=this.text;if(/^\s*$/.test(b))return null;for(;b!=="";){var xe=[],Te=!1;if(/^\n/.exec(b)!==null){F++,z=0,y++,b=b.replace(/\n/,""),$=!0;continue}for(var lt in R)if(R.hasOwnProperty(lt)){var Ct=R[lt].exec(b);Ct&&xe.push({value:Ct[0],name:lt,matches:Ct})}if(!xe.length)return this.set_last_tokens([{value:b,matches:[],name:"lexical",line:F,start:z}]);var oe=r(xe,function(Pr,Ir){return Pr.value.length>=Ir.value.length?Pr:Ir});switch(oe.start=z,oe.line=F,b=b.replace(oe.value,""),z+=oe.value.length,y+=oe.value.length,oe.name){case"atom":oe.raw=oe.value,oe.value.charAt(0)==="'"&&(oe.value=S(oe.value.substr(1,oe.value.length-2),"'"),oe.value===null&&(oe.name="lexical",oe.value="unknown escape sequence"));break;case"number":oe.float=oe.value.substring(0,2)!=="0x"&&oe.value.match(/[.eE]/)!==null&&oe.value!=="0'.",oe.value=I(oe.value),oe.blank=Te;break;case"string":var qt=oe.value.charAt(0);oe.value=S(oe.value.substr(1,oe.value.length-2),qt),oe.value===null&&(oe.name="lexical",oe.value="unknown escape sequence");break;case"whitespace":var ir=X[X.length-1];ir&&(ir.space=!0),Te=!0;continue;case"r_bracket":X.length>0&&X[X.length-1].name==="l_bracket"&&(oe=X.pop(),oe.name="atom",oe.value="{}",oe.raw="{}",oe.space=!1);break;case"r_brace":X.length>0&&X[X.length-1].name==="l_brace"&&(oe=X.pop(),oe.name="atom",oe.value="[]",oe.raw="[]",oe.space=!1);break}oe.len=y,X.push(oe),Te=!1}var Pt=this.set_last_tokens(X);return Pt.length===0?null:Pt};function W(w,b,y,F,z){if(!b[y])return{type:f,value:x.error.syntax(b[y-1],"expression expected",!0)};var X;if(F==="0"){var $=b[y];switch($.name){case"number":return{type:p,len:y+1,value:new x.type.Num($.value,$.float)};case"variable":return{type:p,len:y+1,value:new x.type.Var($.value)};case"string":var oe;switch(w.get_flag("double_quotes").id){case"atom":oe=new j($.value,[]);break;case"codes":oe=new j("[]",[]);for(var xe=$.value.length-1;xe>=0;xe--)oe=new j(".",[new x.type.Num(n($.value,xe),!1),oe]);break;case"chars":oe=new j("[]",[]);for(var xe=$.value.length-1;xe>=0;xe--)oe=new j(".",[new x.type.Term($.value.charAt(xe),[]),oe]);break}return{type:p,len:y+1,value:oe};case"l_paren":var Pt=W(w,b,y+1,w.__get_max_priority(),!0);return Pt.type!==p?Pt:b[Pt.len]&&b[Pt.len].name==="r_paren"?(Pt.len++,Pt):{type:f,derived:!0,value:x.error.syntax(b[Pt.len]?b[Pt.len]:b[Pt.len-1],") or operator expected",!b[Pt.len])};case"l_bracket":var Pt=W(w,b,y+1,w.__get_max_priority(),!0);return Pt.type!==p?Pt:b[Pt.len]&&b[Pt.len].name==="r_bracket"?(Pt.len++,Pt.value=new j("{}",[Pt.value]),Pt):{type:f,derived:!0,value:x.error.syntax(b[Pt.len]?b[Pt.len]:b[Pt.len-1],"} or operator expected",!b[Pt.len])}}var Te=ee(w,b,y,z);return Te.type===p||Te.derived||(Te=ie(w,b,y),Te.type===p||Te.derived)?Te:{type:f,derived:!1,value:x.error.syntax(b[y],"unexpected token")}}var lt=w.__get_max_priority(),Ct=w.__get_next_priority(F),qt=y;if(b[y].name==="atom"&&b[y+1]&&(b[y].space||b[y+1].name!=="l_paren")){var $=b[y++],ir=w.__lookup_operator_classes(F,$.value);if(ir&&ir.indexOf("fy")>-1){var Pt=W(w,b,y,F,z);if(Pt.type!==f)return $.value==="-"&&!$.space&&x.type.is_number(Pt.value)?{value:new x.type.Num(-Pt.value.value,Pt.value.is_float),len:Pt.len,type:p}:{value:new x.type.Term($.value,[Pt.value]),len:Pt.len,type:p};X=Pt}else if(ir&&ir.indexOf("fx")>-1){var Pt=W(w,b,y,Ct,z);if(Pt.type!==f)return{value:new x.type.Term($.value,[Pt.value]),len:Pt.len,type:p};X=Pt}}y=qt;var Pt=W(w,b,y,Ct,z);if(Pt.type===p){y=Pt.len;var $=b[y];if(b[y]&&(b[y].name==="atom"&&w.__lookup_operator_classes(F,$.value)||b[y].name==="bar"&&w.__lookup_operator_classes(F,"|"))){var gn=Ct,Pr=F,ir=w.__lookup_operator_classes(F,$.value);if(ir.indexOf("xf")>-1)return{value:new x.type.Term($.value,[Pt.value]),len:++Pt.len,type:p};if(ir.indexOf("xfx")>-1){var Ir=W(w,b,y+1,gn,z);return Ir.type===p?{value:new x.type.Term($.value,[Pt.value,Ir.value]),len:Ir.len,type:p}:(Ir.derived=!0,Ir)}else if(ir.indexOf("xfy")>-1){var Ir=W(w,b,y+1,Pr,z);return Ir.type===p?{value:new x.type.Term($.value,[Pt.value,Ir.value]),len:Ir.len,type:p}:(Ir.derived=!0,Ir)}else if(Pt.type!==f)for(;;){y=Pt.len;var $=b[y];if($&&$.name==="atom"&&w.__lookup_operator_classes(F,$.value)){var ir=w.__lookup_operator_classes(F,$.value);if(ir.indexOf("yf")>-1)Pt={value:new x.type.Term($.value,[Pt.value]),len:++y,type:p};else if(ir.indexOf("yfx")>-1){var Ir=W(w,b,++y,gn,z);if(Ir.type===f)return Ir.derived=!0,Ir;y=Ir.len,Pt={value:new x.type.Term($.value,[Pt.value,Ir.value]),len:y,type:p}}else break}else break}}else X={type:f,value:x.error.syntax(b[Pt.len-1],"operator expected")};return Pt}return Pt}function ee(w,b,y,F){if(!b[y]||b[y].name==="atom"&&b[y].raw==="."&&!F&&(b[y].space||!b[y+1]||b[y+1].name!=="l_paren"))return{type:f,derived:!1,value:x.error.syntax(b[y-1],"unfounded token")};var z=b[y],X=[];if(b[y].name==="atom"&&b[y].raw!==","){if(y++,b[y-1].space)return{type:p,len:y,value:new x.type.Term(z.value,X)};if(b[y]&&b[y].name==="l_paren"){if(b[y+1]&&b[y+1].name==="r_paren")return{type:f,derived:!0,value:x.error.syntax(b[y+1],"argument expected")};var $=W(w,b,++y,"999",!0);if($.type===f)return $.derived?$:{type:f,derived:!0,value:x.error.syntax(b[y]?b[y]:b[y-1],"argument expected",!b[y])};for(X.push($.value),y=$.len;b[y]&&b[y].name==="atom"&&b[y].value===",";){if($=W(w,b,y+1,"999",!0),$.type===f)return $.derived?$:{type:f,derived:!0,value:x.error.syntax(b[y+1]?b[y+1]:b[y],"argument expected",!b[y+1])};X.push($.value),y=$.len}if(b[y]&&b[y].name==="r_paren")y++;else return{type:f,derived:!0,value:x.error.syntax(b[y]?b[y]:b[y-1],", or ) expected",!b[y])}}return{type:p,len:y,value:new x.type.Term(z.value,X)}}return{type:f,derived:!1,value:x.error.syntax(b[y],"term expected")}}function ie(w,b,y){if(!b[y])return{type:f,derived:!1,value:x.error.syntax(b[y-1],"[ expected")};if(b[y]&&b[y].name==="l_brace"){var F=W(w,b,++y,"999",!0),z=[F.value],X=void 0;if(F.type===f)return b[y]&&b[y].name==="r_brace"?{type:p,len:y+1,value:new x.type.Term("[]",[])}:{type:f,derived:!0,value:x.error.syntax(b[y],"] expected")};for(y=F.len;b[y]&&b[y].name==="atom"&&b[y].value===",";){if(F=W(w,b,y+1,"999",!0),F.type===f)return F.derived?F:{type:f,derived:!0,value:x.error.syntax(b[y+1]?b[y+1]:b[y],"argument expected",!b[y+1])};z.push(F.value),y=F.len}var $=!1;if(b[y]&&b[y].name==="bar"){if($=!0,F=W(w,b,y+1,"999",!0),F.type===f)return F.derived?F:{type:f,derived:!0,value:x.error.syntax(b[y+1]?b[y+1]:b[y],"argument expected",!b[y+1])};X=F.value,y=F.len}return b[y]&&b[y].name==="r_brace"?{type:p,len:y+1,value:g(z,X)}:{type:f,derived:!0,value:x.error.syntax(b[y]?b[y]:b[y-1],$?"] expected":", or | or ] expected",!b[y])}}return{type:f,derived:!1,value:x.error.syntax(b[y],"list expected")}}function ue(w,b,y){var F=b[y].line,z=W(w,b,y,w.__get_max_priority(),!1),X=null,$;if(z.type!==f)if(y=z.len,b[y]&&b[y].name==="atom"&&b[y].raw===".")if(y++,x.type.is_term(z.value)){if(z.value.indicator===":-/2"?(X=new x.type.Rule(z.value.args[0],Ce(z.value.args[1])),$={value:X,len:y,type:p}):z.value.indicator==="-->/2"?(X=pe(new x.type.Rule(z.value.args[0],z.value.args[1]),w),X.body=Ce(X.body),$={value:X,len:y,type:x.type.is_rule(X)?p:f}):(X=new x.type.Rule(z.value,null),$={value:X,len:y,type:p}),X){var oe=X.singleton_variables();oe.length>0&&w.throw_warning(x.warning.singleton(oe,X.head.indicator,F))}return $}else return{type:f,value:x.error.syntax(b[y],"callable expected")};else return{type:f,value:x.error.syntax(b[y]?b[y]:b[y-1],". or operator expected")};return z}function le(w,b,y){y=y||{},y.from=y.from?y.from:"$tau-js",y.reconsult=y.reconsult!==void 0?y.reconsult:!0;var F=new U(w),z={},X;F.new_text(b);var $=0,oe=F.get_tokens($);do{if(oe===null||!oe[$])break;var xe=ue(w,oe,$);if(xe.type===f)return new j("throw",[xe.value]);if(xe.value.body===null&&xe.value.head.indicator==="?-/1"){var Te=new it(w.session);Te.add_goal(xe.value.head.args[0]),Te.answer(function(Ct){x.type.is_error(Ct)?w.throw_warning(Ct.args[0]):(Ct===!1||Ct===null)&&w.throw_warning(x.warning.failed_goal(xe.value.head.args[0],xe.len))}),$=xe.len;var lt=!0}else if(xe.value.body===null&&xe.value.head.indicator===":-/1"){var lt=w.run_directive(xe.value.head.args[0]);$=xe.len,xe.value.head.args[0].indicator==="char_conversion/2"&&(oe=F.get_tokens($),$=0)}else{X=xe.value.head.indicator,y.reconsult!==!1&&z[X]!==!0&&!w.is_multifile_predicate(X)&&(w.session.rules[X]=a(w.session.rules[X]||[],function(qt){return qt.dynamic}),z[X]=!0);var lt=w.add_rule(xe.value,y);$=xe.len}if(!lt)return lt}while(!0);return!0}function me(w,b){var y=new U(w);y.new_text(b);var F=0;do{var z=y.get_tokens(F);if(z===null)break;var X=W(w,z,0,w.__get_max_priority(),!1);if(X.type!==f){var $=X.len,oe=$;if(z[$]&&z[$].name==="atom"&&z[$].raw===".")w.add_goal(Ce(X.value));else{var xe=z[$];return new j("throw",[x.error.syntax(xe||z[$-1],". or operator expected",!xe)])}F=X.len+1}else return new j("throw",[X.value])}while(!0);return!0}function pe(w,b){w=w.rename(b);var y=b.next_free_variable(),F=Be(w.body,y,b);return F.error?F.value:(w.body=F.value,w.head.args=w.head.args.concat([y,F.variable]),w.head=new j(w.head.id,w.head.args),w)}function Be(w,b,y){var F;if(x.type.is_term(w)&&w.indicator==="!/0")return{value:w,variable:b,error:!1};if(x.type.is_term(w)&&w.indicator===",/2"){var z=Be(w.args[0],b,y);if(z.error)return z;var X=Be(w.args[1],z.variable,y);return X.error?X:{value:new j(",",[z.value,X.value]),variable:X.variable,error:!1}}else{if(x.type.is_term(w)&&w.indicator==="{}/1")return{value:w.args[0],variable:b,error:!1};if(x.type.is_empty_list(w))return{value:new j("true",[]),variable:b,error:!1};if(x.type.is_list(w)){F=y.next_free_variable();for(var $=w,oe;$.indicator==="./2";)oe=$,$=$.args[1];return x.type.is_variable($)?{value:x.error.instantiation("DCG"),variable:b,error:!0}:x.type.is_empty_list($)?(oe.args[1]=F,{value:new j("=",[b,w]),variable:F,error:!1}):{value:x.error.type("list",w,"DCG"),variable:b,error:!0}}else return x.type.is_callable(w)?(F=y.next_free_variable(),w.args=w.args.concat([b,F]),w=new j(w.id,w.args),{value:w,variable:F,error:!1}):{value:x.error.type("callable",w,"DCG"),variable:b,error:!0}}}function Ce(w){return x.type.is_variable(w)?new j("call",[w]):x.type.is_term(w)&&[",/2",";/2","->/2"].indexOf(w.indicator)!==-1?new j(w.id,[Ce(w.args[0]),Ce(w.args[1])]):w}function g(w,b){for(var y=b||new x.type.Term("[]",[]),F=w.length-1;F>=0;F--)y=new x.type.Term(".",[w[F],y]);return y}function we(w,b){for(var y=w.length-1;y>=0;y--)w[y]===b&&w.splice(y,1)}function ye(w){for(var b={},y=[],F=0;F=0;b--)if(w.charAt(b)==="/")return new j("/",[new j(w.substring(0,b)),new Re(parseInt(w.substring(b+1)),!1)])}function De(w){this.id=w}function Re(w,b){this.is_float=b!==void 0?b:parseInt(w)!==w,this.value=this.is_float?w:parseInt(w)}var mt=0;function j(w,b,y){this.ref=y||++mt,this.id=w,this.args=b||[],this.indicator=w+"/"+this.args.length}var rt=0;function Fe(w,b,y,F,z,X){this.id=rt++,this.stream=w,this.mode=b,this.alias=y,this.type=F!==void 0?F:"text",this.reposition=z!==void 0?z:!0,this.eof_action=X!==void 0?X:"eof_code",this.position=this.mode==="append"?"end_of_stream":0,this.output=this.mode==="write"||this.mode==="append",this.input=this.mode==="read"}function Ne(w){w=w||{},this.links=w}function Pe(w,b,y){b=b||new Ne,y=y||null,this.goal=w,this.substitution=b,this.parent=y}function Ve(w,b,y){this.head=w,this.body=b,this.dynamic=y||!1}function ke(w){w=w===void 0||w<=0?1e3:w,this.rules={},this.src_predicates={},this.rename=0,this.modules=[],this.thread=new it(this),this.total_threads=1,this.renamed_variables={},this.public_predicates={},this.multifile_predicates={},this.limit=w,this.streams={user_input:new Fe(typeof ec<"u"&&ec.exports?nodejs_user_input:tau_user_input,"read","user_input","text",!1,"reset"),user_output:new Fe(typeof ec<"u"&&ec.exports?nodejs_user_output:tau_user_output,"write","user_output","text",!1,"eof_code")},this.file_system=typeof ec<"u"&&ec.exports?nodejs_file_system:tau_file_system,this.standard_input=this.streams.user_input,this.standard_output=this.streams.user_output,this.current_input=this.streams.user_input,this.current_output=this.streams.user_output,this.format_success=function(b){return b.substitution},this.format_error=function(b){return b.goal},this.flag={bounded:x.flag.bounded.value,max_integer:x.flag.max_integer.value,min_integer:x.flag.min_integer.value,integer_rounding_function:x.flag.integer_rounding_function.value,char_conversion:x.flag.char_conversion.value,debug:x.flag.debug.value,max_arity:x.flag.max_arity.value,unknown:x.flag.unknown.value,double_quotes:x.flag.double_quotes.value,occurs_check:x.flag.occurs_check.value,dialect:x.flag.dialect.value,version_data:x.flag.version_data.value,nodejs:x.flag.nodejs.value},this.__loaded_modules=[],this.__char_conversion={},this.__operators={1200:{":-":["fx","xfx"],"-->":["xfx"],"?-":["fx"]},1100:{";":["xfy"]},1050:{"->":["xfy"]},1e3:{",":["xfy"]},900:{"\\+":["fy"]},700:{"=":["xfx"],"\\=":["xfx"],"==":["xfx"],"\\==":["xfx"],"@<":["xfx"],"@=<":["xfx"],"@>":["xfx"],"@>=":["xfx"],"=..":["xfx"],is:["xfx"],"=:=":["xfx"],"=\\=":["xfx"],"<":["xfx"],"=<":["xfx"],">":["xfx"],">=":["xfx"]},600:{":":["xfy"]},500:{"+":["yfx"],"-":["yfx"],"/\\":["yfx"],"\\/":["yfx"]},400:{"*":["yfx"],"/":["yfx"],"//":["yfx"],rem:["yfx"],mod:["yfx"],"<<":["yfx"],">>":["yfx"]},200:{"**":["xfx"],"^":["xfy"],"-":["fy"],"+":["fy"],"\\":["fy"]}}}function it(w){this.epoch=Date.now(),this.session=w,this.session.total_threads++,this.total_steps=0,this.cpu_time=0,this.cpu_time_last=0,this.points=[],this.debugger=!1,this.debugger_states=[],this.level="top_level/0",this.__calls=[],this.current_limit=this.session.limit,this.warnings=[]}function Ue(w,b,y){this.id=w,this.rules=b,this.exports=y,x.module[w]=this}Ue.prototype.exports_predicate=function(w){return this.exports.indexOf(w)!==-1},De.prototype.unify=function(w,b){if(b&&e(w.variables(),this.id)!==-1&&!x.type.is_variable(w))return null;var y={};return y[this.id]=w,new Ne(y)},Re.prototype.unify=function(w,b){return x.type.is_number(w)&&this.value===w.value&&this.is_float===w.is_float?new Ne:null},j.prototype.unify=function(w,b){if(x.type.is_term(w)&&this.indicator===w.indicator){for(var y=new Ne,F=0;F=0){var F=this.args[0].value,z=Math.floor(F/26),X=F%26;return"ABCDEFGHIJKLMNOPQRSTUVWXYZ"[X]+(z!==0?z:"")}switch(this.indicator){case"[]/0":case"{}/0":case"!/0":return this.id;case"{}/1":return"{"+this.args[0].toString(w)+"}";case"./2":for(var $="["+this.args[0].toString(w),oe=this.args[1];oe.indicator==="./2";)$+=", "+oe.args[0].toString(w),oe=oe.args[1];return oe.indicator!=="[]/0"&&($+="|"+oe.toString(w)),$+="]",$;case",/2":return"("+this.args[0].toString(w)+", "+this.args[1].toString(w)+")";default:var xe=this.id,Te=w.session?w.session.lookup_operator(this.id,this.args.length):null;if(w.session===void 0||w.ignore_ops||Te===null)return w.quoted&&!/^(!|,|;|[a-z][0-9a-zA-Z_]*)$/.test(xe)&&xe!=="{}"&&xe!=="[]"&&(xe="'"+P(xe)+"'"),xe+(this.args.length?"("+s(this.args,function(ir){return ir.toString(w)}).join(", ")+")":"");var lt=Te.priority>b.priority||Te.priority===b.priority&&(Te.class==="xfy"&&this.indicator!==b.indicator||Te.class==="yfx"&&this.indicator!==b.indicator||this.indicator===b.indicator&&Te.class==="yfx"&&y==="right"||this.indicator===b.indicator&&Te.class==="xfy"&&y==="left");Te.indicator=this.indicator;var Ct=lt?"(":"",qt=lt?")":"";return this.args.length===0?"("+this.id+")":["fy","fx"].indexOf(Te.class)!==-1?Ct+xe+" "+this.args[0].toString(w,Te)+qt:["yf","xf"].indexOf(Te.class)!==-1?Ct+this.args[0].toString(w,Te)+" "+xe+qt:Ct+this.args[0].toString(w,Te,"left")+" "+this.id+" "+this.args[1].toString(w,Te,"right")+qt}},Fe.prototype.toString=function(w){return"("+this.id+")"},Ne.prototype.toString=function(w){var b="{";for(var y in this.links)this.links.hasOwnProperty(y)&&(b!=="{"&&(b+=", "),b+=y+"/"+this.links[y].toString(w));return b+="}",b},Pe.prototype.toString=function(w){return this.goal===null?"<"+this.substitution.toString(w)+">":"<"+this.goal.toString(w)+", "+this.substitution.toString(w)+">"},Ve.prototype.toString=function(w){return this.body?this.head.toString(w)+" :- "+this.body.toString(w)+".":this.head.toString(w)+"."},ke.prototype.toString=function(w){for(var b="",y=0;y=0;z--)F=new j(".",[b[z],F]);return F}return new j(this.id,s(this.args,function(X){return X.apply(w)}),this.ref)},Fe.prototype.apply=function(w){return this},Ve.prototype.apply=function(w){return new Ve(this.head.apply(w),this.body!==null?this.body.apply(w):null)},Ne.prototype.apply=function(w){var b,y={};for(b in this.links)this.links.hasOwnProperty(b)&&(y[b]=this.links[b].apply(w));return new Ne(y)},j.prototype.select=function(){for(var w=this;w.indicator===",/2";)w=w.args[0];return w},j.prototype.replace=function(w){return this.indicator===",/2"?this.args[0].indicator===",/2"?new j(",",[this.args[0].replace(w),this.args[1]]):w===null?this.args[1]:new j(",",[w,this.args[1]]):w},j.prototype.search=function(w){if(x.type.is_term(w)&&w.ref!==void 0&&this.ref===w.ref)return!0;for(var b=0;bb&&F0&&(b=this.head_point().substitution.domain());e(b,x.format_variable(this.session.rename))!==-1;)this.session.rename++;if(w.id==="_")return new De(x.format_variable(this.session.rename));this.session.renamed_variables[w.id]=x.format_variable(this.session.rename)}return new De(this.session.renamed_variables[w.id])},ke.prototype.next_free_variable=function(){return this.thread.next_free_variable()},it.prototype.next_free_variable=function(){this.session.rename++;var w=[];for(this.points.length>0&&(w=this.head_point().substitution.domain());e(w,x.format_variable(this.session.rename))!==-1;)this.session.rename++;return new De(x.format_variable(this.session.rename))},ke.prototype.is_public_predicate=function(w){return!this.public_predicates.hasOwnProperty(w)||this.public_predicates[w]===!0},it.prototype.is_public_predicate=function(w){return this.session.is_public_predicate(w)},ke.prototype.is_multifile_predicate=function(w){return this.multifile_predicates.hasOwnProperty(w)&&this.multifile_predicates[w]===!0},it.prototype.is_multifile_predicate=function(w){return this.session.is_multifile_predicate(w)},ke.prototype.prepend=function(w){return this.thread.prepend(w)},it.prototype.prepend=function(w){for(var b=w.length-1;b>=0;b--)this.points.push(w[b])},ke.prototype.success=function(w,b){return this.thread.success(w,b)},it.prototype.success=function(w,y){var y=typeof y>"u"?w:y;this.prepend([new Pe(w.goal.replace(null),w.substitution,y)])},ke.prototype.throw_error=function(w){return this.thread.throw_error(w)},it.prototype.throw_error=function(w){this.prepend([new Pe(new j("throw",[w]),new Ne,null,null)])},ke.prototype.step_rule=function(w,b){return this.thread.step_rule(w,b)},it.prototype.step_rule=function(w,b){var y=b.indicator;if(w==="user"&&(w=null),w===null&&this.session.rules.hasOwnProperty(y))return this.session.rules[y];for(var F=w===null?this.session.modules:e(this.session.modules,w)===-1?[]:[w],z=0;z1)&&this.again()},ke.prototype.answers=function(w,b,y){return this.thread.answers(w,b,y)},it.prototype.answers=function(w,b,y){var F=b||1e3,z=this;if(b<=0){y&&y();return}this.answer(function(X){w(X),X!==!1?setTimeout(function(){z.answers(w,b-1,y)},1):y&&y()})},ke.prototype.again=function(w){return this.thread.again(w)},it.prototype.again=function(w){for(var b,y=Date.now();this.__calls.length>0;){for(this.warnings=[],w!==!1&&(this.current_limit=this.session.limit);this.current_limit>0&&this.points.length>0&&this.head_point().goal!==null&&!x.type.is_error(this.head_point().goal);)if(this.current_limit--,this.step()===!0)return;var F=Date.now();this.cpu_time_last=F-y,this.cpu_time+=this.cpu_time_last;var z=this.__calls.shift();this.current_limit<=0?z(null):this.points.length===0?z(!1):x.type.is_error(this.head_point().goal)?(b=this.session.format_error(this.points.pop()),this.points=[],z(b)):(this.debugger&&this.debugger_states.push(this.head_point()),b=this.session.format_success(this.points.pop()),z(b))}},ke.prototype.unfold=function(w){if(w.body===null)return!1;var b=w.head,y=w.body,F=y.select(),z=new it(this),X=[];z.add_goal(F),z.step();for(var $=z.points.length-1;$>=0;$--){var oe=z.points[$],xe=b.apply(oe.substitution),Te=y.replace(oe.goal);Te!==null&&(Te=Te.apply(oe.substitution)),X.push(new Ve(xe,Te))}var lt=this.rules[b.indicator],Ct=e(lt,w);return X.length>0&&Ct!==-1?(lt.splice.apply(lt,[Ct,1].concat(X)),!0):!1},it.prototype.unfold=function(w){return this.session.unfold(w)},De.prototype.interpret=function(w){return x.error.instantiation(w.level)},Re.prototype.interpret=function(w){return this},j.prototype.interpret=function(w){return x.type.is_unitary_list(this)?this.args[0].interpret(w):x.operate(w,this)},De.prototype.compare=function(w){return this.idw.id?1:0},Re.prototype.compare=function(w){if(this.value===w.value&&this.is_float===w.is_float)return 0;if(this.valuew.value)return 1},j.prototype.compare=function(w){if(this.args.lengthw.args.length||this.args.length===w.args.length&&this.id>w.id)return 1;for(var b=0;bF)return 1;if(w.constructor===Re){if(w.is_float&&b.is_float)return 0;if(w.is_float)return-1;if(b.is_float)return 1}return 0},is_substitution:function(w){return w instanceof Ne},is_state:function(w){return w instanceof Pe},is_rule:function(w){return w instanceof Ve},is_variable:function(w){return w instanceof De},is_stream:function(w){return w instanceof Fe},is_anonymous_var:function(w){return w instanceof De&&w.id==="_"},is_callable:function(w){return w instanceof j},is_number:function(w){return w instanceof Re},is_integer:function(w){return w instanceof Re&&!w.is_float},is_float:function(w){return w instanceof Re&&w.is_float},is_term:function(w){return w instanceof j},is_atom:function(w){return w instanceof j&&w.args.length===0},is_ground:function(w){if(w instanceof De)return!1;if(w instanceof j){for(var b=0;b0},is_list:function(w){return w instanceof j&&(w.indicator==="[]/0"||w.indicator==="./2")},is_empty_list:function(w){return w instanceof j&&w.indicator==="[]/0"},is_non_empty_list:function(w){return w instanceof j&&w.indicator==="./2"},is_fully_list:function(w){for(;w instanceof j&&w.indicator==="./2";)w=w.args[1];return w instanceof De||w instanceof j&&w.indicator==="[]/0"},is_instantiated_list:function(w){for(;w instanceof j&&w.indicator==="./2";)w=w.args[1];return w instanceof j&&w.indicator==="[]/0"},is_unitary_list:function(w){return w instanceof j&&w.indicator==="./2"&&w.args[1]instanceof j&&w.args[1].indicator==="[]/0"},is_character:function(w){return w instanceof j&&(w.id.length===1||w.id.length>0&&w.id.length<=2&&n(w.id,0)>=65536)},is_character_code:function(w){return w instanceof Re&&!w.is_float&&w.value>=0&&w.value<=1114111},is_byte:function(w){return w instanceof Re&&!w.is_float&&w.value>=0&&w.value<=255},is_operator:function(w){return w instanceof j&&x.arithmetic.evaluation[w.indicator]},is_directive:function(w){return w instanceof j&&x.directive[w.indicator]!==void 0},is_builtin:function(w){return w instanceof j&&x.predicate[w.indicator]!==void 0},is_error:function(w){return w instanceof j&&w.indicator==="throw/1"},is_predicate_indicator:function(w){return w instanceof j&&w.indicator==="//2"&&w.args[0]instanceof j&&w.args[0].args.length===0&&w.args[1]instanceof Re&&w.args[1].is_float===!1},is_flag:function(w){return w instanceof j&&w.args.length===0&&x.flag[w.id]!==void 0},is_value_flag:function(w,b){if(!x.type.is_flag(w))return!1;for(var y in x.flag[w.id].allowed)if(x.flag[w.id].allowed.hasOwnProperty(y)&&x.flag[w.id].allowed[y].equals(b))return!0;return!1},is_io_mode:function(w){return x.type.is_atom(w)&&["read","write","append"].indexOf(w.id)!==-1},is_stream_option:function(w){return x.type.is_term(w)&&(w.indicator==="alias/1"&&x.type.is_atom(w.args[0])||w.indicator==="reposition/1"&&x.type.is_atom(w.args[0])&&(w.args[0].id==="true"||w.args[0].id==="false")||w.indicator==="type/1"&&x.type.is_atom(w.args[0])&&(w.args[0].id==="text"||w.args[0].id==="binary")||w.indicator==="eof_action/1"&&x.type.is_atom(w.args[0])&&(w.args[0].id==="error"||w.args[0].id==="eof_code"||w.args[0].id==="reset"))},is_stream_position:function(w){return x.type.is_integer(w)&&w.value>=0||x.type.is_atom(w)&&(w.id==="end_of_stream"||w.id==="past_end_of_stream")},is_stream_property:function(w){return x.type.is_term(w)&&(w.indicator==="input/0"||w.indicator==="output/0"||w.indicator==="alias/1"&&(x.type.is_variable(w.args[0])||x.type.is_atom(w.args[0]))||w.indicator==="file_name/1"&&(x.type.is_variable(w.args[0])||x.type.is_atom(w.args[0]))||w.indicator==="position/1"&&(x.type.is_variable(w.args[0])||x.type.is_stream_position(w.args[0]))||w.indicator==="reposition/1"&&(x.type.is_variable(w.args[0])||x.type.is_atom(w.args[0])&&(w.args[0].id==="true"||w.args[0].id==="false"))||w.indicator==="type/1"&&(x.type.is_variable(w.args[0])||x.type.is_atom(w.args[0])&&(w.args[0].id==="text"||w.args[0].id==="binary"))||w.indicator==="mode/1"&&(x.type.is_variable(w.args[0])||x.type.is_atom(w.args[0])&&(w.args[0].id==="read"||w.args[0].id==="write"||w.args[0].id==="append"))||w.indicator==="eof_action/1"&&(x.type.is_variable(w.args[0])||x.type.is_atom(w.args[0])&&(w.args[0].id==="error"||w.args[0].id==="eof_code"||w.args[0].id==="reset"))||w.indicator==="end_of_stream/1"&&(x.type.is_variable(w.args[0])||x.type.is_atom(w.args[0])&&(w.args[0].id==="at"||w.args[0].id==="past"||w.args[0].id==="not")))},is_streamable:function(w){return w.__proto__.stream!==void 0},is_read_option:function(w){return x.type.is_term(w)&&["variables/1","variable_names/1","singletons/1"].indexOf(w.indicator)!==-1},is_write_option:function(w){return x.type.is_term(w)&&(w.indicator==="quoted/1"&&x.type.is_atom(w.args[0])&&(w.args[0].id==="true"||w.args[0].id==="false")||w.indicator==="ignore_ops/1"&&x.type.is_atom(w.args[0])&&(w.args[0].id==="true"||w.args[0].id==="false")||w.indicator==="numbervars/1"&&x.type.is_atom(w.args[0])&&(w.args[0].id==="true"||w.args[0].id==="false"))},is_close_option:function(w){return x.type.is_term(w)&&w.indicator==="force/1"&&x.type.is_atom(w.args[0])&&(w.args[0].id==="true"||w.args[0].id==="false")},is_modifiable_flag:function(w){return x.type.is_flag(w)&&x.flag[w.id].changeable},is_module:function(w){return w instanceof j&&w.indicator==="library/1"&&w.args[0]instanceof j&&w.args[0].args.length===0&&x.module[w.args[0].id]!==void 0}},arithmetic:{evaluation:{"e/0":{type_args:null,type_result:!0,fn:function(w){return Math.E}},"pi/0":{type_args:null,type_result:!0,fn:function(w){return Math.PI}},"tau/0":{type_args:null,type_result:!0,fn:function(w){return 2*Math.PI}},"epsilon/0":{type_args:null,type_result:!0,fn:function(w){return Number.EPSILON}},"+/1":{type_args:null,type_result:null,fn:function(w,b){return w}},"-/1":{type_args:null,type_result:null,fn:function(w,b){return-w}},"\\/1":{type_args:!1,type_result:!1,fn:function(w,b){return~w}},"abs/1":{type_args:null,type_result:null,fn:function(w,b){return Math.abs(w)}},"sign/1":{type_args:null,type_result:null,fn:function(w,b){return Math.sign(w)}},"float_integer_part/1":{type_args:!0,type_result:!1,fn:function(w,b){return parseInt(w)}},"float_fractional_part/1":{type_args:!0,type_result:!0,fn:function(w,b){return w-parseInt(w)}},"float/1":{type_args:null,type_result:!0,fn:function(w,b){return parseFloat(w)}},"floor/1":{type_args:!0,type_result:!1,fn:function(w,b){return Math.floor(w)}},"truncate/1":{type_args:!0,type_result:!1,fn:function(w,b){return parseInt(w)}},"round/1":{type_args:!0,type_result:!1,fn:function(w,b){return Math.round(w)}},"ceiling/1":{type_args:!0,type_result:!1,fn:function(w,b){return Math.ceil(w)}},"sin/1":{type_args:null,type_result:!0,fn:function(w,b){return Math.sin(w)}},"cos/1":{type_args:null,type_result:!0,fn:function(w,b){return Math.cos(w)}},"tan/1":{type_args:null,type_result:!0,fn:function(w,b){return Math.tan(w)}},"asin/1":{type_args:null,type_result:!0,fn:function(w,b){return Math.asin(w)}},"acos/1":{type_args:null,type_result:!0,fn:function(w,b){return Math.acos(w)}},"atan/1":{type_args:null,type_result:!0,fn:function(w,b){return Math.atan(w)}},"atan2/2":{type_args:null,type_result:!0,fn:function(w,b,y){return Math.atan2(w,b)}},"exp/1":{type_args:null,type_result:!0,fn:function(w,b){return Math.exp(w)}},"sqrt/1":{type_args:null,type_result:!0,fn:function(w,b){return Math.sqrt(w)}},"log/1":{type_args:null,type_result:!0,fn:function(w,b){return w>0?Math.log(w):x.error.evaluation("undefined",b.__call_indicator)}},"+/2":{type_args:null,type_result:null,fn:function(w,b,y){return w+b}},"-/2":{type_args:null,type_result:null,fn:function(w,b,y){return w-b}},"*/2":{type_args:null,type_result:null,fn:function(w,b,y){return w*b}},"//2":{type_args:null,type_result:!0,fn:function(w,b,y){return b?w/b:x.error.evaluation("zero_division",y.__call_indicator)}},"///2":{type_args:!1,type_result:!1,fn:function(w,b,y){return b?parseInt(w/b):x.error.evaluation("zero_division",y.__call_indicator)}},"**/2":{type_args:null,type_result:!0,fn:function(w,b,y){return Math.pow(w,b)}},"^/2":{type_args:null,type_result:null,fn:function(w,b,y){return Math.pow(w,b)}},"<>/2":{type_args:!1,type_result:!1,fn:function(w,b,y){return w>>b}},"/\\/2":{type_args:!1,type_result:!1,fn:function(w,b,y){return w&b}},"\\//2":{type_args:!1,type_result:!1,fn:function(w,b,y){return w|b}},"xor/2":{type_args:!1,type_result:!1,fn:function(w,b,y){return w^b}},"rem/2":{type_args:!1,type_result:!1,fn:function(w,b,y){return b?w%b:x.error.evaluation("zero_division",y.__call_indicator)}},"mod/2":{type_args:!1,type_result:!1,fn:function(w,b,y){return b?w-parseInt(w/b)*b:x.error.evaluation("zero_division",y.__call_indicator)}},"max/2":{type_args:null,type_result:null,fn:function(w,b,y){return Math.max(w,b)}},"min/2":{type_args:null,type_result:null,fn:function(w,b,y){return Math.min(w,b)}}}},directive:{"dynamic/1":function(w,b){var y=b.args[0];if(x.type.is_variable(y))w.throw_error(x.error.instantiation(b.indicator));else if(!x.type.is_compound(y)||y.indicator!=="//2")w.throw_error(x.error.type("predicate_indicator",y,b.indicator));else if(x.type.is_variable(y.args[0])||x.type.is_variable(y.args[1]))w.throw_error(x.error.instantiation(b.indicator));else if(!x.type.is_atom(y.args[0]))w.throw_error(x.error.type("atom",y.args[0],b.indicator));else if(!x.type.is_integer(y.args[1]))w.throw_error(x.error.type("integer",y.args[1],b.indicator));else{var F=b.args[0].args[0].id+"/"+b.args[0].args[1].value;w.session.public_predicates[F]=!0,w.session.rules[F]||(w.session.rules[F]=[])}},"multifile/1":function(w,b){var y=b.args[0];x.type.is_variable(y)?w.throw_error(x.error.instantiation(b.indicator)):!x.type.is_compound(y)||y.indicator!=="//2"?w.throw_error(x.error.type("predicate_indicator",y,b.indicator)):x.type.is_variable(y.args[0])||x.type.is_variable(y.args[1])?w.throw_error(x.error.instantiation(b.indicator)):x.type.is_atom(y.args[0])?x.type.is_integer(y.args[1])?w.session.multifile_predicates[b.args[0].args[0].id+"/"+b.args[0].args[1].value]=!0:w.throw_error(x.error.type("integer",y.args[1],b.indicator)):w.throw_error(x.error.type("atom",y.args[0],b.indicator))},"set_prolog_flag/2":function(w,b){var y=b.args[0],F=b.args[1];x.type.is_variable(y)||x.type.is_variable(F)?w.throw_error(x.error.instantiation(b.indicator)):x.type.is_atom(y)?x.type.is_flag(y)?x.type.is_value_flag(y,F)?x.type.is_modifiable_flag(y)?w.session.flag[y.id]=F:w.throw_error(x.error.permission("modify","flag",y)):w.throw_error(x.error.domain("flag_value",new j("+",[y,F]),b.indicator)):w.throw_error(x.error.domain("prolog_flag",y,b.indicator)):w.throw_error(x.error.type("atom",y,b.indicator))},"use_module/1":function(w,b){var y=b.args[0];if(x.type.is_variable(y))w.throw_error(x.error.instantiation(b.indicator));else if(!x.type.is_term(y))w.throw_error(x.error.type("term",y,b.indicator));else if(x.type.is_module(y)){var F=y.args[0].id;e(w.session.modules,F)===-1&&w.session.modules.push(F)}},"char_conversion/2":function(w,b){var y=b.args[0],F=b.args[1];x.type.is_variable(y)||x.type.is_variable(F)?w.throw_error(x.error.instantiation(b.indicator)):x.type.is_character(y)?x.type.is_character(F)?y.id===F.id?delete w.session.__char_conversion[y.id]:w.session.__char_conversion[y.id]=F.id:w.throw_error(x.error.type("character",F,b.indicator)):w.throw_error(x.error.type("character",y,b.indicator))},"op/3":function(w,b){var y=b.args[0],F=b.args[1],z=b.args[2];if(x.type.is_variable(y)||x.type.is_variable(F)||x.type.is_variable(z))w.throw_error(x.error.instantiation(b.indicator));else if(!x.type.is_integer(y))w.throw_error(x.error.type("integer",y,b.indicator));else if(!x.type.is_atom(F))w.throw_error(x.error.type("atom",F,b.indicator));else if(!x.type.is_atom(z))w.throw_error(x.error.type("atom",z,b.indicator));else if(y.value<0||y.value>1200)w.throw_error(x.error.domain("operator_priority",y,b.indicator));else if(z.id===",")w.throw_error(x.error.permission("modify","operator",z,b.indicator));else if(z.id==="|"&&(y.value<1001||F.id.length!==3))w.throw_error(x.error.permission("modify","operator",z,b.indicator));else if(["fy","fx","yf","xf","xfx","yfx","xfy"].indexOf(F.id)===-1)w.throw_error(x.error.domain("operator_specifier",F,b.indicator));else{var X={prefix:null,infix:null,postfix:null};for(var $ in w.session.__operators)if(w.session.__operators.hasOwnProperty($)){var oe=w.session.__operators[$][z.id];oe&&(e(oe,"fx")!==-1&&(X.prefix={priority:$,type:"fx"}),e(oe,"fy")!==-1&&(X.prefix={priority:$,type:"fy"}),e(oe,"xf")!==-1&&(X.postfix={priority:$,type:"xf"}),e(oe,"yf")!==-1&&(X.postfix={priority:$,type:"yf"}),e(oe,"xfx")!==-1&&(X.infix={priority:$,type:"xfx"}),e(oe,"xfy")!==-1&&(X.infix={priority:$,type:"xfy"}),e(oe,"yfx")!==-1&&(X.infix={priority:$,type:"yfx"}))}var xe;switch(F.id){case"fy":case"fx":xe="prefix";break;case"yf":case"xf":xe="postfix";break;default:xe="infix";break}if(((X.prefix&&xe==="prefix"||X.postfix&&xe==="postfix"||X.infix&&xe==="infix")&&X[xe].type!==F.id||X.infix&&xe==="postfix"||X.postfix&&xe==="infix")&&y.value!==0)w.throw_error(x.error.permission("create","operator",z,b.indicator));else return X[xe]&&(we(w.session.__operators[X[xe].priority][z.id],F.id),w.session.__operators[X[xe].priority][z.id].length===0&&delete w.session.__operators[X[xe].priority][z.id]),y.value>0&&(w.session.__operators[y.value]||(w.session.__operators[y.value.toString()]={}),w.session.__operators[y.value][z.id]||(w.session.__operators[y.value][z.id]=[]),w.session.__operators[y.value][z.id].push(F.id)),!0}}},predicate:{"op/3":function(w,b,y){x.directive["op/3"](w,y)&&w.success(b)},"current_op/3":function(w,b,y){var F=y.args[0],z=y.args[1],X=y.args[2],$=[];for(var oe in w.session.__operators)for(var xe in w.session.__operators[oe])for(var Te=0;Te/2"){var F=w.points,z=w.session.format_success,X=w.session.format_error;w.session.format_success=function(Te){return Te.substitution},w.session.format_error=function(Te){return Te.goal},w.points=[new Pe(y.args[0].args[0],b.substitution,b)];var $=function(Te){w.points=F,w.session.format_success=z,w.session.format_error=X,Te===!1?w.prepend([new Pe(b.goal.replace(y.args[1]),b.substitution,b)]):x.type.is_error(Te)?w.throw_error(Te.args[0]):Te===null?(w.prepend([b]),w.__calls.shift()(null)):w.prepend([new Pe(b.goal.replace(y.args[0].args[1]).apply(Te),b.substitution.apply(Te),b)])};w.__calls.unshift($)}else{var oe=new Pe(b.goal.replace(y.args[0]),b.substitution,b),xe=new Pe(b.goal.replace(y.args[1]),b.substitution,b);w.prepend([oe,xe])}},"!/0":function(w,b,y){var F,z,X=[];for(F=b,z=null;F.parent!==null&&F.parent.goal.search(y);)if(z=F,F=F.parent,F.goal!==null){var $=F.goal.select();if($&&$.id==="call"&&$.search(y)){F=z;break}}for(var oe=w.points.length-1;oe>=0;oe--){for(var xe=w.points[oe],Te=xe.parent;Te!==null&&Te!==F.parent;)Te=Te.parent;Te===null&&Te!==F.parent&&X.push(xe)}w.points=X.reverse(),w.success(b)},"\\+/1":function(w,b,y){var F=y.args[0];x.type.is_variable(F)?w.throw_error(x.error.instantiation(w.level)):x.type.is_callable(F)?w.prepend([new Pe(b.goal.replace(new j(",",[new j(",",[new j("call",[F]),new j("!",[])]),new j("fail",[])])),b.substitution,b),new Pe(b.goal.replace(null),b.substitution,b)]):w.throw_error(x.error.type("callable",F,w.level))},"->/2":function(w,b,y){var F=b.goal.replace(new j(",",[y.args[0],new j(",",[new j("!"),y.args[1]])]));w.prepend([new Pe(F,b.substitution,b)])},"fail/0":function(w,b,y){},"false/0":function(w,b,y){},"true/0":function(w,b,y){w.success(b)},"call/1":se(1),"call/2":se(2),"call/3":se(3),"call/4":se(4),"call/5":se(5),"call/6":se(6),"call/7":se(7),"call/8":se(8),"once/1":function(w,b,y){var F=y.args[0];w.prepend([new Pe(b.goal.replace(new j(",",[new j("call",[F]),new j("!",[])])),b.substitution,b)])},"forall/2":function(w,b,y){var F=y.args[0],z=y.args[1];w.prepend([new Pe(b.goal.replace(new j("\\+",[new j(",",[new j("call",[F]),new j("\\+",[new j("call",[z])])])])),b.substitution,b)])},"repeat/0":function(w,b,y){w.prepend([new Pe(b.goal.replace(null),b.substitution,b),b])},"throw/1":function(w,b,y){x.type.is_variable(y.args[0])?w.throw_error(x.error.instantiation(w.level)):w.throw_error(y.args[0])},"catch/3":function(w,b,y){var F=w.points;w.points=[],w.prepend([new Pe(y.args[0],b.substitution,b)]);var z=w.session.format_success,X=w.session.format_error;w.session.format_success=function(oe){return oe.substitution},w.session.format_error=function(oe){return oe.goal};var $=function(oe){var xe=w.points;if(w.points=F,w.session.format_success=z,w.session.format_error=X,x.type.is_error(oe)){for(var Te=[],lt=w.points.length-1;lt>=0;lt--){for(var ir=w.points[lt],Ct=ir.parent;Ct!==null&&Ct!==b.parent;)Ct=Ct.parent;Ct===null&&Ct!==b.parent&&Te.push(ir)}w.points=Te;var qt=w.get_flag("occurs_check").indicator==="true/0",ir=new Pe,Pt=x.unify(oe.args[0],y.args[1],qt);Pt!==null?(ir.substitution=b.substitution.apply(Pt),ir.goal=b.goal.replace(y.args[2]).apply(Pt),ir.parent=b,w.prepend([ir])):w.throw_error(oe.args[0])}else if(oe!==!1){for(var gn=oe===null?[]:[new Pe(b.goal.apply(oe).replace(null),b.substitution.apply(oe),b)],Pr=[],lt=xe.length-1;lt>=0;lt--){Pr.push(xe[lt]);var Ir=xe[lt].goal!==null?xe[lt].goal.select():null;if(x.type.is_term(Ir)&&Ir.indicator==="!/0")break}var Or=s(Pr,function(on){return on.goal===null&&(on.goal=new j("true",[])),on=new Pe(b.goal.replace(new j("catch",[on.goal,y.args[1],y.args[2]])),b.substitution.apply(on.substitution),on.parent),on.exclude=y.args[0].variables(),on}).reverse();w.prepend(Or),w.prepend(gn),oe===null&&(this.current_limit=0,w.__calls.shift()(null))}};w.__calls.unshift($)},"=/2":function(w,b,y){var F=w.get_flag("occurs_check").indicator==="true/0",z=new Pe,X=x.unify(y.args[0],y.args[1],F);X!==null&&(z.goal=b.goal.apply(X).replace(null),z.substitution=b.substitution.apply(X),z.parent=b,w.prepend([z]))},"unify_with_occurs_check/2":function(w,b,y){var F=new Pe,z=x.unify(y.args[0],y.args[1],!0);z!==null&&(F.goal=b.goal.apply(z).replace(null),F.substitution=b.substitution.apply(z),F.parent=b,w.prepend([F]))},"\\=/2":function(w,b,y){var F=w.get_flag("occurs_check").indicator==="true/0",z=x.unify(y.args[0],y.args[1],F);z===null&&w.success(b)},"subsumes_term/2":function(w,b,y){var F=w.get_flag("occurs_check").indicator==="true/0",z=x.unify(y.args[1],y.args[0],F);z!==null&&y.args[1].apply(z).equals(y.args[1])&&w.success(b)},"findall/3":function(w,b,y){var F=y.args[0],z=y.args[1],X=y.args[2];if(x.type.is_variable(z))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_callable(z))w.throw_error(x.error.type("callable",z,y.indicator));else if(!x.type.is_variable(X)&&!x.type.is_list(X))w.throw_error(x.error.type("list",X,y.indicator));else{var $=w.next_free_variable(),oe=new j(",",[z,new j("=",[$,F])]),xe=w.points,Te=w.session.limit,lt=w.session.format_success;w.session.format_success=function(ir){return ir.substitution},w.add_goal(oe,!0,b);var Ct=[],qt=function(ir){if(ir!==!1&&ir!==null&&!x.type.is_error(ir))w.__calls.unshift(qt),Ct.push(ir.links[$.id]),w.session.limit=w.current_limit;else if(w.points=xe,w.session.limit=Te,w.session.format_success=lt,x.type.is_error(ir))w.throw_error(ir.args[0]);else if(w.current_limit>0){for(var Pt=new j("[]"),gn=Ct.length-1;gn>=0;gn--)Pt=new j(".",[Ct[gn],Pt]);w.prepend([new Pe(b.goal.replace(new j("=",[X,Pt])),b.substitution,b)])}};w.__calls.unshift(qt)}},"bagof/3":function(w,b,y){var F,z=y.args[0],X=y.args[1],$=y.args[2];if(x.type.is_variable(X))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_callable(X))w.throw_error(x.error.type("callable",X,y.indicator));else if(!x.type.is_variable($)&&!x.type.is_list($))w.throw_error(x.error.type("list",$,y.indicator));else{var oe=w.next_free_variable(),xe;X.indicator==="^/2"?(xe=X.args[0].variables(),X=X.args[1]):xe=[],xe=xe.concat(z.variables());for(var Te=X.variables().filter(function(Or){return e(xe,Or)===-1}),lt=new j("[]"),Ct=Te.length-1;Ct>=0;Ct--)lt=new j(".",[new De(Te[Ct]),lt]);var qt=new j(",",[X,new j("=",[oe,new j(",",[lt,z])])]),ir=w.points,Pt=w.session.limit,gn=w.session.format_success;w.session.format_success=function(Or){return Or.substitution},w.add_goal(qt,!0,b);var Pr=[],Ir=function(Or){if(Or!==!1&&Or!==null&&!x.type.is_error(Or)){w.__calls.unshift(Ir);var on=!1,ai=Or.links[oe.id].args[0],Io=Or.links[oe.id].args[1];for(var rs in Pr)if(Pr.hasOwnProperty(rs)){var $s=Pr[rs];if($s.variables.equals(ai)){$s.answers.push(Io),on=!0;break}}on||Pr.push({variables:ai,answers:[Io]}),w.session.limit=w.current_limit}else if(w.points=ir,w.session.limit=Pt,w.session.format_success=gn,x.type.is_error(Or))w.throw_error(Or.args[0]);else if(w.current_limit>0){for(var Co=[],ji=0;ji=0;wo--)eo=new j(".",[Or[wo],eo]);Co.push(new Pe(b.goal.replace(new j(",",[new j("=",[lt,Pr[ji].variables]),new j("=",[$,eo])])),b.substitution,b))}w.prepend(Co)}};w.__calls.unshift(Ir)}},"setof/3":function(w,b,y){var F,z=y.args[0],X=y.args[1],$=y.args[2];if(x.type.is_variable(X))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_callable(X))w.throw_error(x.error.type("callable",X,y.indicator));else if(!x.type.is_variable($)&&!x.type.is_list($))w.throw_error(x.error.type("list",$,y.indicator));else{var oe=w.next_free_variable(),xe;X.indicator==="^/2"?(xe=X.args[0].variables(),X=X.args[1]):xe=[],xe=xe.concat(z.variables());for(var Te=X.variables().filter(function(Or){return e(xe,Or)===-1}),lt=new j("[]"),Ct=Te.length-1;Ct>=0;Ct--)lt=new j(".",[new De(Te[Ct]),lt]);var qt=new j(",",[X,new j("=",[oe,new j(",",[lt,z])])]),ir=w.points,Pt=w.session.limit,gn=w.session.format_success;w.session.format_success=function(Or){return Or.substitution},w.add_goal(qt,!0,b);var Pr=[],Ir=function(Or){if(Or!==!1&&Or!==null&&!x.type.is_error(Or)){w.__calls.unshift(Ir);var on=!1,ai=Or.links[oe.id].args[0],Io=Or.links[oe.id].args[1];for(var rs in Pr)if(Pr.hasOwnProperty(rs)){var $s=Pr[rs];if($s.variables.equals(ai)){$s.answers.push(Io),on=!0;break}}on||Pr.push({variables:ai,answers:[Io]}),w.session.limit=w.current_limit}else if(w.points=ir,w.session.limit=Pt,w.session.format_success=gn,x.type.is_error(Or))w.throw_error(Or.args[0]);else if(w.current_limit>0){for(var Co=[],ji=0;ji=0;wo--)eo=new j(".",[Or[wo],eo]);Co.push(new Pe(b.goal.replace(new j(",",[new j("=",[lt,Pr[ji].variables]),new j("=",[$,eo])])),b.substitution,b))}w.prepend(Co)}};w.__calls.unshift(Ir)}},"functor/3":function(w,b,y){var F,z=y.args[0],X=y.args[1],$=y.args[2];if(x.type.is_variable(z)&&(x.type.is_variable(X)||x.type.is_variable($)))w.throw_error(x.error.instantiation("functor/3"));else if(!x.type.is_variable($)&&!x.type.is_integer($))w.throw_error(x.error.type("integer",y.args[2],"functor/3"));else if(!x.type.is_variable(X)&&!x.type.is_atomic(X))w.throw_error(x.error.type("atomic",y.args[1],"functor/3"));else if(x.type.is_integer(X)&&x.type.is_integer($)&&$.value!==0)w.throw_error(x.error.type("atom",y.args[1],"functor/3"));else if(x.type.is_variable(z)){if(y.args[2].value>=0){for(var oe=[],xe=0;xe<$.value;xe++)oe.push(w.next_free_variable());var Te=x.type.is_integer(X)?X:new j(X.id,oe);w.prepend([new Pe(b.goal.replace(new j("=",[z,Te])),b.substitution,b)])}}else{var lt=x.type.is_integer(z)?z:new j(z.id,[]),Ct=x.type.is_integer(z)?new Re(0,!1):new Re(z.args.length,!1),qt=new j(",",[new j("=",[lt,X]),new j("=",[Ct,$])]);w.prepend([new Pe(b.goal.replace(qt),b.substitution,b)])}},"arg/3":function(w,b,y){if(x.type.is_variable(y.args[0])||x.type.is_variable(y.args[1]))w.throw_error(x.error.instantiation(y.indicator));else if(y.args[0].value<0)w.throw_error(x.error.domain("not_less_than_zero",y.args[0],y.indicator));else if(!x.type.is_compound(y.args[1]))w.throw_error(x.error.type("compound",y.args[1],y.indicator));else{var F=y.args[0].value;if(F>0&&F<=y.args[1].args.length){var z=new j("=",[y.args[1].args[F-1],y.args[2]]);w.prepend([new Pe(b.goal.replace(z),b.substitution,b)])}}},"=../2":function(w,b,y){var F;if(x.type.is_variable(y.args[0])&&(x.type.is_variable(y.args[1])||x.type.is_non_empty_list(y.args[1])&&x.type.is_variable(y.args[1].args[0])))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_fully_list(y.args[1]))w.throw_error(x.error.type("list",y.args[1],y.indicator));else if(x.type.is_variable(y.args[0])){if(!x.type.is_variable(y.args[1])){var X=[];for(F=y.args[1].args[1];F.indicator==="./2";)X.push(F.args[0]),F=F.args[1];x.type.is_variable(y.args[0])&&x.type.is_variable(F)?w.throw_error(x.error.instantiation(y.indicator)):X.length===0&&x.type.is_compound(y.args[1].args[0])?w.throw_error(x.error.type("atomic",y.args[1].args[0],y.indicator)):X.length>0&&(x.type.is_compound(y.args[1].args[0])||x.type.is_number(y.args[1].args[0]))?w.throw_error(x.error.type("atom",y.args[1].args[0],y.indicator)):X.length===0?w.prepend([new Pe(b.goal.replace(new j("=",[y.args[1].args[0],y.args[0]],b)),b.substitution,b)]):w.prepend([new Pe(b.goal.replace(new j("=",[new j(y.args[1].args[0].id,X),y.args[0]])),b.substitution,b)])}}else{if(x.type.is_atomic(y.args[0]))F=new j(".",[y.args[0],new j("[]")]);else{F=new j("[]");for(var z=y.args[0].args.length-1;z>=0;z--)F=new j(".",[y.args[0].args[z],F]);F=new j(".",[new j(y.args[0].id),F])}w.prepend([new Pe(b.goal.replace(new j("=",[F,y.args[1]])),b.substitution,b)])}},"copy_term/2":function(w,b,y){var F=y.args[0].rename(w);w.prepend([new Pe(b.goal.replace(new j("=",[F,y.args[1]])),b.substitution,b.parent)])},"term_variables/2":function(w,b,y){var F=y.args[0],z=y.args[1];if(!x.type.is_fully_list(z))w.throw_error(x.error.type("list",z,y.indicator));else{var X=g(s(ye(F.variables()),function($){return new De($)}));w.prepend([new Pe(b.goal.replace(new j("=",[z,X])),b.substitution,b)])}},"clause/2":function(w,b,y){if(x.type.is_variable(y.args[0]))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_callable(y.args[0]))w.throw_error(x.error.type("callable",y.args[0],y.indicator));else if(!x.type.is_variable(y.args[1])&&!x.type.is_callable(y.args[1]))w.throw_error(x.error.type("callable",y.args[1],y.indicator));else if(w.session.rules[y.args[0].indicator]!==void 0)if(w.is_public_predicate(y.args[0].indicator)){var F=[];for(var z in w.session.rules[y.args[0].indicator])if(w.session.rules[y.args[0].indicator].hasOwnProperty(z)){var X=w.session.rules[y.args[0].indicator][z];w.session.renamed_variables={},X=X.rename(w),X.body===null&&(X.body=new j("true"));var $=new j(",",[new j("=",[X.head,y.args[0]]),new j("=",[X.body,y.args[1]])]);F.push(new Pe(b.goal.replace($),b.substitution,b))}w.prepend(F)}else w.throw_error(x.error.permission("access","private_procedure",y.args[0].indicator,y.indicator))},"current_predicate/1":function(w,b,y){var F=y.args[0];if(!x.type.is_variable(F)&&(!x.type.is_compound(F)||F.indicator!=="//2"))w.throw_error(x.error.type("predicate_indicator",F,y.indicator));else if(!x.type.is_variable(F)&&!x.type.is_variable(F.args[0])&&!x.type.is_atom(F.args[0]))w.throw_error(x.error.type("atom",F.args[0],y.indicator));else if(!x.type.is_variable(F)&&!x.type.is_variable(F.args[1])&&!x.type.is_integer(F.args[1]))w.throw_error(x.error.type("integer",F.args[1],y.indicator));else{var z=[];for(var X in w.session.rules)if(w.session.rules.hasOwnProperty(X)){var $=X.lastIndexOf("/"),oe=X.substr(0,$),xe=parseInt(X.substr($+1,X.length-($+1))),Te=new j("/",[new j(oe),new Re(xe,!1)]),lt=new j("=",[Te,F]);z.push(new Pe(b.goal.replace(lt),b.substitution,b))}w.prepend(z)}},"asserta/1":function(w,b,y){if(x.type.is_variable(y.args[0]))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_callable(y.args[0]))w.throw_error(x.error.type("callable",y.args[0],y.indicator));else{var F,z;y.args[0].indicator===":-/2"?(F=y.args[0].args[0],z=Ce(y.args[0].args[1])):(F=y.args[0],z=null),x.type.is_callable(F)?z!==null&&!x.type.is_callable(z)?w.throw_error(x.error.type("callable",z,y.indicator)):w.is_public_predicate(F.indicator)?(w.session.rules[F.indicator]===void 0&&(w.session.rules[F.indicator]=[]),w.session.public_predicates[F.indicator]=!0,w.session.rules[F.indicator]=[new Ve(F,z,!0)].concat(w.session.rules[F.indicator]),w.success(b)):w.throw_error(x.error.permission("modify","static_procedure",F.indicator,y.indicator)):w.throw_error(x.error.type("callable",F,y.indicator))}},"assertz/1":function(w,b,y){if(x.type.is_variable(y.args[0]))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_callable(y.args[0]))w.throw_error(x.error.type("callable",y.args[0],y.indicator));else{var F,z;y.args[0].indicator===":-/2"?(F=y.args[0].args[0],z=Ce(y.args[0].args[1])):(F=y.args[0],z=null),x.type.is_callable(F)?z!==null&&!x.type.is_callable(z)?w.throw_error(x.error.type("callable",z,y.indicator)):w.is_public_predicate(F.indicator)?(w.session.rules[F.indicator]===void 0&&(w.session.rules[F.indicator]=[]),w.session.public_predicates[F.indicator]=!0,w.session.rules[F.indicator].push(new Ve(F,z,!0)),w.success(b)):w.throw_error(x.error.permission("modify","static_procedure",F.indicator,y.indicator)):w.throw_error(x.error.type("callable",F,y.indicator))}},"retract/1":function(w,b,y){if(x.type.is_variable(y.args[0]))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_callable(y.args[0]))w.throw_error(x.error.type("callable",y.args[0],y.indicator));else{var F,z;if(y.args[0].indicator===":-/2"?(F=y.args[0].args[0],z=y.args[0].args[1]):(F=y.args[0],z=new j("true")),typeof b.retract>"u")if(w.is_public_predicate(F.indicator)){if(w.session.rules[F.indicator]!==void 0){for(var X=[],$=0;$w.get_flag("max_arity").value)w.throw_error(x.error.representation("max_arity",y.indicator));else{var F=y.args[0].args[0].id+"/"+y.args[0].args[1].value;w.is_public_predicate(F)?(delete w.session.rules[F],w.success(b)):w.throw_error(x.error.permission("modify","static_procedure",F,y.indicator))}},"atom_length/2":function(w,b,y){if(x.type.is_variable(y.args[0]))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_atom(y.args[0]))w.throw_error(x.error.type("atom",y.args[0],y.indicator));else if(!x.type.is_variable(y.args[1])&&!x.type.is_integer(y.args[1]))w.throw_error(x.error.type("integer",y.args[1],y.indicator));else if(x.type.is_integer(y.args[1])&&y.args[1].value<0)w.throw_error(x.error.domain("not_less_than_zero",y.args[1],y.indicator));else{var F=new Re(y.args[0].id.length,!1);w.prepend([new Pe(b.goal.replace(new j("=",[F,y.args[1]])),b.substitution,b)])}},"atom_concat/3":function(w,b,y){var F,z,X=y.args[0],$=y.args[1],oe=y.args[2];if(x.type.is_variable(oe)&&(x.type.is_variable(X)||x.type.is_variable($)))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(X)&&!x.type.is_atom(X))w.throw_error(x.error.type("atom",X,y.indicator));else if(!x.type.is_variable($)&&!x.type.is_atom($))w.throw_error(x.error.type("atom",$,y.indicator));else if(!x.type.is_variable(oe)&&!x.type.is_atom(oe))w.throw_error(x.error.type("atom",oe,y.indicator));else{var xe=x.type.is_variable(X),Te=x.type.is_variable($);if(!xe&&!Te)z=new j("=",[oe,new j(X.id+$.id)]),w.prepend([new Pe(b.goal.replace(z),b.substitution,b)]);else if(xe&&!Te)F=oe.id.substr(0,oe.id.length-$.id.length),F+$.id===oe.id&&(z=new j("=",[X,new j(F)]),w.prepend([new Pe(b.goal.replace(z),b.substitution,b)]));else if(Te&&!xe)F=oe.id.substr(X.id.length),X.id+F===oe.id&&(z=new j("=",[$,new j(F)]),w.prepend([new Pe(b.goal.replace(z),b.substitution,b)]));else{for(var lt=[],Ct=0;Ct<=oe.id.length;Ct++){var qt=new j(oe.id.substr(0,Ct)),ir=new j(oe.id.substr(Ct));z=new j(",",[new j("=",[qt,X]),new j("=",[ir,$])]),lt.push(new Pe(b.goal.replace(z),b.substitution,b))}w.prepend(lt)}}},"sub_atom/5":function(w,b,y){var F,z=y.args[0],X=y.args[1],$=y.args[2],oe=y.args[3],xe=y.args[4];if(x.type.is_variable(z))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(X)&&!x.type.is_integer(X))w.throw_error(x.error.type("integer",X,y.indicator));else if(!x.type.is_variable($)&&!x.type.is_integer($))w.throw_error(x.error.type("integer",$,y.indicator));else if(!x.type.is_variable(oe)&&!x.type.is_integer(oe))w.throw_error(x.error.type("integer",oe,y.indicator));else if(x.type.is_integer(X)&&X.value<0)w.throw_error(x.error.domain("not_less_than_zero",X,y.indicator));else if(x.type.is_integer($)&&$.value<0)w.throw_error(x.error.domain("not_less_than_zero",$,y.indicator));else if(x.type.is_integer(oe)&&oe.value<0)w.throw_error(x.error.domain("not_less_than_zero",oe,y.indicator));else{var Te=[],lt=[],Ct=[];if(x.type.is_variable(X))for(F=0;F<=z.id.length;F++)Te.push(F);else Te.push(X.value);if(x.type.is_variable($))for(F=0;F<=z.id.length;F++)lt.push(F);else lt.push($.value);if(x.type.is_variable(oe))for(F=0;F<=z.id.length;F++)Ct.push(F);else Ct.push(oe.value);var qt=[];for(var ir in Te)if(Te.hasOwnProperty(ir)){F=Te[ir];for(var Pt in lt)if(lt.hasOwnProperty(Pt)){var gn=lt[Pt],Pr=z.id.length-F-gn;if(e(Ct,Pr)!==-1&&F+gn+Pr===z.id.length){var Ir=z.id.substr(F,gn);if(z.id===z.id.substr(0,F)+Ir+z.id.substr(F+gn,Pr)){var Or=new j("=",[new j(Ir),xe]),on=new j("=",[X,new Re(F)]),ai=new j("=",[$,new Re(gn)]),Io=new j("=",[oe,new Re(Pr)]),rs=new j(",",[new j(",",[new j(",",[on,ai]),Io]),Or]);qt.push(new Pe(b.goal.replace(rs),b.substitution,b))}}}}w.prepend(qt)}},"atom_chars/2":function(w,b,y){var F=y.args[0],z=y.args[1];if(x.type.is_variable(F)&&x.type.is_variable(z))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(F)&&!x.type.is_atom(F))w.throw_error(x.error.type("atom",F,y.indicator));else if(x.type.is_variable(F)){for(var oe=z,xe=x.type.is_variable(F),Te="";oe.indicator==="./2";){if(x.type.is_character(oe.args[0]))Te+=oe.args[0].id;else if(x.type.is_variable(oe.args[0])&&xe){w.throw_error(x.error.instantiation(y.indicator));return}else if(!x.type.is_variable(oe.args[0])){w.throw_error(x.error.type("character",oe.args[0],y.indicator));return}oe=oe.args[1]}x.type.is_variable(oe)&&xe?w.throw_error(x.error.instantiation(y.indicator)):!x.type.is_empty_list(oe)&&!x.type.is_variable(oe)?w.throw_error(x.error.type("list",z,y.indicator)):w.prepend([new Pe(b.goal.replace(new j("=",[new j(Te),F])),b.substitution,b)])}else{for(var X=new j("[]"),$=F.id.length-1;$>=0;$--)X=new j(".",[new j(F.id.charAt($)),X]);w.prepend([new Pe(b.goal.replace(new j("=",[z,X])),b.substitution,b)])}},"atom_codes/2":function(w,b,y){var F=y.args[0],z=y.args[1];if(x.type.is_variable(F)&&x.type.is_variable(z))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(F)&&!x.type.is_atom(F))w.throw_error(x.error.type("atom",F,y.indicator));else if(x.type.is_variable(F)){for(var oe=z,xe=x.type.is_variable(F),Te="";oe.indicator==="./2";){if(x.type.is_character_code(oe.args[0]))Te+=c(oe.args[0].value);else if(x.type.is_variable(oe.args[0])&&xe){w.throw_error(x.error.instantiation(y.indicator));return}else if(!x.type.is_variable(oe.args[0])){w.throw_error(x.error.representation("character_code",y.indicator));return}oe=oe.args[1]}x.type.is_variable(oe)&&xe?w.throw_error(x.error.instantiation(y.indicator)):!x.type.is_empty_list(oe)&&!x.type.is_variable(oe)?w.throw_error(x.error.type("list",z,y.indicator)):w.prepend([new Pe(b.goal.replace(new j("=",[new j(Te),F])),b.substitution,b)])}else{for(var X=new j("[]"),$=F.id.length-1;$>=0;$--)X=new j(".",[new Re(n(F.id,$),!1),X]);w.prepend([new Pe(b.goal.replace(new j("=",[z,X])),b.substitution,b)])}},"char_code/2":function(w,b,y){var F=y.args[0],z=y.args[1];if(x.type.is_variable(F)&&x.type.is_variable(z))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(F)&&!x.type.is_character(F))w.throw_error(x.error.type("character",F,y.indicator));else if(!x.type.is_variable(z)&&!x.type.is_integer(z))w.throw_error(x.error.type("integer",z,y.indicator));else if(!x.type.is_variable(z)&&!x.type.is_character_code(z))w.throw_error(x.error.representation("character_code",y.indicator));else if(x.type.is_variable(z)){var X=new Re(n(F.id,0),!1);w.prepend([new Pe(b.goal.replace(new j("=",[X,z])),b.substitution,b)])}else{var $=new j(c(z.value));w.prepend([new Pe(b.goal.replace(new j("=",[$,F])),b.substitution,b)])}},"number_chars/2":function(w,b,y){var F,z=y.args[0],X=y.args[1];if(x.type.is_variable(z)&&x.type.is_variable(X))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(z)&&!x.type.is_number(z))w.throw_error(x.error.type("number",z,y.indicator));else if(!x.type.is_variable(X)&&!x.type.is_list(X))w.throw_error(x.error.type("list",X,y.indicator));else{var $=x.type.is_variable(z);if(!x.type.is_variable(X)){var oe=X,xe=!0;for(F="";oe.indicator==="./2";){if(x.type.is_character(oe.args[0]))F+=oe.args[0].id;else if(x.type.is_variable(oe.args[0]))xe=!1;else if(!x.type.is_variable(oe.args[0])){w.throw_error(x.error.type("character",oe.args[0],y.indicator));return}oe=oe.args[1]}if(xe=xe&&x.type.is_empty_list(oe),!x.type.is_empty_list(oe)&&!x.type.is_variable(oe)){w.throw_error(x.error.type("list",X,y.indicator));return}if(!xe&&$){w.throw_error(x.error.instantiation(y.indicator));return}else if(xe)if(x.type.is_variable(oe)&&$){w.throw_error(x.error.instantiation(y.indicator));return}else{var Te=w.parse(F),lt=Te.value;!x.type.is_number(lt)||Te.tokens[Te.tokens.length-1].space?w.throw_error(x.error.syntax_by_predicate("parseable_number",y.indicator)):w.prepend([new Pe(b.goal.replace(new j("=",[z,lt])),b.substitution,b)]);return}}if(!$){F=z.toString();for(var Ct=new j("[]"),qt=F.length-1;qt>=0;qt--)Ct=new j(".",[new j(F.charAt(qt)),Ct]);w.prepend([new Pe(b.goal.replace(new j("=",[X,Ct])),b.substitution,b)])}}},"number_codes/2":function(w,b,y){var F,z=y.args[0],X=y.args[1];if(x.type.is_variable(z)&&x.type.is_variable(X))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(z)&&!x.type.is_number(z))w.throw_error(x.error.type("number",z,y.indicator));else if(!x.type.is_variable(X)&&!x.type.is_list(X))w.throw_error(x.error.type("list",X,y.indicator));else{var $=x.type.is_variable(z);if(!x.type.is_variable(X)){var oe=X,xe=!0;for(F="";oe.indicator==="./2";){if(x.type.is_character_code(oe.args[0]))F+=c(oe.args[0].value);else if(x.type.is_variable(oe.args[0]))xe=!1;else if(!x.type.is_variable(oe.args[0])){w.throw_error(x.error.type("character_code",oe.args[0],y.indicator));return}oe=oe.args[1]}if(xe=xe&&x.type.is_empty_list(oe),!x.type.is_empty_list(oe)&&!x.type.is_variable(oe)){w.throw_error(x.error.type("list",X,y.indicator));return}if(!xe&&$){w.throw_error(x.error.instantiation(y.indicator));return}else if(xe)if(x.type.is_variable(oe)&&$){w.throw_error(x.error.instantiation(y.indicator));return}else{var Te=w.parse(F),lt=Te.value;!x.type.is_number(lt)||Te.tokens[Te.tokens.length-1].space?w.throw_error(x.error.syntax_by_predicate("parseable_number",y.indicator)):w.prepend([new Pe(b.goal.replace(new j("=",[z,lt])),b.substitution,b)]);return}}if(!$){F=z.toString();for(var Ct=new j("[]"),qt=F.length-1;qt>=0;qt--)Ct=new j(".",[new Re(n(F,qt),!1),Ct]);w.prepend([new Pe(b.goal.replace(new j("=",[X,Ct])),b.substitution,b)])}}},"upcase_atom/2":function(w,b,y){var F=y.args[0],z=y.args[1];x.type.is_variable(F)?w.throw_error(x.error.instantiation(y.indicator)):x.type.is_atom(F)?!x.type.is_variable(z)&&!x.type.is_atom(z)?w.throw_error(x.error.type("atom",z,y.indicator)):w.prepend([new Pe(b.goal.replace(new j("=",[z,new j(F.id.toUpperCase(),[])])),b.substitution,b)]):w.throw_error(x.error.type("atom",F,y.indicator))},"downcase_atom/2":function(w,b,y){var F=y.args[0],z=y.args[1];x.type.is_variable(F)?w.throw_error(x.error.instantiation(y.indicator)):x.type.is_atom(F)?!x.type.is_variable(z)&&!x.type.is_atom(z)?w.throw_error(x.error.type("atom",z,y.indicator)):w.prepend([new Pe(b.goal.replace(new j("=",[z,new j(F.id.toLowerCase(),[])])),b.substitution,b)]):w.throw_error(x.error.type("atom",F,y.indicator))},"atomic_list_concat/2":function(w,b,y){var F=y.args[0],z=y.args[1];w.prepend([new Pe(b.goal.replace(new j("atomic_list_concat",[F,new j("",[]),z])),b.substitution,b)])},"atomic_list_concat/3":function(w,b,y){var F=y.args[0],z=y.args[1],X=y.args[2];if(x.type.is_variable(z)||x.type.is_variable(F)&&x.type.is_variable(X))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(F)&&!x.type.is_list(F))w.throw_error(x.error.type("list",F,y.indicator));else if(!x.type.is_variable(X)&&!x.type.is_atom(X))w.throw_error(x.error.type("atom",X,y.indicator));else if(x.type.is_variable(X)){for(var oe="",xe=F;x.type.is_term(xe)&&xe.indicator==="./2";){if(!x.type.is_atom(xe.args[0])&&!x.type.is_number(xe.args[0])){w.throw_error(x.error.type("atomic",xe.args[0],y.indicator));return}oe!==""&&(oe+=z.id),x.type.is_atom(xe.args[0])?oe+=xe.args[0].id:oe+=""+xe.args[0].value,xe=xe.args[1]}oe=new j(oe,[]),x.type.is_variable(xe)?w.throw_error(x.error.instantiation(y.indicator)):!x.type.is_term(xe)||xe.indicator!=="[]/0"?w.throw_error(x.error.type("list",F,y.indicator)):w.prepend([new Pe(b.goal.replace(new j("=",[oe,X])),b.substitution,b)])}else{var $=g(s(X.id.split(z.id),function(Te){return new j(Te,[])}));w.prepend([new Pe(b.goal.replace(new j("=",[$,F])),b.substitution,b)])}},"@=/2":function(w,b,y){x.compare(y.args[0],y.args[1])>0&&w.success(b)},"@>=/2":function(w,b,y){x.compare(y.args[0],y.args[1])>=0&&w.success(b)},"compare/3":function(w,b,y){var F=y.args[0],z=y.args[1],X=y.args[2];if(!x.type.is_variable(F)&&!x.type.is_atom(F))w.throw_error(x.error.type("atom",F,y.indicator));else if(x.type.is_atom(F)&&["<",">","="].indexOf(F.id)===-1)w.throw_error(x.type.domain("order",F,y.indicator));else{var $=x.compare(z,X);$=$===0?"=":$===-1?"<":">",w.prepend([new Pe(b.goal.replace(new j("=",[F,new j($,[])])),b.substitution,b)])}},"is/2":function(w,b,y){var F=y.args[1].interpret(w);x.type.is_number(F)?w.prepend([new Pe(b.goal.replace(new j("=",[y.args[0],F],w.level)),b.substitution,b)]):w.throw_error(F)},"between/3":function(w,b,y){var F=y.args[0],z=y.args[1],X=y.args[2];if(x.type.is_variable(F)||x.type.is_variable(z))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_integer(F))w.throw_error(x.error.type("integer",F,y.indicator));else if(!x.type.is_integer(z))w.throw_error(x.error.type("integer",z,y.indicator));else if(!x.type.is_variable(X)&&!x.type.is_integer(X))w.throw_error(x.error.type("integer",X,y.indicator));else if(x.type.is_variable(X)){var $=[new Pe(b.goal.replace(new j("=",[X,F])),b.substitution,b)];F.value=X.value&&w.success(b)},"succ/2":function(w,b,y){var F=y.args[0],z=y.args[1];x.type.is_variable(F)&&x.type.is_variable(z)?w.throw_error(x.error.instantiation(y.indicator)):!x.type.is_variable(F)&&!x.type.is_integer(F)?w.throw_error(x.error.type("integer",F,y.indicator)):!x.type.is_variable(z)&&!x.type.is_integer(z)?w.throw_error(x.error.type("integer",z,y.indicator)):!x.type.is_variable(F)&&F.value<0?w.throw_error(x.error.domain("not_less_than_zero",F,y.indicator)):!x.type.is_variable(z)&&z.value<0?w.throw_error(x.error.domain("not_less_than_zero",z,y.indicator)):(x.type.is_variable(z)||z.value>0)&&(x.type.is_variable(F)?w.prepend([new Pe(b.goal.replace(new j("=",[F,new Re(z.value-1,!1)])),b.substitution,b)]):w.prepend([new Pe(b.goal.replace(new j("=",[z,new Re(F.value+1,!1)])),b.substitution,b)]))},"=:=/2":function(w,b,y){var F=x.arithmetic_compare(w,y.args[0],y.args[1]);x.type.is_term(F)?w.throw_error(F):F===0&&w.success(b)},"=\\=/2":function(w,b,y){var F=x.arithmetic_compare(w,y.args[0],y.args[1]);x.type.is_term(F)?w.throw_error(F):F!==0&&w.success(b)},"/2":function(w,b,y){var F=x.arithmetic_compare(w,y.args[0],y.args[1]);x.type.is_term(F)?w.throw_error(F):F>0&&w.success(b)},">=/2":function(w,b,y){var F=x.arithmetic_compare(w,y.args[0],y.args[1]);x.type.is_term(F)?w.throw_error(F):F>=0&&w.success(b)},"var/1":function(w,b,y){x.type.is_variable(y.args[0])&&w.success(b)},"atom/1":function(w,b,y){x.type.is_atom(y.args[0])&&w.success(b)},"atomic/1":function(w,b,y){x.type.is_atomic(y.args[0])&&w.success(b)},"compound/1":function(w,b,y){x.type.is_compound(y.args[0])&&w.success(b)},"integer/1":function(w,b,y){x.type.is_integer(y.args[0])&&w.success(b)},"float/1":function(w,b,y){x.type.is_float(y.args[0])&&w.success(b)},"number/1":function(w,b,y){x.type.is_number(y.args[0])&&w.success(b)},"nonvar/1":function(w,b,y){x.type.is_variable(y.args[0])||w.success(b)},"ground/1":function(w,b,y){y.variables().length===0&&w.success(b)},"acyclic_term/1":function(w,b,y){for(var F=b.substitution.apply(b.substitution),z=y.args[0].variables(),X=0;X0?Pt[Pt.length-1]:null,Pt!==null&&(qt=W(w,Pt,0,w.__get_max_priority(),!1))}if(qt.type===p&&qt.len===Pt.length-1&&gn.value==="."){qt=qt.value.rename(w);var Pr=new j("=",[z,qt]);if(oe.variables){var Ir=g(s(ye(qt.variables()),function(Or){return new De(Or)}));Pr=new j(",",[Pr,new j("=",[oe.variables,Ir])])}if(oe.variable_names){var Ir=g(s(ye(qt.variables()),function(on){var ai;for(ai in w.session.renamed_variables)if(w.session.renamed_variables.hasOwnProperty(ai)&&w.session.renamed_variables[ai]===on)break;return new j("=",[new j(ai,[]),new De(on)])}));Pr=new j(",",[Pr,new j("=",[oe.variable_names,Ir])])}if(oe.singletons){var Ir=g(s(new Ve(qt,null).singleton_variables(),function(on){var ai;for(ai in w.session.renamed_variables)if(w.session.renamed_variables.hasOwnProperty(ai)&&w.session.renamed_variables[ai]===on)break;return new j("=",[new j(ai,[]),new De(on)])}));Pr=new j(",",[Pr,new j("=",[oe.singletons,Ir])])}w.prepend([new Pe(b.goal.replace(Pr),b.substitution,b)])}else qt.type===p?w.throw_error(x.error.syntax(Pt[qt.len],"unexpected token",!1)):w.throw_error(qt.value)}}},"write/1":function(w,b,y){var F=y.args[0];w.prepend([new Pe(b.goal.replace(new j(",",[new j("current_output",[new De("S")]),new j("write",[new De("S"),F])])),b.substitution,b)])},"write/2":function(w,b,y){var F=y.args[0],z=y.args[1];w.prepend([new Pe(b.goal.replace(new j("write_term",[F,z,new j(".",[new j("quoted",[new j("false",[])]),new j(".",[new j("ignore_ops",[new j("false")]),new j(".",[new j("numbervars",[new j("true")]),new j("[]",[])])])])])),b.substitution,b)])},"writeq/1":function(w,b,y){var F=y.args[0];w.prepend([new Pe(b.goal.replace(new j(",",[new j("current_output",[new De("S")]),new j("writeq",[new De("S"),F])])),b.substitution,b)])},"writeq/2":function(w,b,y){var F=y.args[0],z=y.args[1];w.prepend([new Pe(b.goal.replace(new j("write_term",[F,z,new j(".",[new j("quoted",[new j("true",[])]),new j(".",[new j("ignore_ops",[new j("false")]),new j(".",[new j("numbervars",[new j("true")]),new j("[]",[])])])])])),b.substitution,b)])},"write_canonical/1":function(w,b,y){var F=y.args[0];w.prepend([new Pe(b.goal.replace(new j(",",[new j("current_output",[new De("S")]),new j("write_canonical",[new De("S"),F])])),b.substitution,b)])},"write_canonical/2":function(w,b,y){var F=y.args[0],z=y.args[1];w.prepend([new Pe(b.goal.replace(new j("write_term",[F,z,new j(".",[new j("quoted",[new j("true",[])]),new j(".",[new j("ignore_ops",[new j("true")]),new j(".",[new j("numbervars",[new j("false")]),new j("[]",[])])])])])),b.substitution,b)])},"write_term/2":function(w,b,y){var F=y.args[0],z=y.args[1];w.prepend([new Pe(b.goal.replace(new j(",",[new j("current_output",[new De("S")]),new j("write_term",[new De("S"),F,z])])),b.substitution,b)])},"write_term/3":function(w,b,y){var F=y.args[0],z=y.args[1],X=y.args[2],$=x.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(x.type.is_variable(F)||x.type.is_variable(X))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_list(X))w.throw_error(x.error.type("list",X,y.indicator));else if(!x.type.is_stream(F)&&!x.type.is_atom(F))w.throw_error(x.error.domain("stream_or_alias",F,y.indicator));else if(!x.type.is_stream($)||$.stream===null)w.throw_error(x.error.existence("stream",F,y.indicator));else if($.input)w.throw_error(x.error.permission("output","stream",F,y.indicator));else if($.type==="binary")w.throw_error(x.error.permission("output","binary_stream",F,y.indicator));else if($.position==="past_end_of_stream"&&$.eof_action==="error")w.throw_error(x.error.permission("output","past_end_of_stream",F,y.indicator));else{for(var oe={},xe=X,Te;x.type.is_term(xe)&&xe.indicator==="./2";){if(Te=xe.args[0],x.type.is_variable(Te)){w.throw_error(x.error.instantiation(y.indicator));return}else if(!x.type.is_write_option(Te)){w.throw_error(x.error.domain("write_option",Te,y.indicator));return}oe[Te.id]=Te.args[0].id==="true",xe=xe.args[1]}if(xe.indicator!=="[]/0"){x.type.is_variable(xe)?w.throw_error(x.error.instantiation(y.indicator)):w.throw_error(x.error.type("list",X,y.indicator));return}else{oe.session=w.session;var lt=z.toString(oe);$.stream.put(lt,$.position),typeof $.position=="number"&&($.position+=lt.length),w.success(b)}}},"halt/0":function(w,b,y){w.points=[]},"halt/1":function(w,b,y){var F=y.args[0];x.type.is_variable(F)?w.throw_error(x.error.instantiation(y.indicator)):x.type.is_integer(F)?w.points=[]:w.throw_error(x.error.type("integer",F,y.indicator))},"current_prolog_flag/2":function(w,b,y){var F=y.args[0],z=y.args[1];if(!x.type.is_variable(F)&&!x.type.is_atom(F))w.throw_error(x.error.type("atom",F,y.indicator));else if(!x.type.is_variable(F)&&!x.type.is_flag(F))w.throw_error(x.error.domain("prolog_flag",F,y.indicator));else{var X=[];for(var $ in x.flag)if(x.flag.hasOwnProperty($)){var oe=new j(",",[new j("=",[new j($),F]),new j("=",[w.get_flag($),z])]);X.push(new Pe(b.goal.replace(oe),b.substitution,b))}w.prepend(X)}},"set_prolog_flag/2":function(w,b,y){var F=y.args[0],z=y.args[1];x.type.is_variable(F)||x.type.is_variable(z)?w.throw_error(x.error.instantiation(y.indicator)):x.type.is_atom(F)?x.type.is_flag(F)?x.type.is_value_flag(F,z)?x.type.is_modifiable_flag(F)?(w.session.flag[F.id]=z,w.success(b)):w.throw_error(x.error.permission("modify","flag",F)):w.throw_error(x.error.domain("flag_value",new j("+",[F,z]),y.indicator)):w.throw_error(x.error.domain("prolog_flag",F,y.indicator)):w.throw_error(x.error.type("atom",F,y.indicator))}},flag:{bounded:{allowed:[new j("true"),new j("false")],value:new j("true"),changeable:!1},max_integer:{allowed:[new Re(Number.MAX_SAFE_INTEGER)],value:new Re(Number.MAX_SAFE_INTEGER),changeable:!1},min_integer:{allowed:[new Re(Number.MIN_SAFE_INTEGER)],value:new Re(Number.MIN_SAFE_INTEGER),changeable:!1},integer_rounding_function:{allowed:[new j("down"),new j("toward_zero")],value:new j("toward_zero"),changeable:!1},char_conversion:{allowed:[new j("on"),new j("off")],value:new j("on"),changeable:!0},debug:{allowed:[new j("on"),new j("off")],value:new j("off"),changeable:!0},max_arity:{allowed:[new j("unbounded")],value:new j("unbounded"),changeable:!1},unknown:{allowed:[new j("error"),new j("fail"),new j("warning")],value:new j("error"),changeable:!0},double_quotes:{allowed:[new j("chars"),new j("codes"),new j("atom")],value:new j("codes"),changeable:!0},occurs_check:{allowed:[new j("false"),new j("true")],value:new j("false"),changeable:!0},dialect:{allowed:[new j("tau")],value:new j("tau"),changeable:!1},version_data:{allowed:[new j("tau",[new Re(t.major,!1),new Re(t.minor,!1),new Re(t.patch,!1),new j(t.status)])],value:new j("tau",[new Re(t.major,!1),new Re(t.minor,!1),new Re(t.patch,!1),new j(t.status)]),changeable:!1},nodejs:{allowed:[new j("yes"),new j("no")],value:new j(typeof ec<"u"&&ec.exports?"yes":"no"),changeable:!1}},unify:function(w,b,y){y=y===void 0?!1:y;for(var F=[{left:w,right:b}],z={};F.length!==0;){var X=F.pop();if(w=X.left,b=X.right,x.type.is_term(w)&&x.type.is_term(b)){if(w.indicator!==b.indicator)return null;for(var $=0;$z.value?1:0:z}else return F},operate:function(w,b){if(x.type.is_operator(b)){for(var y=x.type.is_operator(b),F=[],z,X=!1,$=0;$w.get_flag("max_integer").value||z0?w.start+w.matches[0].length:w.start,z=y?new j("token_not_found"):new j("found",[new j(w.value.toString())]),X=new j(".",[new j("line",[new Re(w.line+1)]),new j(".",[new j("column",[new Re(F+1)]),new j(".",[z,new j("[]",[])])])]);return new j("error",[new j("syntax_error",[new j(b)]),X])},syntax_by_predicate:function(w,b){return new j("error",[new j("syntax_error",[new j(w)]),Z(b)])}},warning:{singleton:function(w,b,y){for(var F=new j("[]"),z=w.length-1;z>=0;z--)F=new j(".",[new De(w[z]),F]);return new j("warning",[new j("singleton_variables",[F,Z(b)]),new j(".",[new j("line",[new Re(y,!1)]),new j("[]")])])},failed_goal:function(w,b){return new j("warning",[new j("failed_goal",[w]),new j(".",[new j("line",[new Re(b,!1)]),new j("[]")])])}},format_variable:function(w){return"_"+w},format_answer:function(w,b,F){b instanceof ke&&(b=b.thread);var F=F||{};if(F.session=b?b.session:void 0,x.type.is_error(w))return"uncaught exception: "+w.args[0].toString();if(w===!1)return"false.";if(w===null)return"limit exceeded ;";var z=0,X="";if(x.type.is_substitution(w)){var $=w.domain(!0);w=w.filter(function(Te,lt){return!x.type.is_variable(lt)||$.indexOf(lt.id)!==-1&&Te!==lt.id})}for(var oe in w.links)w.links.hasOwnProperty(oe)&&(z++,X!==""&&(X+=", "),X+=oe.toString(F)+" = "+w.links[oe].toString(F));var xe=typeof b>"u"||b.points.length>0?" ;":".";return z===0?"true"+xe:X+xe},flatten_error:function(w){if(!x.type.is_error(w))return null;w=w.args[0];var b={};return b.type=w.args[0].id,b.thrown=b.type==="syntax_error"?null:w.args[1].id,b.expected=null,b.found=null,b.representation=null,b.existence=null,b.existence_type=null,b.line=null,b.column=null,b.permission_operation=null,b.permission_type=null,b.evaluation_type=null,b.type==="type_error"||b.type==="domain_error"?(b.expected=w.args[0].args[0].id,b.found=w.args[0].args[1].toString()):b.type==="syntax_error"?w.args[1].indicator==="./2"?(b.expected=w.args[0].args[0].id,b.found=w.args[1].args[1].args[1].args[0],b.found=b.found.id==="token_not_found"?b.found.id:b.found.args[0].id,b.line=w.args[1].args[0].args[0].value,b.column=w.args[1].args[1].args[0].args[0].value):b.thrown=w.args[1].id:b.type==="permission_error"?(b.found=w.args[0].args[2].toString(),b.permission_operation=w.args[0].args[0].id,b.permission_type=w.args[0].args[1].id):b.type==="evaluation_error"?b.evaluation_type=w.args[0].args[0].id:b.type==="representation_error"?b.representation=w.args[0].args[0].id:b.type==="existence_error"&&(b.existence=w.args[0].args[1].toString(),b.existence_type=w.args[0].args[0].id),b},create:function(w){return new x.type.Session(w)}};typeof ec<"u"?ec.exports=x:window.pl=x})()});function EEe(t,e,r){t.prepend(r.map(s=>new hl.default.type.State(e.goal.replace(s),e.substitution,e)))}function Lq(t){let e=CEe.get(t.session);if(e==null)throw new Error("Assertion failed: A project should have been registered for the active session");return e}function wEe(t,e){CEe.set(t,e),t.consult(`:- use_module(library(${Zct.id})).`)}var hl,IEe,J0,zct,Xct,CEe,Zct,BEe=Xe(()=>{Ge();ql();hl=ut(Oq()),IEe=ut(Ie("vm")),{is_atom:J0,is_variable:zct,is_instantiated_list:Xct}=hl.default.type;CEe=new WeakMap;Zct=new hl.default.type.Module("constraints",{"project_workspaces_by_descriptor/3":(t,e,r)=>{let[s,a,n]=r.args;if(!J0(s)||!J0(a)){t.throw_error(hl.default.error.instantiation(r.indicator));return}let c=G.parseIdent(s.id),f=G.makeDescriptor(c,a.id),h=Lq(t).tryWorkspaceByDescriptor(f);zct(n)&&h!==null&&EEe(t,e,[new hl.default.type.Term("=",[n,new hl.default.type.Term(String(h.relativeCwd))])]),J0(n)&&h!==null&&h.relativeCwd===n.id&&t.success(e)},"workspace_field/3":(t,e,r)=>{let[s,a,n]=r.args;if(!J0(s)||!J0(a)){t.throw_error(hl.default.error.instantiation(r.indicator));return}let f=Lq(t).tryWorkspaceByCwd(s.id);if(f==null)return;let p=va(f.manifest.raw,a.id);typeof p>"u"||EEe(t,e,[new hl.default.type.Term("=",[n,new hl.default.type.Term(typeof p=="object"?JSON.stringify(p):p)])])},"workspace_field_test/3":(t,e,r)=>{let[s,a,n]=r.args;t.prepend([new hl.default.type.State(e.goal.replace(new hl.default.type.Term("workspace_field_test",[s,a,n,new hl.default.type.Term("[]",[])])),e.substitution,e)])},"workspace_field_test/4":(t,e,r)=>{let[s,a,n,c]=r.args;if(!J0(s)||!J0(a)||!J0(n)||!Xct(c)){t.throw_error(hl.default.error.instantiation(r.indicator));return}let p=Lq(t).tryWorkspaceByCwd(s.id);if(p==null)return;let h=va(p.manifest.raw,a.id);if(typeof h>"u")return;let E={$$:h};for(let[S,P]of c.toJavaScript().entries())E[`$${S}`]=P;IEe.default.runInNewContext(n.id,E)&&t.success(e)}},["project_workspaces_by_descriptor/3","workspace_field/3","workspace_field_test/3","workspace_field_test/4"])});var aS={};Vt(aS,{Constraints:()=>Uq,DependencyType:()=>bEe});function go(t){if(t instanceof KC.default.type.Num)return t.value;if(t instanceof KC.default.type.Term)switch(t.indicator){case"throw/1":return go(t.args[0]);case"error/1":return go(t.args[0]);case"error/2":if(t.args[0]instanceof KC.default.type.Term&&t.args[0].indicator==="syntax_error/1")return Object.assign(go(t.args[0]),...go(t.args[1]));{let e=go(t.args[0]);return e.message+=` (in ${go(t.args[1])})`,e}case"syntax_error/1":return new jt(43,`Syntax error: ${go(t.args[0])}`);case"existence_error/2":return new jt(44,`Existence error: ${go(t.args[0])} ${go(t.args[1])} not found`);case"instantiation_error/0":return new jt(75,"Instantiation error: an argument is variable when an instantiated argument was expected");case"line/1":return{line:go(t.args[0])};case"column/1":return{column:go(t.args[0])};case"found/1":return{found:go(t.args[0])};case"./2":return[go(t.args[0])].concat(go(t.args[1]));case"//2":return`${go(t.args[0])}/${go(t.args[1])}`;default:return t.id}throw`couldn't pretty print because of unsupported node ${t}`}function SEe(t){let e;try{e=go(t)}catch(r){throw typeof r=="string"?new jt(42,`Unknown error: ${t} (note: ${r})`):r}return typeof e.line<"u"&&typeof e.column<"u"&&(e.message+=` at line ${e.line}, column ${e.column}`),e}function Pm(t){return t.id==="null"?null:`${t.toJavaScript()}`}function $ct(t){if(t.id==="null")return null;{let e=t.toJavaScript();if(typeof e!="string")return JSON.stringify(e);try{return JSON.stringify(JSON.parse(e))}catch{return JSON.stringify(e)}}}function K0(t){return typeof t=="string"?`'${t}'`:"[]"}var DEe,KC,bEe,vEe,Mq,Uq,lS=Xe(()=>{Ge();Ge();Dt();DEe=ut(nEe()),KC=ut(Oq());iS();BEe();(0,DEe.default)(KC.default);bEe=(s=>(s.Dependencies="dependencies",s.DevDependencies="devDependencies",s.PeerDependencies="peerDependencies",s))(bEe||{}),vEe=["dependencies","devDependencies","peerDependencies"];Mq=class{constructor(e,r){let s=1e3*e.workspaces.length;this.session=KC.default.create(s),wEe(this.session,e),this.session.consult(":- use_module(library(lists))."),this.session.consult(r)}fetchNextAnswer(){return new Promise(e=>{this.session.answer(r=>{e(r)})})}async*makeQuery(e){let r=this.session.query(e);if(r!==!0)throw SEe(r);for(;;){let s=await this.fetchNextAnswer();if(s===null)throw new jt(79,"Resolution limit exceeded");if(!s)break;if(s.id==="throw")throw SEe(s);yield s}}};Uq=class t{constructor(e){this.source="";this.project=e;let r=e.configuration.get("constraintsPath");ce.existsSync(r)&&(this.source=ce.readFileSync(r,"utf8"))}static async find(e){return new t(e)}getProjectDatabase(){let e="";for(let r of vEe)e+=`dependency_type(${r}). +`;for(let r of this.project.workspacesByCwd.values()){let s=r.relativeCwd;e+=`workspace(${K0(s)}). +`,e+=`workspace_ident(${K0(s)}, ${K0(G.stringifyIdent(r.anchoredLocator))}). +`,e+=`workspace_version(${K0(s)}, ${K0(r.manifest.version)}). +`;for(let a of vEe)for(let n of r.manifest[a].values())e+=`workspace_has_dependency(${K0(s)}, ${K0(G.stringifyIdent(n))}, ${K0(n.range)}, ${a}). +`}return e+=`workspace(_) :- false. +`,e+=`workspace_ident(_, _) :- false. +`,e+=`workspace_version(_, _) :- false. +`,e+=`workspace_has_dependency(_, _, _, _) :- false. +`,e}getDeclarations(){let e="";return e+=`gen_enforced_dependency(_, _, _, _) :- false. +`,e+=`gen_enforced_field(_, _, _) :- false. +`,e}get fullSource(){return`${this.getProjectDatabase()} +${this.source} +${this.getDeclarations()}`}createSession(){return new Mq(this.project,this.fullSource)}async processClassic(){let e=this.createSession();return{enforcedDependencies:await this.genEnforcedDependencies(e),enforcedFields:await this.genEnforcedFields(e)}}async process(){let{enforcedDependencies:e,enforcedFields:r}=await this.processClassic(),s=new Map;for(let{workspace:a,dependencyIdent:n,dependencyRange:c,dependencyType:f}of e){let p=nS([f,G.stringifyIdent(n)]),h=je.getMapWithDefault(s,a.cwd);je.getMapWithDefault(h,p).set(c??void 0,new Set)}for(let{workspace:a,fieldPath:n,fieldValue:c}of r){let f=nS(n),p=je.getMapWithDefault(s,a.cwd);je.getMapWithDefault(p,f).set(JSON.parse(c)??void 0,new Set)}return{manifestUpdates:s,reportedErrors:new Map}}async genEnforcedDependencies(e){let r=[];for await(let s of e.makeQuery("workspace(WorkspaceCwd), dependency_type(DependencyType), gen_enforced_dependency(WorkspaceCwd, DependencyIdent, DependencyRange, DependencyType).")){let a=J.resolve(this.project.cwd,Pm(s.links.WorkspaceCwd)),n=Pm(s.links.DependencyIdent),c=Pm(s.links.DependencyRange),f=Pm(s.links.DependencyType);if(a===null||n===null)throw new Error("Invalid rule");let p=this.project.getWorkspaceByCwd(a),h=G.parseIdent(n);r.push({workspace:p,dependencyIdent:h,dependencyRange:c,dependencyType:f})}return je.sortMap(r,[({dependencyRange:s})=>s!==null?"0":"1",({workspace:s})=>G.stringifyIdent(s.anchoredLocator),({dependencyIdent:s})=>G.stringifyIdent(s)])}async genEnforcedFields(e){let r=[];for await(let s of e.makeQuery("workspace(WorkspaceCwd), gen_enforced_field(WorkspaceCwd, FieldPath, FieldValue).")){let a=J.resolve(this.project.cwd,Pm(s.links.WorkspaceCwd)),n=Pm(s.links.FieldPath),c=$ct(s.links.FieldValue);if(a===null||n===null)throw new Error("Invalid rule");let f=this.project.getWorkspaceByCwd(a);r.push({workspace:f,fieldPath:n,fieldValue:c})}return je.sortMap(r,[({workspace:s})=>G.stringifyIdent(s.anchoredLocator),({fieldPath:s})=>s])}async*query(e){let r=this.createSession();for await(let s of r.makeQuery(e)){let a={};for(let[n,c]of Object.entries(s.links))n!=="_"&&(a[n]=Pm(c));yield a}}}});var OEe=_(fF=>{"use strict";Object.defineProperty(fF,"__esModule",{value:!0});function BS(t){let e=[...t.caches],r=e.shift();return r===void 0?NEe():{get(s,a,n={miss:()=>Promise.resolve()}){return r.get(s,a,n).catch(()=>BS({caches:e}).get(s,a,n))},set(s,a){return r.set(s,a).catch(()=>BS({caches:e}).set(s,a))},delete(s){return r.delete(s).catch(()=>BS({caches:e}).delete(s))},clear(){return r.clear().catch(()=>BS({caches:e}).clear())}}}function NEe(){return{get(t,e,r={miss:()=>Promise.resolve()}){return e().then(a=>Promise.all([a,r.miss(a)])).then(([a])=>a)},set(t,e){return Promise.resolve(e)},delete(t){return Promise.resolve()},clear(){return Promise.resolve()}}}fF.createFallbackableCache=BS;fF.createNullCache=NEe});var MEe=_((BJt,LEe)=>{LEe.exports=OEe()});var UEe=_($q=>{"use strict";Object.defineProperty($q,"__esModule",{value:!0});function yut(t={serializable:!0}){let e={};return{get(r,s,a={miss:()=>Promise.resolve()}){let n=JSON.stringify(r);if(n in e)return Promise.resolve(t.serializable?JSON.parse(e[n]):e[n]);let c=s(),f=a&&a.miss||(()=>Promise.resolve());return c.then(p=>f(p)).then(()=>c)},set(r,s){return e[JSON.stringify(r)]=t.serializable?JSON.stringify(s):s,Promise.resolve(s)},delete(r){return delete e[JSON.stringify(r)],Promise.resolve()},clear(){return e={},Promise.resolve()}}}$q.createInMemoryCache=yut});var HEe=_((SJt,_Ee)=>{_Ee.exports=UEe()});var GEe=_($u=>{"use strict";Object.defineProperty($u,"__esModule",{value:!0});function Eut(t,e,r){let s={"x-algolia-api-key":r,"x-algolia-application-id":e};return{headers(){return t===e9.WithinHeaders?s:{}},queryParameters(){return t===e9.WithinQueryParameters?s:{}}}}function Iut(t){let e=0,r=()=>(e++,new Promise(s=>{setTimeout(()=>{s(t(r))},Math.min(100*e,1e3))}));return t(r)}function jEe(t,e=(r,s)=>Promise.resolve()){return Object.assign(t,{wait(r){return jEe(t.then(s=>Promise.all([e(s,r),s])).then(s=>s[1]))}})}function Cut(t){let e=t.length-1;for(e;e>0;e--){let r=Math.floor(Math.random()*(e+1)),s=t[e];t[e]=t[r],t[r]=s}return t}function wut(t,e){return e&&Object.keys(e).forEach(r=>{t[r]=e[r](t)}),t}function But(t,...e){let r=0;return t.replace(/%s/g,()=>encodeURIComponent(e[r++]))}var vut="4.22.1",Sut=t=>()=>t.transporter.requester.destroy(),e9={WithinQueryParameters:0,WithinHeaders:1};$u.AuthMode=e9;$u.addMethods=wut;$u.createAuth=Eut;$u.createRetryablePromise=Iut;$u.createWaitablePromise=jEe;$u.destroy=Sut;$u.encode=But;$u.shuffle=Cut;$u.version=vut});var vS=_((bJt,qEe)=>{qEe.exports=GEe()});var WEe=_(t9=>{"use strict";Object.defineProperty(t9,"__esModule",{value:!0});var Dut={Delete:"DELETE",Get:"GET",Post:"POST",Put:"PUT"};t9.MethodEnum=Dut});var SS=_((xJt,YEe)=>{YEe.exports=WEe()});var aIe=_(Yi=>{"use strict";Object.defineProperty(Yi,"__esModule",{value:!0});var JEe=SS();function r9(t,e){let r=t||{},s=r.data||{};return Object.keys(r).forEach(a=>{["timeout","headers","queryParameters","data","cacheable"].indexOf(a)===-1&&(s[a]=r[a])}),{data:Object.entries(s).length>0?s:void 0,timeout:r.timeout||e,headers:r.headers||{},queryParameters:r.queryParameters||{},cacheable:r.cacheable}}var DS={Read:1,Write:2,Any:3},sw={Up:1,Down:2,Timeouted:3},KEe=2*60*1e3;function i9(t,e=sw.Up){return{...t,status:e,lastUpdate:Date.now()}}function zEe(t){return t.status===sw.Up||Date.now()-t.lastUpdate>KEe}function XEe(t){return t.status===sw.Timeouted&&Date.now()-t.lastUpdate<=KEe}function s9(t){return typeof t=="string"?{protocol:"https",url:t,accept:DS.Any}:{protocol:t.protocol||"https",url:t.url,accept:t.accept||DS.Any}}function but(t,e){return Promise.all(e.map(r=>t.get(r,()=>Promise.resolve(i9(r))))).then(r=>{let s=r.filter(f=>zEe(f)),a=r.filter(f=>XEe(f)),n=[...s,...a],c=n.length>0?n.map(f=>s9(f)):e;return{getTimeout(f,p){return(a.length===0&&f===0?1:a.length+3+f)*p},statelessHosts:c}})}var Put=({isTimedOut:t,status:e})=>!t&&~~e===0,xut=t=>{let e=t.status;return t.isTimedOut||Put(t)||~~(e/100)!==2&&~~(e/100)!==4},kut=({status:t})=>~~(t/100)===2,Qut=(t,e)=>xut(t)?e.onRetry(t):kut(t)?e.onSuccess(t):e.onFail(t);function VEe(t,e,r,s){let a=[],n=rIe(r,s),c=nIe(t,s),f=r.method,p=r.method!==JEe.MethodEnum.Get?{}:{...r.data,...s.data},h={"x-algolia-agent":t.userAgent.value,...t.queryParameters,...p,...s.queryParameters},E=0,C=(S,P)=>{let I=S.pop();if(I===void 0)throw oIe(n9(a));let R={data:n,headers:c,method:f,url:eIe(I,r.path,h),connectTimeout:P(E,t.timeouts.connect),responseTimeout:P(E,s.timeout)},N=W=>{let ee={request:R,response:W,host:I,triesLeft:S.length};return a.push(ee),ee},U={onSuccess:W=>ZEe(W),onRetry(W){let ee=N(W);return W.isTimedOut&&E++,Promise.all([t.logger.info("Retryable failure",o9(ee)),t.hostsCache.set(I,i9(I,W.isTimedOut?sw.Timeouted:sw.Down))]).then(()=>C(S,P))},onFail(W){throw N(W),$Ee(W,n9(a))}};return t.requester.send(R).then(W=>Qut(W,U))};return but(t.hostsCache,e).then(S=>C([...S.statelessHosts].reverse(),S.getTimeout))}function Tut(t){let{hostsCache:e,logger:r,requester:s,requestsCache:a,responsesCache:n,timeouts:c,userAgent:f,hosts:p,queryParameters:h,headers:E}=t,C={hostsCache:e,logger:r,requester:s,requestsCache:a,responsesCache:n,timeouts:c,userAgent:f,headers:E,queryParameters:h,hosts:p.map(S=>s9(S)),read(S,P){let I=r9(P,C.timeouts.read),R=()=>VEe(C,C.hosts.filter(W=>(W.accept&DS.Read)!==0),S,I);if((I.cacheable!==void 0?I.cacheable:S.cacheable)!==!0)return R();let U={request:S,mappedRequestOptions:I,transporter:{queryParameters:C.queryParameters,headers:C.headers}};return C.responsesCache.get(U,()=>C.requestsCache.get(U,()=>C.requestsCache.set(U,R()).then(W=>Promise.all([C.requestsCache.delete(U),W]),W=>Promise.all([C.requestsCache.delete(U),Promise.reject(W)])).then(([W,ee])=>ee)),{miss:W=>C.responsesCache.set(U,W)})},write(S,P){return VEe(C,C.hosts.filter(I=>(I.accept&DS.Write)!==0),S,r9(P,C.timeouts.write))}};return C}function Rut(t){let e={value:`Algolia for JavaScript (${t})`,add(r){let s=`; ${r.segment}${r.version!==void 0?` (${r.version})`:""}`;return e.value.indexOf(s)===-1&&(e.value=`${e.value}${s}`),e}};return e}function ZEe(t){try{return JSON.parse(t.content)}catch(e){throw sIe(e.message,t)}}function $Ee({content:t,status:e},r){let s=t;try{s=JSON.parse(t).message}catch{}return iIe(s,e,r)}function Fut(t,...e){let r=0;return t.replace(/%s/g,()=>encodeURIComponent(e[r++]))}function eIe(t,e,r){let s=tIe(r),a=`${t.protocol}://${t.url}/${e.charAt(0)==="/"?e.substr(1):e}`;return s.length&&(a+=`?${s}`),a}function tIe(t){let e=r=>Object.prototype.toString.call(r)==="[object Object]"||Object.prototype.toString.call(r)==="[object Array]";return Object.keys(t).map(r=>Fut("%s=%s",r,e(t[r])?JSON.stringify(t[r]):t[r])).join("&")}function rIe(t,e){if(t.method===JEe.MethodEnum.Get||t.data===void 0&&e.data===void 0)return;let r=Array.isArray(t.data)?t.data:{...t.data,...e.data};return JSON.stringify(r)}function nIe(t,e){let r={...t.headers,...e.headers},s={};return Object.keys(r).forEach(a=>{let n=r[a];s[a.toLowerCase()]=n}),s}function n9(t){return t.map(e=>o9(e))}function o9(t){let e=t.request.headers["x-algolia-api-key"]?{"x-algolia-api-key":"*****"}:{};return{...t,request:{...t.request,headers:{...t.request.headers,...e}}}}function iIe(t,e,r){return{name:"ApiError",message:t,status:e,transporterStackTrace:r}}function sIe(t,e){return{name:"DeserializationError",message:t,response:e}}function oIe(t){return{name:"RetryError",message:"Unreachable hosts - your application id may be incorrect. If the error persists, contact support@algolia.com.",transporterStackTrace:t}}Yi.CallEnum=DS;Yi.HostStatusEnum=sw;Yi.createApiError=iIe;Yi.createDeserializationError=sIe;Yi.createMappedRequestOptions=r9;Yi.createRetryError=oIe;Yi.createStatefulHost=i9;Yi.createStatelessHost=s9;Yi.createTransporter=Tut;Yi.createUserAgent=Rut;Yi.deserializeFailure=$Ee;Yi.deserializeSuccess=ZEe;Yi.isStatefulHostTimeouted=XEe;Yi.isStatefulHostUp=zEe;Yi.serializeData=rIe;Yi.serializeHeaders=nIe;Yi.serializeQueryParameters=tIe;Yi.serializeUrl=eIe;Yi.stackFrameWithoutCredentials=o9;Yi.stackTraceWithoutCredentials=n9});var bS=_((QJt,lIe)=>{lIe.exports=aIe()});var cIe=_(X0=>{"use strict";Object.defineProperty(X0,"__esModule",{value:!0});var ow=vS(),Nut=bS(),PS=SS(),Out=t=>{let e=t.region||"us",r=ow.createAuth(ow.AuthMode.WithinHeaders,t.appId,t.apiKey),s=Nut.createTransporter({hosts:[{url:`analytics.${e}.algolia.com`}],...t,headers:{...r.headers(),"content-type":"application/json",...t.headers},queryParameters:{...r.queryParameters(),...t.queryParameters}}),a=t.appId;return ow.addMethods({appId:a,transporter:s},t.methods)},Lut=t=>(e,r)=>t.transporter.write({method:PS.MethodEnum.Post,path:"2/abtests",data:e},r),Mut=t=>(e,r)=>t.transporter.write({method:PS.MethodEnum.Delete,path:ow.encode("2/abtests/%s",e)},r),Uut=t=>(e,r)=>t.transporter.read({method:PS.MethodEnum.Get,path:ow.encode("2/abtests/%s",e)},r),_ut=t=>e=>t.transporter.read({method:PS.MethodEnum.Get,path:"2/abtests"},e),Hut=t=>(e,r)=>t.transporter.write({method:PS.MethodEnum.Post,path:ow.encode("2/abtests/%s/stop",e)},r);X0.addABTest=Lut;X0.createAnalyticsClient=Out;X0.deleteABTest=Mut;X0.getABTest=Uut;X0.getABTests=_ut;X0.stopABTest=Hut});var fIe=_((RJt,uIe)=>{uIe.exports=cIe()});var pIe=_(xS=>{"use strict";Object.defineProperty(xS,"__esModule",{value:!0});var a9=vS(),jut=bS(),AIe=SS(),Gut=t=>{let e=t.region||"us",r=a9.createAuth(a9.AuthMode.WithinHeaders,t.appId,t.apiKey),s=jut.createTransporter({hosts:[{url:`personalization.${e}.algolia.com`}],...t,headers:{...r.headers(),"content-type":"application/json",...t.headers},queryParameters:{...r.queryParameters(),...t.queryParameters}});return a9.addMethods({appId:t.appId,transporter:s},t.methods)},qut=t=>e=>t.transporter.read({method:AIe.MethodEnum.Get,path:"1/strategies/personalization"},e),Wut=t=>(e,r)=>t.transporter.write({method:AIe.MethodEnum.Post,path:"1/strategies/personalization",data:e},r);xS.createPersonalizationClient=Gut;xS.getPersonalizationStrategy=qut;xS.setPersonalizationStrategy=Wut});var gIe=_((NJt,hIe)=>{hIe.exports=pIe()});var xIe=_(Ft=>{"use strict";Object.defineProperty(Ft,"__esModule",{value:!0});var Jt=vS(),gl=bS(),br=SS(),Yut=Ie("crypto");function AF(t){let e=r=>t.request(r).then(s=>{if(t.batch!==void 0&&t.batch(s.hits),!t.shouldStop(s))return s.cursor?e({cursor:s.cursor}):e({page:(r.page||0)+1})});return e({})}var Vut=t=>{let e=t.appId,r=Jt.createAuth(t.authMode!==void 0?t.authMode:Jt.AuthMode.WithinHeaders,e,t.apiKey),s=gl.createTransporter({hosts:[{url:`${e}-dsn.algolia.net`,accept:gl.CallEnum.Read},{url:`${e}.algolia.net`,accept:gl.CallEnum.Write}].concat(Jt.shuffle([{url:`${e}-1.algolianet.com`},{url:`${e}-2.algolianet.com`},{url:`${e}-3.algolianet.com`}])),...t,headers:{...r.headers(),"content-type":"application/x-www-form-urlencoded",...t.headers},queryParameters:{...r.queryParameters(),...t.queryParameters}}),a={transporter:s,appId:e,addAlgoliaAgent(n,c){s.userAgent.add({segment:n,version:c})},clearCache(){return Promise.all([s.requestsCache.clear(),s.responsesCache.clear()]).then(()=>{})}};return Jt.addMethods(a,t.methods)};function dIe(){return{name:"MissingObjectIDError",message:"All objects must have an unique objectID (like a primary key) to be valid. Algolia is also able to generate objectIDs automatically but *it's not recommended*. To do it, use the `{'autoGenerateObjectIDIfNotExist': true}` option."}}function mIe(){return{name:"ObjectNotFoundError",message:"Object not found."}}function yIe(){return{name:"ValidUntilNotFoundError",message:"ValidUntil not found in given secured api key."}}var Jut=t=>(e,r)=>{let{queryParameters:s,...a}=r||{},n={acl:e,...s!==void 0?{queryParameters:s}:{}},c=(f,p)=>Jt.createRetryablePromise(h=>kS(t)(f.key,p).catch(E=>{if(E.status!==404)throw E;return h()}));return Jt.createWaitablePromise(t.transporter.write({method:br.MethodEnum.Post,path:"1/keys",data:n},a),c)},Kut=t=>(e,r,s)=>{let a=gl.createMappedRequestOptions(s);return a.queryParameters["X-Algolia-User-ID"]=e,t.transporter.write({method:br.MethodEnum.Post,path:"1/clusters/mapping",data:{cluster:r}},a)},zut=t=>(e,r,s)=>t.transporter.write({method:br.MethodEnum.Post,path:"1/clusters/mapping/batch",data:{users:e,cluster:r}},s),Xut=t=>(e,r)=>Jt.createWaitablePromise(t.transporter.write({method:br.MethodEnum.Post,path:Jt.encode("/1/dictionaries/%s/batch",e),data:{clearExistingDictionaryEntries:!0,requests:{action:"addEntry",body:[]}}},r),(s,a)=>aw(t)(s.taskID,a)),pF=t=>(e,r,s)=>{let a=(n,c)=>QS(t)(e,{methods:{waitTask:hs}}).waitTask(n.taskID,c);return Jt.createWaitablePromise(t.transporter.write({method:br.MethodEnum.Post,path:Jt.encode("1/indexes/%s/operation",e),data:{operation:"copy",destination:r}},s),a)},Zut=t=>(e,r,s)=>pF(t)(e,r,{...s,scope:[gF.Rules]}),$ut=t=>(e,r,s)=>pF(t)(e,r,{...s,scope:[gF.Settings]}),eft=t=>(e,r,s)=>pF(t)(e,r,{...s,scope:[gF.Synonyms]}),tft=t=>(e,r)=>e.method===br.MethodEnum.Get?t.transporter.read(e,r):t.transporter.write(e,r),rft=t=>(e,r)=>{let s=(a,n)=>Jt.createRetryablePromise(c=>kS(t)(e,n).then(c).catch(f=>{if(f.status!==404)throw f}));return Jt.createWaitablePromise(t.transporter.write({method:br.MethodEnum.Delete,path:Jt.encode("1/keys/%s",e)},r),s)},nft=t=>(e,r,s)=>{let a=r.map(n=>({action:"deleteEntry",body:{objectID:n}}));return Jt.createWaitablePromise(t.transporter.write({method:br.MethodEnum.Post,path:Jt.encode("/1/dictionaries/%s/batch",e),data:{clearExistingDictionaryEntries:!1,requests:a}},s),(n,c)=>aw(t)(n.taskID,c))},ift=()=>(t,e)=>{let r=gl.serializeQueryParameters(e),s=Yut.createHmac("sha256",t).update(r).digest("hex");return Buffer.from(s+r).toString("base64")},kS=t=>(e,r)=>t.transporter.read({method:br.MethodEnum.Get,path:Jt.encode("1/keys/%s",e)},r),EIe=t=>(e,r)=>t.transporter.read({method:br.MethodEnum.Get,path:Jt.encode("1/task/%s",e.toString())},r),sft=t=>e=>t.transporter.read({method:br.MethodEnum.Get,path:"/1/dictionaries/*/settings"},e),oft=t=>e=>t.transporter.read({method:br.MethodEnum.Get,path:"1/logs"},e),aft=()=>t=>{let e=Buffer.from(t,"base64").toString("ascii"),r=/validUntil=(\d+)/,s=e.match(r);if(s===null)throw yIe();return parseInt(s[1],10)-Math.round(new Date().getTime()/1e3)},lft=t=>e=>t.transporter.read({method:br.MethodEnum.Get,path:"1/clusters/mapping/top"},e),cft=t=>(e,r)=>t.transporter.read({method:br.MethodEnum.Get,path:Jt.encode("1/clusters/mapping/%s",e)},r),uft=t=>e=>{let{retrieveMappings:r,...s}=e||{};return r===!0&&(s.getClusters=!0),t.transporter.read({method:br.MethodEnum.Get,path:"1/clusters/mapping/pending"},s)},QS=t=>(e,r={})=>{let s={transporter:t.transporter,appId:t.appId,indexName:e};return Jt.addMethods(s,r.methods)},fft=t=>e=>t.transporter.read({method:br.MethodEnum.Get,path:"1/keys"},e),Aft=t=>e=>t.transporter.read({method:br.MethodEnum.Get,path:"1/clusters"},e),pft=t=>e=>t.transporter.read({method:br.MethodEnum.Get,path:"1/indexes"},e),hft=t=>e=>t.transporter.read({method:br.MethodEnum.Get,path:"1/clusters/mapping"},e),gft=t=>(e,r,s)=>{let a=(n,c)=>QS(t)(e,{methods:{waitTask:hs}}).waitTask(n.taskID,c);return Jt.createWaitablePromise(t.transporter.write({method:br.MethodEnum.Post,path:Jt.encode("1/indexes/%s/operation",e),data:{operation:"move",destination:r}},s),a)},dft=t=>(e,r)=>{let s=(a,n)=>Promise.all(Object.keys(a.taskID).map(c=>QS(t)(c,{methods:{waitTask:hs}}).waitTask(a.taskID[c],n)));return Jt.createWaitablePromise(t.transporter.write({method:br.MethodEnum.Post,path:"1/indexes/*/batch",data:{requests:e}},r),s)},mft=t=>(e,r)=>t.transporter.read({method:br.MethodEnum.Post,path:"1/indexes/*/objects",data:{requests:e}},r),yft=t=>(e,r)=>{let s=e.map(a=>({...a,params:gl.serializeQueryParameters(a.params||{})}));return t.transporter.read({method:br.MethodEnum.Post,path:"1/indexes/*/queries",data:{requests:s},cacheable:!0},r)},Eft=t=>(e,r)=>Promise.all(e.map(s=>{let{facetName:a,facetQuery:n,...c}=s.params;return QS(t)(s.indexName,{methods:{searchForFacetValues:DIe}}).searchForFacetValues(a,n,{...r,...c})})),Ift=t=>(e,r)=>{let s=gl.createMappedRequestOptions(r);return s.queryParameters["X-Algolia-User-ID"]=e,t.transporter.write({method:br.MethodEnum.Delete,path:"1/clusters/mapping"},s)},Cft=t=>(e,r,s)=>{let a=r.map(n=>({action:"addEntry",body:n}));return Jt.createWaitablePromise(t.transporter.write({method:br.MethodEnum.Post,path:Jt.encode("/1/dictionaries/%s/batch",e),data:{clearExistingDictionaryEntries:!0,requests:a}},s),(n,c)=>aw(t)(n.taskID,c))},wft=t=>(e,r)=>{let s=(a,n)=>Jt.createRetryablePromise(c=>kS(t)(e,n).catch(f=>{if(f.status!==404)throw f;return c()}));return Jt.createWaitablePromise(t.transporter.write({method:br.MethodEnum.Post,path:Jt.encode("1/keys/%s/restore",e)},r),s)},Bft=t=>(e,r,s)=>{let a=r.map(n=>({action:"addEntry",body:n}));return Jt.createWaitablePromise(t.transporter.write({method:br.MethodEnum.Post,path:Jt.encode("/1/dictionaries/%s/batch",e),data:{clearExistingDictionaryEntries:!1,requests:a}},s),(n,c)=>aw(t)(n.taskID,c))},vft=t=>(e,r,s)=>t.transporter.read({method:br.MethodEnum.Post,path:Jt.encode("/1/dictionaries/%s/search",e),data:{query:r},cacheable:!0},s),Sft=t=>(e,r)=>t.transporter.read({method:br.MethodEnum.Post,path:"1/clusters/mapping/search",data:{query:e}},r),Dft=t=>(e,r)=>Jt.createWaitablePromise(t.transporter.write({method:br.MethodEnum.Put,path:"/1/dictionaries/*/settings",data:e},r),(s,a)=>aw(t)(s.taskID,a)),bft=t=>(e,r)=>{let s=Object.assign({},r),{queryParameters:a,...n}=r||{},c=a?{queryParameters:a}:{},f=["acl","indexes","referers","restrictSources","queryParameters","description","maxQueriesPerIPPerHour","maxHitsPerQuery"],p=E=>Object.keys(s).filter(C=>f.indexOf(C)!==-1).every(C=>{if(Array.isArray(E[C])&&Array.isArray(s[C])){let S=E[C];return S.length===s[C].length&&S.every((P,I)=>P===s[C][I])}else return E[C]===s[C]}),h=(E,C)=>Jt.createRetryablePromise(S=>kS(t)(e,C).then(P=>p(P)?Promise.resolve():S()));return Jt.createWaitablePromise(t.transporter.write({method:br.MethodEnum.Put,path:Jt.encode("1/keys/%s",e),data:c},n),h)},aw=t=>(e,r)=>Jt.createRetryablePromise(s=>EIe(t)(e,r).then(a=>a.status!=="published"?s():void 0)),IIe=t=>(e,r)=>{let s=(a,n)=>hs(t)(a.taskID,n);return Jt.createWaitablePromise(t.transporter.write({method:br.MethodEnum.Post,path:Jt.encode("1/indexes/%s/batch",t.indexName),data:{requests:e}},r),s)},Pft=t=>e=>AF({shouldStop:r=>r.cursor===void 0,...e,request:r=>t.transporter.read({method:br.MethodEnum.Post,path:Jt.encode("1/indexes/%s/browse",t.indexName),data:r},e)}),xft=t=>e=>{let r={hitsPerPage:1e3,...e};return AF({shouldStop:s=>s.hits.length({...a,hits:a.hits.map(n=>(delete n._highlightResult,n))}))}})},kft=t=>e=>{let r={hitsPerPage:1e3,...e};return AF({shouldStop:s=>s.hits.length({...a,hits:a.hits.map(n=>(delete n._highlightResult,n))}))}})},hF=t=>(e,r,s)=>{let{batchSize:a,...n}=s||{},c={taskIDs:[],objectIDs:[]},f=(p=0)=>{let h=[],E;for(E=p;E({action:r,body:C})),n).then(C=>(c.objectIDs=c.objectIDs.concat(C.objectIDs),c.taskIDs.push(C.taskID),E++,f(E)))};return Jt.createWaitablePromise(f(),(p,h)=>Promise.all(p.taskIDs.map(E=>hs(t)(E,h))))},Qft=t=>e=>Jt.createWaitablePromise(t.transporter.write({method:br.MethodEnum.Post,path:Jt.encode("1/indexes/%s/clear",t.indexName)},e),(r,s)=>hs(t)(r.taskID,s)),Tft=t=>e=>{let{forwardToReplicas:r,...s}=e||{},a=gl.createMappedRequestOptions(s);return r&&(a.queryParameters.forwardToReplicas=1),Jt.createWaitablePromise(t.transporter.write({method:br.MethodEnum.Post,path:Jt.encode("1/indexes/%s/rules/clear",t.indexName)},a),(n,c)=>hs(t)(n.taskID,c))},Rft=t=>e=>{let{forwardToReplicas:r,...s}=e||{},a=gl.createMappedRequestOptions(s);return r&&(a.queryParameters.forwardToReplicas=1),Jt.createWaitablePromise(t.transporter.write({method:br.MethodEnum.Post,path:Jt.encode("1/indexes/%s/synonyms/clear",t.indexName)},a),(n,c)=>hs(t)(n.taskID,c))},Fft=t=>(e,r)=>Jt.createWaitablePromise(t.transporter.write({method:br.MethodEnum.Post,path:Jt.encode("1/indexes/%s/deleteByQuery",t.indexName),data:e},r),(s,a)=>hs(t)(s.taskID,a)),Nft=t=>e=>Jt.createWaitablePromise(t.transporter.write({method:br.MethodEnum.Delete,path:Jt.encode("1/indexes/%s",t.indexName)},e),(r,s)=>hs(t)(r.taskID,s)),Oft=t=>(e,r)=>Jt.createWaitablePromise(CIe(t)([e],r).then(s=>({taskID:s.taskIDs[0]})),(s,a)=>hs(t)(s.taskID,a)),CIe=t=>(e,r)=>{let s=e.map(a=>({objectID:a}));return hF(t)(s,km.DeleteObject,r)},Lft=t=>(e,r)=>{let{forwardToReplicas:s,...a}=r||{},n=gl.createMappedRequestOptions(a);return s&&(n.queryParameters.forwardToReplicas=1),Jt.createWaitablePromise(t.transporter.write({method:br.MethodEnum.Delete,path:Jt.encode("1/indexes/%s/rules/%s",t.indexName,e)},n),(c,f)=>hs(t)(c.taskID,f))},Mft=t=>(e,r)=>{let{forwardToReplicas:s,...a}=r||{},n=gl.createMappedRequestOptions(a);return s&&(n.queryParameters.forwardToReplicas=1),Jt.createWaitablePromise(t.transporter.write({method:br.MethodEnum.Delete,path:Jt.encode("1/indexes/%s/synonyms/%s",t.indexName,e)},n),(c,f)=>hs(t)(c.taskID,f))},Uft=t=>e=>wIe(t)(e).then(()=>!0).catch(r=>{if(r.status!==404)throw r;return!1}),_ft=t=>(e,r,s)=>t.transporter.read({method:br.MethodEnum.Post,path:Jt.encode("1/answers/%s/prediction",t.indexName),data:{query:e,queryLanguages:r},cacheable:!0},s),Hft=t=>(e,r)=>{let{query:s,paginate:a,...n}=r||{},c=0,f=()=>SIe(t)(s||"",{...n,page:c}).then(p=>{for(let[h,E]of Object.entries(p.hits))if(e(E))return{object:E,position:parseInt(h,10),page:c};if(c++,a===!1||c>=p.nbPages)throw mIe();return f()});return f()},jft=t=>(e,r)=>t.transporter.read({method:br.MethodEnum.Get,path:Jt.encode("1/indexes/%s/%s",t.indexName,e)},r),Gft=()=>(t,e)=>{for(let[r,s]of Object.entries(t.hits))if(s.objectID===e)return parseInt(r,10);return-1},qft=t=>(e,r)=>{let{attributesToRetrieve:s,...a}=r||{},n=e.map(c=>({indexName:t.indexName,objectID:c,...s?{attributesToRetrieve:s}:{}}));return t.transporter.read({method:br.MethodEnum.Post,path:"1/indexes/*/objects",data:{requests:n}},a)},Wft=t=>(e,r)=>t.transporter.read({method:br.MethodEnum.Get,path:Jt.encode("1/indexes/%s/rules/%s",t.indexName,e)},r),wIe=t=>e=>t.transporter.read({method:br.MethodEnum.Get,path:Jt.encode("1/indexes/%s/settings",t.indexName),data:{getVersion:2}},e),Yft=t=>(e,r)=>t.transporter.read({method:br.MethodEnum.Get,path:Jt.encode("1/indexes/%s/synonyms/%s",t.indexName,e)},r),BIe=t=>(e,r)=>t.transporter.read({method:br.MethodEnum.Get,path:Jt.encode("1/indexes/%s/task/%s",t.indexName,e.toString())},r),Vft=t=>(e,r)=>Jt.createWaitablePromise(vIe(t)([e],r).then(s=>({objectID:s.objectIDs[0],taskID:s.taskIDs[0]})),(s,a)=>hs(t)(s.taskID,a)),vIe=t=>(e,r)=>{let{createIfNotExists:s,...a}=r||{},n=s?km.PartialUpdateObject:km.PartialUpdateObjectNoCreate;return hF(t)(e,n,a)},Jft=t=>(e,r)=>{let{safe:s,autoGenerateObjectIDIfNotExist:a,batchSize:n,...c}=r||{},f=(I,R,N,U)=>Jt.createWaitablePromise(t.transporter.write({method:br.MethodEnum.Post,path:Jt.encode("1/indexes/%s/operation",I),data:{operation:N,destination:R}},U),(W,ee)=>hs(t)(W.taskID,ee)),p=Math.random().toString(36).substring(7),h=`${t.indexName}_tmp_${p}`,E=l9({appId:t.appId,transporter:t.transporter,indexName:h}),C=[],S=f(t.indexName,h,"copy",{...c,scope:["settings","synonyms","rules"]});C.push(S);let P=(s?S.wait(c):S).then(()=>{let I=E(e,{...c,autoGenerateObjectIDIfNotExist:a,batchSize:n});return C.push(I),s?I.wait(c):I}).then(()=>{let I=f(h,t.indexName,"move",c);return C.push(I),s?I.wait(c):I}).then(()=>Promise.all(C)).then(([I,R,N])=>({objectIDs:R.objectIDs,taskIDs:[I.taskID,...R.taskIDs,N.taskID]}));return Jt.createWaitablePromise(P,(I,R)=>Promise.all(C.map(N=>N.wait(R))))},Kft=t=>(e,r)=>c9(t)(e,{...r,clearExistingRules:!0}),zft=t=>(e,r)=>u9(t)(e,{...r,clearExistingSynonyms:!0}),Xft=t=>(e,r)=>Jt.createWaitablePromise(l9(t)([e],r).then(s=>({objectID:s.objectIDs[0],taskID:s.taskIDs[0]})),(s,a)=>hs(t)(s.taskID,a)),l9=t=>(e,r)=>{let{autoGenerateObjectIDIfNotExist:s,...a}=r||{},n=s?km.AddObject:km.UpdateObject;if(n===km.UpdateObject){for(let c of e)if(c.objectID===void 0)return Jt.createWaitablePromise(Promise.reject(dIe()))}return hF(t)(e,n,a)},Zft=t=>(e,r)=>c9(t)([e],r),c9=t=>(e,r)=>{let{forwardToReplicas:s,clearExistingRules:a,...n}=r||{},c=gl.createMappedRequestOptions(n);return s&&(c.queryParameters.forwardToReplicas=1),a&&(c.queryParameters.clearExistingRules=1),Jt.createWaitablePromise(t.transporter.write({method:br.MethodEnum.Post,path:Jt.encode("1/indexes/%s/rules/batch",t.indexName),data:e},c),(f,p)=>hs(t)(f.taskID,p))},$ft=t=>(e,r)=>u9(t)([e],r),u9=t=>(e,r)=>{let{forwardToReplicas:s,clearExistingSynonyms:a,replaceExistingSynonyms:n,...c}=r||{},f=gl.createMappedRequestOptions(c);return s&&(f.queryParameters.forwardToReplicas=1),(n||a)&&(f.queryParameters.replaceExistingSynonyms=1),Jt.createWaitablePromise(t.transporter.write({method:br.MethodEnum.Post,path:Jt.encode("1/indexes/%s/synonyms/batch",t.indexName),data:e},f),(p,h)=>hs(t)(p.taskID,h))},SIe=t=>(e,r)=>t.transporter.read({method:br.MethodEnum.Post,path:Jt.encode("1/indexes/%s/query",t.indexName),data:{query:e},cacheable:!0},r),DIe=t=>(e,r,s)=>t.transporter.read({method:br.MethodEnum.Post,path:Jt.encode("1/indexes/%s/facets/%s/query",t.indexName,e),data:{facetQuery:r},cacheable:!0},s),bIe=t=>(e,r)=>t.transporter.read({method:br.MethodEnum.Post,path:Jt.encode("1/indexes/%s/rules/search",t.indexName),data:{query:e}},r),PIe=t=>(e,r)=>t.transporter.read({method:br.MethodEnum.Post,path:Jt.encode("1/indexes/%s/synonyms/search",t.indexName),data:{query:e}},r),eAt=t=>(e,r)=>{let{forwardToReplicas:s,...a}=r||{},n=gl.createMappedRequestOptions(a);return s&&(n.queryParameters.forwardToReplicas=1),Jt.createWaitablePromise(t.transporter.write({method:br.MethodEnum.Put,path:Jt.encode("1/indexes/%s/settings",t.indexName),data:e},n),(c,f)=>hs(t)(c.taskID,f))},hs=t=>(e,r)=>Jt.createRetryablePromise(s=>BIe(t)(e,r).then(a=>a.status!=="published"?s():void 0)),tAt={AddObject:"addObject",Analytics:"analytics",Browser:"browse",DeleteIndex:"deleteIndex",DeleteObject:"deleteObject",EditSettings:"editSettings",Inference:"inference",ListIndexes:"listIndexes",Logs:"logs",Personalization:"personalization",Recommendation:"recommendation",Search:"search",SeeUnretrievableAttributes:"seeUnretrievableAttributes",Settings:"settings",Usage:"usage"},km={AddObject:"addObject",UpdateObject:"updateObject",PartialUpdateObject:"partialUpdateObject",PartialUpdateObjectNoCreate:"partialUpdateObjectNoCreate",DeleteObject:"deleteObject",DeleteIndex:"delete",ClearIndex:"clear"},gF={Settings:"settings",Synonyms:"synonyms",Rules:"rules"},rAt={None:"none",StopIfEnoughMatches:"stopIfEnoughMatches"},nAt={Synonym:"synonym",OneWaySynonym:"oneWaySynonym",AltCorrection1:"altCorrection1",AltCorrection2:"altCorrection2",Placeholder:"placeholder"};Ft.ApiKeyACLEnum=tAt;Ft.BatchActionEnum=km;Ft.ScopeEnum=gF;Ft.StrategyEnum=rAt;Ft.SynonymEnum=nAt;Ft.addApiKey=Jut;Ft.assignUserID=Kut;Ft.assignUserIDs=zut;Ft.batch=IIe;Ft.browseObjects=Pft;Ft.browseRules=xft;Ft.browseSynonyms=kft;Ft.chunkedBatch=hF;Ft.clearDictionaryEntries=Xut;Ft.clearObjects=Qft;Ft.clearRules=Tft;Ft.clearSynonyms=Rft;Ft.copyIndex=pF;Ft.copyRules=Zut;Ft.copySettings=$ut;Ft.copySynonyms=eft;Ft.createBrowsablePromise=AF;Ft.createMissingObjectIDError=dIe;Ft.createObjectNotFoundError=mIe;Ft.createSearchClient=Vut;Ft.createValidUntilNotFoundError=yIe;Ft.customRequest=tft;Ft.deleteApiKey=rft;Ft.deleteBy=Fft;Ft.deleteDictionaryEntries=nft;Ft.deleteIndex=Nft;Ft.deleteObject=Oft;Ft.deleteObjects=CIe;Ft.deleteRule=Lft;Ft.deleteSynonym=Mft;Ft.exists=Uft;Ft.findAnswers=_ft;Ft.findObject=Hft;Ft.generateSecuredApiKey=ift;Ft.getApiKey=kS;Ft.getAppTask=EIe;Ft.getDictionarySettings=sft;Ft.getLogs=oft;Ft.getObject=jft;Ft.getObjectPosition=Gft;Ft.getObjects=qft;Ft.getRule=Wft;Ft.getSecuredApiKeyRemainingValidity=aft;Ft.getSettings=wIe;Ft.getSynonym=Yft;Ft.getTask=BIe;Ft.getTopUserIDs=lft;Ft.getUserID=cft;Ft.hasPendingMappings=uft;Ft.initIndex=QS;Ft.listApiKeys=fft;Ft.listClusters=Aft;Ft.listIndices=pft;Ft.listUserIDs=hft;Ft.moveIndex=gft;Ft.multipleBatch=dft;Ft.multipleGetObjects=mft;Ft.multipleQueries=yft;Ft.multipleSearchForFacetValues=Eft;Ft.partialUpdateObject=Vft;Ft.partialUpdateObjects=vIe;Ft.removeUserID=Ift;Ft.replaceAllObjects=Jft;Ft.replaceAllRules=Kft;Ft.replaceAllSynonyms=zft;Ft.replaceDictionaryEntries=Cft;Ft.restoreApiKey=wft;Ft.saveDictionaryEntries=Bft;Ft.saveObject=Xft;Ft.saveObjects=l9;Ft.saveRule=Zft;Ft.saveRules=c9;Ft.saveSynonym=$ft;Ft.saveSynonyms=u9;Ft.search=SIe;Ft.searchDictionaryEntries=vft;Ft.searchForFacetValues=DIe;Ft.searchRules=bIe;Ft.searchSynonyms=PIe;Ft.searchUserIDs=Sft;Ft.setDictionarySettings=Dft;Ft.setSettings=eAt;Ft.updateApiKey=bft;Ft.waitAppTask=aw;Ft.waitTask=hs});var QIe=_((LJt,kIe)=>{kIe.exports=xIe()});var TIe=_(dF=>{"use strict";Object.defineProperty(dF,"__esModule",{value:!0});function iAt(){return{debug(t,e){return Promise.resolve()},info(t,e){return Promise.resolve()},error(t,e){return Promise.resolve()}}}var sAt={Debug:1,Info:2,Error:3};dF.LogLevelEnum=sAt;dF.createNullLogger=iAt});var FIe=_((UJt,RIe)=>{RIe.exports=TIe()});var MIe=_(f9=>{"use strict";Object.defineProperty(f9,"__esModule",{value:!0});var NIe=Ie("http"),OIe=Ie("https"),oAt=Ie("url"),LIe={keepAlive:!0},aAt=new NIe.Agent(LIe),lAt=new OIe.Agent(LIe);function cAt({agent:t,httpAgent:e,httpsAgent:r,requesterOptions:s={}}={}){let a=e||t||aAt,n=r||t||lAt;return{send(c){return new Promise(f=>{let p=oAt.parse(c.url),h=p.query===null?p.pathname:`${p.pathname}?${p.query}`,E={...s,agent:p.protocol==="https:"?n:a,hostname:p.hostname,path:h,method:c.method,headers:{...s&&s.headers?s.headers:{},...c.headers},...p.port!==void 0?{port:p.port||""}:{}},C=(p.protocol==="https:"?OIe:NIe).request(E,R=>{let N=[];R.on("data",U=>{N=N.concat(U)}),R.on("end",()=>{clearTimeout(P),clearTimeout(I),f({status:R.statusCode||0,content:Buffer.concat(N).toString(),isTimedOut:!1})})}),S=(R,N)=>setTimeout(()=>{C.abort(),f({status:0,content:N,isTimedOut:!0})},R*1e3),P=S(c.connectTimeout,"Connection timeout"),I;C.on("error",R=>{clearTimeout(P),clearTimeout(I),f({status:0,content:R.message,isTimedOut:!1})}),C.once("response",()=>{clearTimeout(P),I=S(c.responseTimeout,"Socket timeout")}),c.data!==void 0&&C.write(c.data),C.end()})},destroy(){return a.destroy(),n.destroy(),Promise.resolve()}}}f9.createNodeHttpRequester=cAt});var _Ie=_((HJt,UIe)=>{UIe.exports=MIe()});var qIe=_((jJt,GIe)=>{"use strict";var HIe=MEe(),uAt=HEe(),lw=fIe(),p9=vS(),A9=gIe(),Gt=QIe(),fAt=FIe(),AAt=_Ie(),pAt=bS();function jIe(t,e,r){let s={appId:t,apiKey:e,timeouts:{connect:2,read:5,write:30},requester:AAt.createNodeHttpRequester(),logger:fAt.createNullLogger(),responsesCache:HIe.createNullCache(),requestsCache:HIe.createNullCache(),hostsCache:uAt.createInMemoryCache(),userAgent:pAt.createUserAgent(p9.version).add({segment:"Node.js",version:process.versions.node})},a={...s,...r},n=()=>c=>A9.createPersonalizationClient({...s,...c,methods:{getPersonalizationStrategy:A9.getPersonalizationStrategy,setPersonalizationStrategy:A9.setPersonalizationStrategy}});return Gt.createSearchClient({...a,methods:{search:Gt.multipleQueries,searchForFacetValues:Gt.multipleSearchForFacetValues,multipleBatch:Gt.multipleBatch,multipleGetObjects:Gt.multipleGetObjects,multipleQueries:Gt.multipleQueries,copyIndex:Gt.copyIndex,copySettings:Gt.copySettings,copyRules:Gt.copyRules,copySynonyms:Gt.copySynonyms,moveIndex:Gt.moveIndex,listIndices:Gt.listIndices,getLogs:Gt.getLogs,listClusters:Gt.listClusters,multipleSearchForFacetValues:Gt.multipleSearchForFacetValues,getApiKey:Gt.getApiKey,addApiKey:Gt.addApiKey,listApiKeys:Gt.listApiKeys,updateApiKey:Gt.updateApiKey,deleteApiKey:Gt.deleteApiKey,restoreApiKey:Gt.restoreApiKey,assignUserID:Gt.assignUserID,assignUserIDs:Gt.assignUserIDs,getUserID:Gt.getUserID,searchUserIDs:Gt.searchUserIDs,listUserIDs:Gt.listUserIDs,getTopUserIDs:Gt.getTopUserIDs,removeUserID:Gt.removeUserID,hasPendingMappings:Gt.hasPendingMappings,generateSecuredApiKey:Gt.generateSecuredApiKey,getSecuredApiKeyRemainingValidity:Gt.getSecuredApiKeyRemainingValidity,destroy:p9.destroy,clearDictionaryEntries:Gt.clearDictionaryEntries,deleteDictionaryEntries:Gt.deleteDictionaryEntries,getDictionarySettings:Gt.getDictionarySettings,getAppTask:Gt.getAppTask,replaceDictionaryEntries:Gt.replaceDictionaryEntries,saveDictionaryEntries:Gt.saveDictionaryEntries,searchDictionaryEntries:Gt.searchDictionaryEntries,setDictionarySettings:Gt.setDictionarySettings,waitAppTask:Gt.waitAppTask,customRequest:Gt.customRequest,initIndex:c=>f=>Gt.initIndex(c)(f,{methods:{batch:Gt.batch,delete:Gt.deleteIndex,findAnswers:Gt.findAnswers,getObject:Gt.getObject,getObjects:Gt.getObjects,saveObject:Gt.saveObject,saveObjects:Gt.saveObjects,search:Gt.search,searchForFacetValues:Gt.searchForFacetValues,waitTask:Gt.waitTask,setSettings:Gt.setSettings,getSettings:Gt.getSettings,partialUpdateObject:Gt.partialUpdateObject,partialUpdateObjects:Gt.partialUpdateObjects,deleteObject:Gt.deleteObject,deleteObjects:Gt.deleteObjects,deleteBy:Gt.deleteBy,clearObjects:Gt.clearObjects,browseObjects:Gt.browseObjects,getObjectPosition:Gt.getObjectPosition,findObject:Gt.findObject,exists:Gt.exists,saveSynonym:Gt.saveSynonym,saveSynonyms:Gt.saveSynonyms,getSynonym:Gt.getSynonym,searchSynonyms:Gt.searchSynonyms,browseSynonyms:Gt.browseSynonyms,deleteSynonym:Gt.deleteSynonym,clearSynonyms:Gt.clearSynonyms,replaceAllObjects:Gt.replaceAllObjects,replaceAllSynonyms:Gt.replaceAllSynonyms,searchRules:Gt.searchRules,getRule:Gt.getRule,deleteRule:Gt.deleteRule,saveRule:Gt.saveRule,saveRules:Gt.saveRules,replaceAllRules:Gt.replaceAllRules,browseRules:Gt.browseRules,clearRules:Gt.clearRules}}),initAnalytics:()=>c=>lw.createAnalyticsClient({...s,...c,methods:{addABTest:lw.addABTest,getABTest:lw.getABTest,getABTests:lw.getABTests,stopABTest:lw.stopABTest,deleteABTest:lw.deleteABTest}}),initPersonalization:n,initRecommendation:()=>c=>(a.logger.info("The `initRecommendation` method is deprecated. Use `initPersonalization` instead."),n()(c))}})}jIe.version=p9.version;GIe.exports=jIe});var g9=_((GJt,h9)=>{var WIe=qIe();h9.exports=WIe;h9.exports.default=WIe});var y9=_((WJt,JIe)=>{"use strict";var VIe=Object.getOwnPropertySymbols,gAt=Object.prototype.hasOwnProperty,dAt=Object.prototype.propertyIsEnumerable;function mAt(t){if(t==null)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(t)}function yAt(){try{if(!Object.assign)return!1;var t=new String("abc");if(t[5]="de",Object.getOwnPropertyNames(t)[0]==="5")return!1;for(var e={},r=0;r<10;r++)e["_"+String.fromCharCode(r)]=r;var s=Object.getOwnPropertyNames(e).map(function(n){return e[n]});if(s.join("")!=="0123456789")return!1;var a={};return"abcdefghijklmnopqrst".split("").forEach(function(n){a[n]=n}),Object.keys(Object.assign({},a)).join("")==="abcdefghijklmnopqrst"}catch{return!1}}JIe.exports=yAt()?Object.assign:function(t,e){for(var r,s=mAt(t),a,n=1;n{"use strict";var I9=y9(),cw=60103,XIe=60106;Dn.Fragment=60107;Dn.StrictMode=60108;Dn.Profiler=60114;var ZIe=60109,$Ie=60110,eCe=60112;Dn.Suspense=60113;var tCe=60115,rCe=60116;typeof Symbol=="function"&&Symbol.for&&(Gc=Symbol.for,cw=Gc("react.element"),XIe=Gc("react.portal"),Dn.Fragment=Gc("react.fragment"),Dn.StrictMode=Gc("react.strict_mode"),Dn.Profiler=Gc("react.profiler"),ZIe=Gc("react.provider"),$Ie=Gc("react.context"),eCe=Gc("react.forward_ref"),Dn.Suspense=Gc("react.suspense"),tCe=Gc("react.memo"),rCe=Gc("react.lazy"));var Gc,KIe=typeof Symbol=="function"&&Symbol.iterator;function EAt(t){return t===null||typeof t!="object"?null:(t=KIe&&t[KIe]||t["@@iterator"],typeof t=="function"?t:null)}function TS(t){for(var e="https://reactjs.org/docs/error-decoder.html?invariant="+t,r=1;r{"use strict";fCe.exports=uCe()});var EF=_((JJt,ACe)=>{function vAt(t){var e=typeof t;return t!=null&&(e=="object"||e=="function")}ACe.exports=vAt});var hCe=_((KJt,pCe)=>{var SAt=typeof global=="object"&&global&&global.Object===Object&&global;pCe.exports=SAt});var S9=_((zJt,gCe)=>{var DAt=hCe(),bAt=typeof self=="object"&&self&&self.Object===Object&&self,PAt=DAt||bAt||Function("return this")();gCe.exports=PAt});var mCe=_((XJt,dCe)=>{var xAt=S9(),kAt=function(){return xAt.Date.now()};dCe.exports=kAt});var ECe=_((ZJt,yCe)=>{var QAt=/\s/;function TAt(t){for(var e=t.length;e--&&QAt.test(t.charAt(e)););return e}yCe.exports=TAt});var CCe=_(($Jt,ICe)=>{var RAt=ECe(),FAt=/^\s+/;function NAt(t){return t&&t.slice(0,RAt(t)+1).replace(FAt,"")}ICe.exports=NAt});var D9=_((eKt,wCe)=>{var OAt=S9(),LAt=OAt.Symbol;wCe.exports=LAt});var DCe=_((tKt,SCe)=>{var BCe=D9(),vCe=Object.prototype,MAt=vCe.hasOwnProperty,UAt=vCe.toString,RS=BCe?BCe.toStringTag:void 0;function _At(t){var e=MAt.call(t,RS),r=t[RS];try{t[RS]=void 0;var s=!0}catch{}var a=UAt.call(t);return s&&(e?t[RS]=r:delete t[RS]),a}SCe.exports=_At});var PCe=_((rKt,bCe)=>{var HAt=Object.prototype,jAt=HAt.toString;function GAt(t){return jAt.call(t)}bCe.exports=GAt});var TCe=_((nKt,QCe)=>{var xCe=D9(),qAt=DCe(),WAt=PCe(),YAt="[object Null]",VAt="[object Undefined]",kCe=xCe?xCe.toStringTag:void 0;function JAt(t){return t==null?t===void 0?VAt:YAt:kCe&&kCe in Object(t)?qAt(t):WAt(t)}QCe.exports=JAt});var FCe=_((iKt,RCe)=>{function KAt(t){return t!=null&&typeof t=="object"}RCe.exports=KAt});var OCe=_((sKt,NCe)=>{var zAt=TCe(),XAt=FCe(),ZAt="[object Symbol]";function $At(t){return typeof t=="symbol"||XAt(t)&&zAt(t)==ZAt}NCe.exports=$At});var _Ce=_((oKt,UCe)=>{var ept=CCe(),LCe=EF(),tpt=OCe(),MCe=NaN,rpt=/^[-+]0x[0-9a-f]+$/i,npt=/^0b[01]+$/i,ipt=/^0o[0-7]+$/i,spt=parseInt;function opt(t){if(typeof t=="number")return t;if(tpt(t))return MCe;if(LCe(t)){var e=typeof t.valueOf=="function"?t.valueOf():t;t=LCe(e)?e+"":e}if(typeof t!="string")return t===0?t:+t;t=ept(t);var r=npt.test(t);return r||ipt.test(t)?spt(t.slice(2),r?2:8):rpt.test(t)?MCe:+t}UCe.exports=opt});var GCe=_((aKt,jCe)=>{var apt=EF(),b9=mCe(),HCe=_Ce(),lpt="Expected a function",cpt=Math.max,upt=Math.min;function fpt(t,e,r){var s,a,n,c,f,p,h=0,E=!1,C=!1,S=!0;if(typeof t!="function")throw new TypeError(lpt);e=HCe(e)||0,apt(r)&&(E=!!r.leading,C="maxWait"in r,n=C?cpt(HCe(r.maxWait)||0,e):n,S="trailing"in r?!!r.trailing:S);function P(le){var me=s,pe=a;return s=a=void 0,h=le,c=t.apply(pe,me),c}function I(le){return h=le,f=setTimeout(U,e),E?P(le):c}function R(le){var me=le-p,pe=le-h,Be=e-me;return C?upt(Be,n-pe):Be}function N(le){var me=le-p,pe=le-h;return p===void 0||me>=e||me<0||C&&pe>=n}function U(){var le=b9();if(N(le))return W(le);f=setTimeout(U,R(le))}function W(le){return f=void 0,S&&s?P(le):(s=a=void 0,c)}function ee(){f!==void 0&&clearTimeout(f),h=0,s=p=a=f=void 0}function ie(){return f===void 0?c:W(b9())}function ue(){var le=b9(),me=N(le);if(s=arguments,a=this,p=le,me){if(f===void 0)return I(p);if(C)return clearTimeout(f),f=setTimeout(U,e),P(p)}return f===void 0&&(f=setTimeout(U,e)),c}return ue.cancel=ee,ue.flush=ie,ue}jCe.exports=fpt});var WCe=_((lKt,qCe)=>{var Apt=GCe(),ppt=EF(),hpt="Expected a function";function gpt(t,e,r){var s=!0,a=!0;if(typeof t!="function")throw new TypeError(hpt);return ppt(r)&&(s="leading"in r?!!r.leading:s,a="trailing"in r?!!r.trailing:a),Apt(t,e,{leading:s,maxWait:e,trailing:a})}qCe.exports=gpt});var x9=_((cKt,P9)=>{"use strict";var Cn=P9.exports;P9.exports.default=Cn;var Xn="\x1B[",NS="\x1B]",fw="\x07",IF=";",YCe=process.env.TERM_PROGRAM==="Apple_Terminal";Cn.cursorTo=(t,e)=>{if(typeof t!="number")throw new TypeError("The `x` argument is required");return typeof e!="number"?Xn+(t+1)+"G":Xn+(e+1)+";"+(t+1)+"H"};Cn.cursorMove=(t,e)=>{if(typeof t!="number")throw new TypeError("The `x` argument is required");let r="";return t<0?r+=Xn+-t+"D":t>0&&(r+=Xn+t+"C"),e<0?r+=Xn+-e+"A":e>0&&(r+=Xn+e+"B"),r};Cn.cursorUp=(t=1)=>Xn+t+"A";Cn.cursorDown=(t=1)=>Xn+t+"B";Cn.cursorForward=(t=1)=>Xn+t+"C";Cn.cursorBackward=(t=1)=>Xn+t+"D";Cn.cursorLeft=Xn+"G";Cn.cursorSavePosition=YCe?"\x1B7":Xn+"s";Cn.cursorRestorePosition=YCe?"\x1B8":Xn+"u";Cn.cursorGetPosition=Xn+"6n";Cn.cursorNextLine=Xn+"E";Cn.cursorPrevLine=Xn+"F";Cn.cursorHide=Xn+"?25l";Cn.cursorShow=Xn+"?25h";Cn.eraseLines=t=>{let e="";for(let r=0;r[NS,"8",IF,IF,e,fw,t,NS,"8",IF,IF,fw].join("");Cn.image=(t,e={})=>{let r=`${NS}1337;File=inline=1`;return e.width&&(r+=`;width=${e.width}`),e.height&&(r+=`;height=${e.height}`),e.preserveAspectRatio===!1&&(r+=";preserveAspectRatio=0"),r+":"+t.toString("base64")+fw};Cn.iTerm={setCwd:(t=process.cwd())=>`${NS}50;CurrentDir=${t}${fw}`,annotation:(t,e={})=>{let r=`${NS}1337;`,s=typeof e.x<"u",a=typeof e.y<"u";if((s||a)&&!(s&&a&&typeof e.length<"u"))throw new Error("`x`, `y` and `length` must be defined when `x` or `y` is defined");return t=t.replace(/\|/g,""),r+=e.isHidden?"AddHiddenAnnotation=":"AddAnnotation=",e.length>0?r+=(s?[t,e.length,e.x,e.y]:[e.length,t]).join("|"):r+=t,r+fw}}});var JCe=_((uKt,k9)=>{"use strict";var VCe=(t,e)=>{for(let r of Reflect.ownKeys(e))Object.defineProperty(t,r,Object.getOwnPropertyDescriptor(e,r));return t};k9.exports=VCe;k9.exports.default=VCe});var zCe=_((fKt,wF)=>{"use strict";var dpt=JCe(),CF=new WeakMap,KCe=(t,e={})=>{if(typeof t!="function")throw new TypeError("Expected a function");let r,s=0,a=t.displayName||t.name||"",n=function(...c){if(CF.set(n,++s),s===1)r=t.apply(this,c),t=null;else if(e.throw===!0)throw new Error(`Function \`${a}\` can only be called once`);return r};return dpt(n,t),CF.set(n,s),n};wF.exports=KCe;wF.exports.default=KCe;wF.exports.callCount=t=>{if(!CF.has(t))throw new Error(`The given function \`${t.name}\` is not wrapped by the \`onetime\` package`);return CF.get(t)}});var XCe=_((AKt,BF)=>{BF.exports=["SIGABRT","SIGALRM","SIGHUP","SIGINT","SIGTERM"];process.platform!=="win32"&&BF.exports.push("SIGVTALRM","SIGXCPU","SIGXFSZ","SIGUSR2","SIGTRAP","SIGSYS","SIGQUIT","SIGIOT");process.platform==="linux"&&BF.exports.push("SIGIO","SIGPOLL","SIGPWR","SIGSTKFLT","SIGUNUSED")});var R9=_((pKt,hw)=>{var Qi=global.process,Qm=function(t){return t&&typeof t=="object"&&typeof t.removeListener=="function"&&typeof t.emit=="function"&&typeof t.reallyExit=="function"&&typeof t.listeners=="function"&&typeof t.kill=="function"&&typeof t.pid=="number"&&typeof t.on=="function"};Qm(Qi)?(ZCe=Ie("assert"),Aw=XCe(),$Ce=/^win/i.test(Qi.platform),OS=Ie("events"),typeof OS!="function"&&(OS=OS.EventEmitter),Qi.__signal_exit_emitter__?Js=Qi.__signal_exit_emitter__:(Js=Qi.__signal_exit_emitter__=new OS,Js.count=0,Js.emitted={}),Js.infinite||(Js.setMaxListeners(1/0),Js.infinite=!0),hw.exports=function(t,e){if(!Qm(global.process))return function(){};ZCe.equal(typeof t,"function","a callback must be provided for exit handler"),pw===!1&&Q9();var r="exit";e&&e.alwaysLast&&(r="afterexit");var s=function(){Js.removeListener(r,t),Js.listeners("exit").length===0&&Js.listeners("afterexit").length===0&&vF()};return Js.on(r,t),s},vF=function(){!pw||!Qm(global.process)||(pw=!1,Aw.forEach(function(e){try{Qi.removeListener(e,SF[e])}catch{}}),Qi.emit=DF,Qi.reallyExit=T9,Js.count-=1)},hw.exports.unload=vF,Tm=function(e,r,s){Js.emitted[e]||(Js.emitted[e]=!0,Js.emit(e,r,s))},SF={},Aw.forEach(function(t){SF[t]=function(){if(Qm(global.process)){var r=Qi.listeners(t);r.length===Js.count&&(vF(),Tm("exit",null,t),Tm("afterexit",null,t),$Ce&&t==="SIGHUP"&&(t="SIGINT"),Qi.kill(Qi.pid,t))}}}),hw.exports.signals=function(){return Aw},pw=!1,Q9=function(){pw||!Qm(global.process)||(pw=!0,Js.count+=1,Aw=Aw.filter(function(e){try{return Qi.on(e,SF[e]),!0}catch{return!1}}),Qi.emit=twe,Qi.reallyExit=ewe)},hw.exports.load=Q9,T9=Qi.reallyExit,ewe=function(e){Qm(global.process)&&(Qi.exitCode=e||0,Tm("exit",Qi.exitCode,null),Tm("afterexit",Qi.exitCode,null),T9.call(Qi,Qi.exitCode))},DF=Qi.emit,twe=function(e,r){if(e==="exit"&&Qm(global.process)){r!==void 0&&(Qi.exitCode=r);var s=DF.apply(this,arguments);return Tm("exit",Qi.exitCode,null),Tm("afterexit",Qi.exitCode,null),s}else return DF.apply(this,arguments)}):hw.exports=function(){return function(){}};var ZCe,Aw,$Ce,OS,Js,vF,Tm,SF,pw,Q9,T9,ewe,DF,twe});var nwe=_((hKt,rwe)=>{"use strict";var mpt=zCe(),ypt=R9();rwe.exports=mpt(()=>{ypt(()=>{process.stderr.write("\x1B[?25h")},{alwaysLast:!0})})});var F9=_(gw=>{"use strict";var Ept=nwe(),bF=!1;gw.show=(t=process.stderr)=>{t.isTTY&&(bF=!1,t.write("\x1B[?25h"))};gw.hide=(t=process.stderr)=>{t.isTTY&&(Ept(),bF=!0,t.write("\x1B[?25l"))};gw.toggle=(t,e)=>{t!==void 0&&(bF=t),bF?gw.show(e):gw.hide(e)}});var awe=_(LS=>{"use strict";var owe=LS&&LS.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(LS,"__esModule",{value:!0});var iwe=owe(x9()),swe=owe(F9()),Ipt=(t,{showCursor:e=!1}={})=>{let r=0,s="",a=!1,n=c=>{!e&&!a&&(swe.default.hide(),a=!0);let f=c+` +`;f!==s&&(s=f,t.write(iwe.default.eraseLines(r)+f),r=f.split(` +`).length)};return n.clear=()=>{t.write(iwe.default.eraseLines(r)),s="",r=0},n.done=()=>{s="",r=0,e||(swe.default.show(),a=!1)},n};LS.default={create:Ipt}});var lwe=_((mKt,Cpt)=>{Cpt.exports=[{name:"AppVeyor",constant:"APPVEYOR",env:"APPVEYOR",pr:"APPVEYOR_PULL_REQUEST_NUMBER"},{name:"Azure Pipelines",constant:"AZURE_PIPELINES",env:"SYSTEM_TEAMFOUNDATIONCOLLECTIONURI",pr:"SYSTEM_PULLREQUEST_PULLREQUESTID"},{name:"Bamboo",constant:"BAMBOO",env:"bamboo_planKey"},{name:"Bitbucket Pipelines",constant:"BITBUCKET",env:"BITBUCKET_COMMIT",pr:"BITBUCKET_PR_ID"},{name:"Bitrise",constant:"BITRISE",env:"BITRISE_IO",pr:"BITRISE_PULL_REQUEST"},{name:"Buddy",constant:"BUDDY",env:"BUDDY_WORKSPACE_ID",pr:"BUDDY_EXECUTION_PULL_REQUEST_ID"},{name:"Buildkite",constant:"BUILDKITE",env:"BUILDKITE",pr:{env:"BUILDKITE_PULL_REQUEST",ne:"false"}},{name:"CircleCI",constant:"CIRCLE",env:"CIRCLECI",pr:"CIRCLE_PULL_REQUEST"},{name:"Cirrus CI",constant:"CIRRUS",env:"CIRRUS_CI",pr:"CIRRUS_PR"},{name:"AWS CodeBuild",constant:"CODEBUILD",env:"CODEBUILD_BUILD_ARN"},{name:"Codeship",constant:"CODESHIP",env:{CI_NAME:"codeship"}},{name:"Drone",constant:"DRONE",env:"DRONE",pr:{DRONE_BUILD_EVENT:"pull_request"}},{name:"dsari",constant:"DSARI",env:"DSARI"},{name:"GitLab CI",constant:"GITLAB",env:"GITLAB_CI"},{name:"GoCD",constant:"GOCD",env:"GO_PIPELINE_LABEL"},{name:"Hudson",constant:"HUDSON",env:"HUDSON_URL"},{name:"Jenkins",constant:"JENKINS",env:["JENKINS_URL","BUILD_ID"],pr:{any:["ghprbPullId","CHANGE_ID"]}},{name:"Magnum CI",constant:"MAGNUM",env:"MAGNUM"},{name:"Netlify CI",constant:"NETLIFY",env:"NETLIFY_BUILD_BASE",pr:{env:"PULL_REQUEST",ne:"false"}},{name:"Sail CI",constant:"SAIL",env:"SAILCI",pr:"SAIL_PULL_REQUEST_NUMBER"},{name:"Semaphore",constant:"SEMAPHORE",env:"SEMAPHORE",pr:"PULL_REQUEST_NUMBER"},{name:"Shippable",constant:"SHIPPABLE",env:"SHIPPABLE",pr:{IS_PULL_REQUEST:"true"}},{name:"Solano CI",constant:"SOLANO",env:"TDDIUM",pr:"TDDIUM_PR_ID"},{name:"Strider CD",constant:"STRIDER",env:"STRIDER"},{name:"TaskCluster",constant:"TASKCLUSTER",env:["TASK_ID","RUN_ID"]},{name:"TeamCity",constant:"TEAMCITY",env:"TEAMCITY_VERSION"},{name:"Travis CI",constant:"TRAVIS",env:"TRAVIS",pr:{env:"TRAVIS_PULL_REQUEST",ne:"false"}}]});var fwe=_(tc=>{"use strict";var uwe=lwe(),uA=process.env;Object.defineProperty(tc,"_vendors",{value:uwe.map(function(t){return t.constant})});tc.name=null;tc.isPR=null;uwe.forEach(function(t){var e=Array.isArray(t.env)?t.env:[t.env],r=e.every(function(s){return cwe(s)});if(tc[t.constant]=r,r)switch(tc.name=t.name,typeof t.pr){case"string":tc.isPR=!!uA[t.pr];break;case"object":"env"in t.pr?tc.isPR=t.pr.env in uA&&uA[t.pr.env]!==t.pr.ne:"any"in t.pr?tc.isPR=t.pr.any.some(function(s){return!!uA[s]}):tc.isPR=cwe(t.pr);break;default:tc.isPR=null}});tc.isCI=!!(uA.CI||uA.CONTINUOUS_INTEGRATION||uA.BUILD_NUMBER||uA.RUN_ID||tc.name);function cwe(t){return typeof t=="string"?!!uA[t]:Object.keys(t).every(function(e){return uA[e]===t[e]})}});var pwe=_((EKt,Awe)=>{"use strict";Awe.exports=fwe().isCI});var gwe=_((IKt,hwe)=>{"use strict";var wpt=t=>{let e=new Set;do for(let r of Reflect.ownKeys(t))e.add([t,r]);while((t=Reflect.getPrototypeOf(t))&&t!==Object.prototype);return e};hwe.exports=(t,{include:e,exclude:r}={})=>{let s=a=>{let n=c=>typeof c=="string"?a===c:c.test(a);return e?e.some(n):r?!r.some(n):!0};for(let[a,n]of wpt(t.constructor.prototype)){if(n==="constructor"||!s(n))continue;let c=Reflect.getOwnPropertyDescriptor(a,n);c&&typeof c.value=="function"&&(t[n]=t[n].bind(t))}return t}});var Cwe=_(Vn=>{"use strict";var mw,_S,QF,H9;typeof performance=="object"&&typeof performance.now=="function"?(dwe=performance,Vn.unstable_now=function(){return dwe.now()}):(N9=Date,mwe=N9.now(),Vn.unstable_now=function(){return N9.now()-mwe});var dwe,N9,mwe;typeof window>"u"||typeof MessageChannel!="function"?(dw=null,O9=null,L9=function(){if(dw!==null)try{var t=Vn.unstable_now();dw(!0,t),dw=null}catch(e){throw setTimeout(L9,0),e}},mw=function(t){dw!==null?setTimeout(mw,0,t):(dw=t,setTimeout(L9,0))},_S=function(t,e){O9=setTimeout(t,e)},QF=function(){clearTimeout(O9)},Vn.unstable_shouldYield=function(){return!1},H9=Vn.unstable_forceFrameRate=function(){}):(ywe=window.setTimeout,Ewe=window.clearTimeout,typeof console<"u"&&(Iwe=window.cancelAnimationFrame,typeof window.requestAnimationFrame!="function"&&console.error("This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://reactjs.org/link/react-polyfills"),typeof Iwe!="function"&&console.error("This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://reactjs.org/link/react-polyfills")),MS=!1,US=null,PF=-1,M9=5,U9=0,Vn.unstable_shouldYield=function(){return Vn.unstable_now()>=U9},H9=function(){},Vn.unstable_forceFrameRate=function(t){0>t||125>>1,a=t[s];if(a!==void 0&&0kF(c,r))p!==void 0&&0>kF(p,c)?(t[s]=p,t[f]=r,s=f):(t[s]=c,t[n]=r,s=n);else if(p!==void 0&&0>kF(p,r))t[s]=p,t[f]=r,s=f;else break e}}return e}return null}function kF(t,e){var r=t.sortIndex-e.sortIndex;return r!==0?r:t.id-e.id}var fA=[],Z0=[],Bpt=1,qc=null,$o=3,RF=!1,Rm=!1,HS=!1;function G9(t){for(var e=ef(Z0);e!==null;){if(e.callback===null)TF(Z0);else if(e.startTime<=t)TF(Z0),e.sortIndex=e.expirationTime,j9(fA,e);else break;e=ef(Z0)}}function q9(t){if(HS=!1,G9(t),!Rm)if(ef(fA)!==null)Rm=!0,mw(W9);else{var e=ef(Z0);e!==null&&_S(q9,e.startTime-t)}}function W9(t,e){Rm=!1,HS&&(HS=!1,QF()),RF=!0;var r=$o;try{for(G9(e),qc=ef(fA);qc!==null&&(!(qc.expirationTime>e)||t&&!Vn.unstable_shouldYield());){var s=qc.callback;if(typeof s=="function"){qc.callback=null,$o=qc.priorityLevel;var a=s(qc.expirationTime<=e);e=Vn.unstable_now(),typeof a=="function"?qc.callback=a:qc===ef(fA)&&TF(fA),G9(e)}else TF(fA);qc=ef(fA)}if(qc!==null)var n=!0;else{var c=ef(Z0);c!==null&&_S(q9,c.startTime-e),n=!1}return n}finally{qc=null,$o=r,RF=!1}}var vpt=H9;Vn.unstable_IdlePriority=5;Vn.unstable_ImmediatePriority=1;Vn.unstable_LowPriority=4;Vn.unstable_NormalPriority=3;Vn.unstable_Profiling=null;Vn.unstable_UserBlockingPriority=2;Vn.unstable_cancelCallback=function(t){t.callback=null};Vn.unstable_continueExecution=function(){Rm||RF||(Rm=!0,mw(W9))};Vn.unstable_getCurrentPriorityLevel=function(){return $o};Vn.unstable_getFirstCallbackNode=function(){return ef(fA)};Vn.unstable_next=function(t){switch($o){case 1:case 2:case 3:var e=3;break;default:e=$o}var r=$o;$o=e;try{return t()}finally{$o=r}};Vn.unstable_pauseExecution=function(){};Vn.unstable_requestPaint=vpt;Vn.unstable_runWithPriority=function(t,e){switch(t){case 1:case 2:case 3:case 4:case 5:break;default:t=3}var r=$o;$o=t;try{return e()}finally{$o=r}};Vn.unstable_scheduleCallback=function(t,e,r){var s=Vn.unstable_now();switch(typeof r=="object"&&r!==null?(r=r.delay,r=typeof r=="number"&&0s?(t.sortIndex=r,j9(Z0,t),ef(fA)===null&&t===ef(Z0)&&(HS?QF():HS=!0,_S(q9,r-s))):(t.sortIndex=a,j9(fA,t),Rm||RF||(Rm=!0,mw(W9))),t};Vn.unstable_wrapCallback=function(t){var e=$o;return function(){var r=$o;$o=e;try{return t.apply(this,arguments)}finally{$o=r}}}});var Y9=_((wKt,wwe)=>{"use strict";wwe.exports=Cwe()});var Bwe=_((BKt,jS)=>{jS.exports=function(e){var r={},s=y9(),a=hn(),n=Y9();function c(v){for(var D="https://reactjs.org/docs/error-decoder.html?invariant="+v,Q=1;Q_e||V[Se]!==ne[_e])return` +`+V[Se].replace(" at new "," at ");while(1<=Se&&0<=_e);break}}}finally{ve=!1,Error.prepareStackTrace=Q}return(v=v?v.displayName||v.name:"")?oc(v):""}var ac=[],Oi=-1;function no(v){return{current:v}}function Rt(v){0>Oi||(v.current=ac[Oi],ac[Oi]=null,Oi--)}function xn(v,D){Oi++,ac[Oi]=v.current,v.current=D}var la={},Gi=no(la),Li=no(!1),Na=la;function dn(v,D){var Q=v.type.contextTypes;if(!Q)return la;var H=v.stateNode;if(H&&H.__reactInternalMemoizedUnmaskedChildContext===D)return H.__reactInternalMemoizedMaskedChildContext;var V={},ne;for(ne in Q)V[ne]=D[ne];return H&&(v=v.stateNode,v.__reactInternalMemoizedUnmaskedChildContext=D,v.__reactInternalMemoizedMaskedChildContext=V),V}function Kn(v){return v=v.childContextTypes,v!=null}function Au(){Rt(Li),Rt(Gi)}function yh(v,D,Q){if(Gi.current!==la)throw Error(c(168));xn(Gi,D),xn(Li,Q)}function Oa(v,D,Q){var H=v.stateNode;if(v=D.childContextTypes,typeof H.getChildContext!="function")return Q;H=H.getChildContext();for(var V in H)if(!(V in v))throw Error(c(108,g(D)||"Unknown",V));return s({},Q,H)}function La(v){return v=(v=v.stateNode)&&v.__reactInternalMemoizedMergedChildContext||la,Na=Gi.current,xn(Gi,v),xn(Li,Li.current),!0}function Ma(v,D,Q){var H=v.stateNode;if(!H)throw Error(c(169));Q?(v=Oa(v,D,Na),H.__reactInternalMemoizedMergedChildContext=v,Rt(Li),Rt(Gi),xn(Gi,v)):Rt(Li),xn(Li,Q)}var $e=null,Ua=null,hf=n.unstable_now;hf();var lc=0,wn=8;function ca(v){if(1&v)return wn=15,1;if(2&v)return wn=14,2;if(4&v)return wn=13,4;var D=24&v;return D!==0?(wn=12,D):v&32?(wn=11,32):(D=192&v,D!==0?(wn=10,D):v&256?(wn=9,256):(D=3584&v,D!==0?(wn=8,D):v&4096?(wn=7,4096):(D=4186112&v,D!==0?(wn=6,D):(D=62914560&v,D!==0?(wn=5,D):v&67108864?(wn=4,67108864):v&134217728?(wn=3,134217728):(D=805306368&v,D!==0?(wn=2,D):1073741824&v?(wn=1,1073741824):(wn=8,v))))))}function LA(v){switch(v){case 99:return 15;case 98:return 10;case 97:case 96:return 8;case 95:return 2;default:return 0}}function MA(v){switch(v){case 15:case 14:return 99;case 13:case 12:case 11:case 10:return 98;case 9:case 8:case 7:case 6:case 4:case 5:return 97;case 3:case 2:case 1:return 95;case 0:return 90;default:throw Error(c(358,v))}}function ua(v,D){var Q=v.pendingLanes;if(Q===0)return wn=0;var H=0,V=0,ne=v.expiredLanes,Se=v.suspendedLanes,_e=v.pingedLanes;if(ne!==0)H=ne,V=wn=15;else if(ne=Q&134217727,ne!==0){var pt=ne&~Se;pt!==0?(H=ca(pt),V=wn):(_e&=ne,_e!==0&&(H=ca(_e),V=wn))}else ne=Q&~Se,ne!==0?(H=ca(ne),V=wn):_e!==0&&(H=ca(_e),V=wn);if(H===0)return 0;if(H=31-ns(H),H=Q&((0>H?0:1<Q;Q++)D.push(v);return D}function Ha(v,D,Q){v.pendingLanes|=D;var H=D-1;v.suspendedLanes&=H,v.pingedLanes&=H,v=v.eventTimes,D=31-ns(D),v[D]=Q}var ns=Math.clz32?Math.clz32:uc,cc=Math.log,pu=Math.LN2;function uc(v){return v===0?32:31-(cc(v)/pu|0)|0}var ja=n.unstable_runWithPriority,Mi=n.unstable_scheduleCallback,Is=n.unstable_cancelCallback,vl=n.unstable_shouldYield,gf=n.unstable_requestPaint,fc=n.unstable_now,wi=n.unstable_getCurrentPriorityLevel,Qn=n.unstable_ImmediatePriority,Ac=n.unstable_UserBlockingPriority,Ke=n.unstable_NormalPriority,st=n.unstable_LowPriority,St=n.unstable_IdlePriority,lr={},te=gf!==void 0?gf:function(){},Ee=null,Oe=null,dt=!1,Et=fc(),bt=1e4>Et?fc:function(){return fc()-Et};function tr(){switch(wi()){case Qn:return 99;case Ac:return 98;case Ke:return 97;case st:return 96;case St:return 95;default:throw Error(c(332))}}function An(v){switch(v){case 99:return Qn;case 98:return Ac;case 97:return Ke;case 96:return st;case 95:return St;default:throw Error(c(332))}}function li(v,D){return v=An(v),ja(v,D)}function qi(v,D,Q){return v=An(v),Mi(v,D,Q)}function Tn(){if(Oe!==null){var v=Oe;Oe=null,Is(v)}Ga()}function Ga(){if(!dt&&Ee!==null){dt=!0;var v=0;try{var D=Ee;li(99,function(){for(;vRn?(_n=kr,kr=null):_n=kr.sibling;var zr=Zt(et,kr,gt[Rn],Xt);if(zr===null){kr===null&&(kr=_n);break}v&&kr&&zr.alternate===null&&D(et,kr),qe=ne(zr,qe,Rn),Zn===null?Dr=zr:Zn.sibling=zr,Zn=zr,kr=_n}if(Rn===gt.length)return Q(et,kr),Dr;if(kr===null){for(;RnRn?(_n=kr,kr=null):_n=kr.sibling;var ci=Zt(et,kr,zr.value,Xt);if(ci===null){kr===null&&(kr=_n);break}v&&kr&&ci.alternate===null&&D(et,kr),qe=ne(ci,qe,Rn),Zn===null?Dr=ci:Zn.sibling=ci,Zn=ci,kr=_n}if(zr.done)return Q(et,kr),Dr;if(kr===null){for(;!zr.done;Rn++,zr=gt.next())zr=Lr(et,zr.value,Xt),zr!==null&&(qe=ne(zr,qe,Rn),Zn===null?Dr=zr:Zn.sibling=zr,Zn=zr);return Dr}for(kr=H(et,kr);!zr.done;Rn++,zr=gt.next())zr=zn(kr,et,Rn,zr.value,Xt),zr!==null&&(v&&zr.alternate!==null&&kr.delete(zr.key===null?Rn:zr.key),qe=ne(zr,qe,Rn),Zn===null?Dr=zr:Zn.sibling=zr,Zn=zr);return v&&kr.forEach(function(Du){return D(et,Du)}),Dr}return function(et,qe,gt,Xt){var Dr=typeof gt=="object"&>!==null&>.type===E&>.key===null;Dr&&(gt=gt.props.children);var Zn=typeof gt=="object"&>!==null;if(Zn)switch(gt.$$typeof){case p:e:{for(Zn=gt.key,Dr=qe;Dr!==null;){if(Dr.key===Zn){switch(Dr.tag){case 7:if(gt.type===E){Q(et,Dr.sibling),qe=V(Dr,gt.props.children),qe.return=et,et=qe;break e}break;default:if(Dr.elementType===gt.type){Q(et,Dr.sibling),qe=V(Dr,gt.props),qe.ref=yt(et,Dr,gt),qe.return=et,et=qe;break e}}Q(et,Dr);break}else D(et,Dr);Dr=Dr.sibling}gt.type===E?(qe=kf(gt.props.children,et.mode,Xt,gt.key),qe.return=et,et=qe):(Xt=sd(gt.type,gt.key,gt.props,null,et.mode,Xt),Xt.ref=yt(et,qe,gt),Xt.return=et,et=Xt)}return Se(et);case h:e:{for(Dr=gt.key;qe!==null;){if(qe.key===Dr)if(qe.tag===4&&qe.stateNode.containerInfo===gt.containerInfo&&qe.stateNode.implementation===gt.implementation){Q(et,qe.sibling),qe=V(qe,gt.children||[]),qe.return=et,et=qe;break e}else{Q(et,qe);break}else D(et,qe);qe=qe.sibling}qe=Qo(gt,et.mode,Xt),qe.return=et,et=qe}return Se(et)}if(typeof gt=="string"||typeof gt=="number")return gt=""+gt,qe!==null&&qe.tag===6?(Q(et,qe.sibling),qe=V(qe,gt),qe.return=et,et=qe):(Q(et,qe),qe=b2(gt,et.mode,Xt),qe.return=et,et=qe),Se(et);if(mf(gt))return yi(et,qe,gt,Xt);if(Ce(gt))return za(et,qe,gt,Xt);if(Zn&&gu(et,gt),typeof gt>"u"&&!Dr)switch(et.tag){case 1:case 22:case 0:case 11:case 15:throw Error(c(152,g(et.type)||"Component"))}return Q(et,qe)}}var Mg=By(!0),e2=By(!1),vh={},ur=no(vh),zi=no(vh),yf=no(vh);function qa(v){if(v===vh)throw Error(c(174));return v}function Ug(v,D){xn(yf,D),xn(zi,v),xn(ur,vh),v=mt(D),Rt(ur),xn(ur,v)}function du(){Rt(ur),Rt(zi),Rt(yf)}function Ef(v){var D=qa(yf.current),Q=qa(ur.current);D=j(Q,v.type,D),Q!==D&&(xn(zi,v),xn(ur,D))}function wt(v){zi.current===v&&(Rt(ur),Rt(zi))}var di=no(0);function GA(v){for(var D=v;D!==null;){if(D.tag===13){var Q=D.memoizedState;if(Q!==null&&(Q=Q.dehydrated,Q===null||gr(Q)||Bo(Q)))return D}else if(D.tag===19&&D.memoizedProps.revealOrder!==void 0){if(D.flags&64)return D}else if(D.child!==null){D.child.return=D,D=D.child;continue}if(D===v)break;for(;D.sibling===null;){if(D.return===null||D.return===v)return null;D=D.return}D.sibling.return=D.return,D=D.sibling}return null}var Wa=null,Aa=null,Ya=!1;function _g(v,D){var Q=Ka(5,null,null,0);Q.elementType="DELETED",Q.type="DELETED",Q.stateNode=D,Q.return=v,Q.flags=8,v.lastEffect!==null?(v.lastEffect.nextEffect=Q,v.lastEffect=Q):v.firstEffect=v.lastEffect=Q}function Sh(v,D){switch(v.tag){case 5:return D=aa(D,v.type,v.pendingProps),D!==null?(v.stateNode=D,!0):!1;case 6:return D=FA(D,v.pendingProps),D!==null?(v.stateNode=D,!0):!1;case 13:return!1;default:return!1}}function Hg(v){if(Ya){var D=Aa;if(D){var Q=D;if(!Sh(v,D)){if(D=Me(Q),!D||!Sh(v,D)){v.flags=v.flags&-1025|2,Ya=!1,Wa=v;return}_g(Wa,Q)}Wa=v,Aa=cu(D)}else v.flags=v.flags&-1025|2,Ya=!1,Wa=v}}function vy(v){for(v=v.return;v!==null&&v.tag!==5&&v.tag!==3&&v.tag!==13;)v=v.return;Wa=v}function qA(v){if(!X||v!==Wa)return!1;if(!Ya)return vy(v),Ya=!0,!1;var D=v.type;if(v.tag!==5||D!=="head"&&D!=="body"&&!it(D,v.memoizedProps))for(D=Aa;D;)_g(v,D),D=Me(D);if(vy(v),v.tag===13){if(!X)throw Error(c(316));if(v=v.memoizedState,v=v!==null?v.dehydrated:null,!v)throw Error(c(317));Aa=NA(v)}else Aa=Wa?Me(v.stateNode):null;return!0}function jg(){X&&(Aa=Wa=null,Ya=!1)}var mu=[];function yu(){for(var v=0;vne))throw Error(c(301));ne+=1,Pi=is=null,D.updateQueue=null,If.current=re,v=Q(H,V)}while(Cf)}if(If.current=kt,D=is!==null&&is.next!==null,Eu=0,Pi=is=Gn=null,WA=!1,D)throw Error(c(300));return v}function ss(){var v={memoizedState:null,baseState:null,baseQueue:null,queue:null,next:null};return Pi===null?Gn.memoizedState=Pi=v:Pi=Pi.next=v,Pi}function Pl(){if(is===null){var v=Gn.alternate;v=v!==null?v.memoizedState:null}else v=is.next;var D=Pi===null?Gn.memoizedState:Pi.next;if(D!==null)Pi=D,is=v;else{if(v===null)throw Error(c(310));is=v,v={memoizedState:is.memoizedState,baseState:is.baseState,baseQueue:is.baseQueue,queue:is.queue,next:null},Pi===null?Gn.memoizedState=Pi=v:Pi=Pi.next=v}return Pi}function Po(v,D){return typeof D=="function"?D(v):D}function wf(v){var D=Pl(),Q=D.queue;if(Q===null)throw Error(c(311));Q.lastRenderedReducer=v;var H=is,V=H.baseQueue,ne=Q.pending;if(ne!==null){if(V!==null){var Se=V.next;V.next=ne.next,ne.next=Se}H.baseQueue=V=ne,Q.pending=null}if(V!==null){V=V.next,H=H.baseState;var _e=Se=ne=null,pt=V;do{var Wt=pt.lane;if((Eu&Wt)===Wt)_e!==null&&(_e=_e.next={lane:0,action:pt.action,eagerReducer:pt.eagerReducer,eagerState:pt.eagerState,next:null}),H=pt.eagerReducer===v?pt.eagerState:v(H,pt.action);else{var Sr={lane:Wt,action:pt.action,eagerReducer:pt.eagerReducer,eagerState:pt.eagerState,next:null};_e===null?(Se=_e=Sr,ne=H):_e=_e.next=Sr,Gn.lanes|=Wt,Zg|=Wt}pt=pt.next}while(pt!==null&&pt!==V);_e===null?ne=H:_e.next=Se,vo(H,D.memoizedState)||(Je=!0),D.memoizedState=H,D.baseState=ne,D.baseQueue=_e,Q.lastRenderedState=H}return[D.memoizedState,Q.dispatch]}function Bf(v){var D=Pl(),Q=D.queue;if(Q===null)throw Error(c(311));Q.lastRenderedReducer=v;var H=Q.dispatch,V=Q.pending,ne=D.memoizedState;if(V!==null){Q.pending=null;var Se=V=V.next;do ne=v(ne,Se.action),Se=Se.next;while(Se!==V);vo(ne,D.memoizedState)||(Je=!0),D.memoizedState=ne,D.baseQueue===null&&(D.baseState=ne),Q.lastRenderedState=ne}return[ne,H]}function xl(v,D,Q){var H=D._getVersion;H=H(D._source);var V=y?D._workInProgressVersionPrimary:D._workInProgressVersionSecondary;if(V!==null?v=V===H:(v=v.mutableReadLanes,(v=(Eu&v)===v)&&(y?D._workInProgressVersionPrimary=H:D._workInProgressVersionSecondary=H,mu.push(D))),v)return Q(D._source);throw mu.push(D),Error(c(350))}function yn(v,D,Q,H){var V=so;if(V===null)throw Error(c(349));var ne=D._getVersion,Se=ne(D._source),_e=If.current,pt=_e.useState(function(){return xl(V,D,Q)}),Wt=pt[1],Sr=pt[0];pt=Pi;var Lr=v.memoizedState,Zt=Lr.refs,zn=Zt.getSnapshot,yi=Lr.source;Lr=Lr.subscribe;var za=Gn;return v.memoizedState={refs:Zt,source:D,subscribe:H},_e.useEffect(function(){Zt.getSnapshot=Q,Zt.setSnapshot=Wt;var et=ne(D._source);if(!vo(Se,et)){et=Q(D._source),vo(Sr,et)||(Wt(et),et=Bs(za),V.mutableReadLanes|=et&V.pendingLanes),et=V.mutableReadLanes,V.entangledLanes|=et;for(var qe=V.entanglements,gt=et;0Q?98:Q,function(){v(!0)}),li(97m2&&(D.flags|=64,V=!0,XA(H,!1),D.lanes=33554432)}else{if(!V)if(v=GA(ne),v!==null){if(D.flags|=64,V=!0,v=v.updateQueue,v!==null&&(D.updateQueue=v,D.flags|=4),XA(H,!0),H.tail===null&&H.tailMode==="hidden"&&!ne.alternate&&!Ya)return D=D.lastEffect=H.lastEffect,D!==null&&(D.nextEffect=null),null}else 2*bt()-H.renderingStartTime>m2&&Q!==1073741824&&(D.flags|=64,V=!0,XA(H,!1),D.lanes=33554432);H.isBackwards?(ne.sibling=D.child,D.child=ne):(v=H.last,v!==null?v.sibling=ne:D.child=ne,H.last=ne)}return H.tail!==null?(v=H.tail,H.rendering=v,H.tail=v.sibling,H.lastEffect=D.lastEffect,H.renderingStartTime=bt(),v.sibling=null,D=di.current,xn(di,V?D&1|2:D&1),v):null;case 23:case 24:return B2(),v!==null&&v.memoizedState!==null!=(D.memoizedState!==null)&&H.mode!=="unstable-defer-without-hiding"&&(D.flags|=4),null}throw Error(c(156,D.tag))}function qL(v){switch(v.tag){case 1:Kn(v.type)&&Au();var D=v.flags;return D&4096?(v.flags=D&-4097|64,v):null;case 3:if(du(),Rt(Li),Rt(Gi),yu(),D=v.flags,D&64)throw Error(c(285));return v.flags=D&-4097|64,v;case 5:return wt(v),null;case 13:return Rt(di),D=v.flags,D&4096?(v.flags=D&-4097|64,v):null;case 19:return Rt(di),null;case 4:return du(),null;case 10:return Og(v),null;case 23:case 24:return B2(),null;default:return null}}function Yg(v,D){try{var Q="",H=D;do Q+=$1(H),H=H.return;while(H);var V=Q}catch(ne){V=` +Error generating stack: `+ne.message+` +`+ne.stack}return{value:v,source:D,stack:V}}function Vg(v,D){try{console.error(D.value)}catch(Q){setTimeout(function(){throw Q})}}var WL=typeof WeakMap=="function"?WeakMap:Map;function i2(v,D,Q){Q=Dl(-1,Q),Q.tag=3,Q.payload={element:null};var H=D.value;return Q.callback=function(){_y||(_y=!0,y2=H),Vg(v,D)},Q}function Jg(v,D,Q){Q=Dl(-1,Q),Q.tag=3;var H=v.type.getDerivedStateFromError;if(typeof H=="function"){var V=D.value;Q.payload=function(){return Vg(v,D),H(V)}}var ne=v.stateNode;return ne!==null&&typeof ne.componentDidCatch=="function"&&(Q.callback=function(){typeof H!="function"&&(hc===null?hc=new Set([this]):hc.add(this),Vg(v,D));var Se=D.stack;this.componentDidCatch(D.value,{componentStack:Se!==null?Se:""})}),Q}var YL=typeof WeakSet=="function"?WeakSet:Set;function s2(v){var D=v.ref;if(D!==null)if(typeof D=="function")try{D(null)}catch(Q){xf(v,Q)}else D.current=null}function xy(v,D){switch(D.tag){case 0:case 11:case 15:case 22:return;case 1:if(D.flags&256&&v!==null){var Q=v.memoizedProps,H=v.memoizedState;v=D.stateNode,D=v.getSnapshotBeforeUpdate(D.elementType===D.type?Q:So(D.type,Q),H),v.__reactInternalSnapshotBeforeUpdate=D}return;case 3:F&&D.flags&256&&Ts(D.stateNode.containerInfo);return;case 5:case 6:case 4:case 17:return}throw Error(c(163))}function Th(v,D){if(D=D.updateQueue,D=D!==null?D.lastEffect:null,D!==null){var Q=D=D.next;do{if((Q.tag&v)===v){var H=Q.destroy;Q.destroy=void 0,H!==void 0&&H()}Q=Q.next}while(Q!==D)}}function uP(v,D,Q){switch(Q.tag){case 0:case 11:case 15:case 22:if(D=Q.updateQueue,D=D!==null?D.lastEffect:null,D!==null){v=D=D.next;do{if((v.tag&3)===3){var H=v.create;v.destroy=H()}v=v.next}while(v!==D)}if(D=Q.updateQueue,D=D!==null?D.lastEffect:null,D!==null){v=D=D.next;do{var V=v;H=V.next,V=V.tag,V&4&&V&1&&(vP(Q,v),tM(Q,v)),v=H}while(v!==D)}return;case 1:v=Q.stateNode,Q.flags&4&&(D===null?v.componentDidMount():(H=Q.elementType===Q.type?D.memoizedProps:So(Q.type,D.memoizedProps),v.componentDidUpdate(H,D.memoizedState,v.__reactInternalSnapshotBeforeUpdate))),D=Q.updateQueue,D!==null&&Cy(Q,D,v);return;case 3:if(D=Q.updateQueue,D!==null){if(v=null,Q.child!==null)switch(Q.child.tag){case 5:v=Re(Q.child.stateNode);break;case 1:v=Q.child.stateNode}Cy(Q,D,v)}return;case 5:v=Q.stateNode,D===null&&Q.flags&4&&$s(v,Q.type,Q.memoizedProps,Q);return;case 6:return;case 4:return;case 12:return;case 13:X&&Q.memoizedState===null&&(Q=Q.alternate,Q!==null&&(Q=Q.memoizedState,Q!==null&&(Q=Q.dehydrated,Q!==null&&uu(Q))));return;case 19:case 17:case 20:case 21:case 23:case 24:return}throw Error(c(163))}function fP(v,D){if(F)for(var Q=v;;){if(Q.tag===5){var H=Q.stateNode;D?dh(H):to(Q.stateNode,Q.memoizedProps)}else if(Q.tag===6)H=Q.stateNode,D?mh(H):jn(H,Q.memoizedProps);else if((Q.tag!==23&&Q.tag!==24||Q.memoizedState===null||Q===v)&&Q.child!==null){Q.child.return=Q,Q=Q.child;continue}if(Q===v)break;for(;Q.sibling===null;){if(Q.return===null||Q.return===v)return;Q=Q.return}Q.sibling.return=Q.return,Q=Q.sibling}}function ky(v,D){if(Ua&&typeof Ua.onCommitFiberUnmount=="function")try{Ua.onCommitFiberUnmount($e,D)}catch{}switch(D.tag){case 0:case 11:case 14:case 15:case 22:if(v=D.updateQueue,v!==null&&(v=v.lastEffect,v!==null)){var Q=v=v.next;do{var H=Q,V=H.destroy;if(H=H.tag,V!==void 0)if(H&4)vP(D,Q);else{H=D;try{V()}catch(ne){xf(H,ne)}}Q=Q.next}while(Q!==v)}break;case 1:if(s2(D),v=D.stateNode,typeof v.componentWillUnmount=="function")try{v.props=D.memoizedProps,v.state=D.memoizedState,v.componentWillUnmount()}catch(ne){xf(D,ne)}break;case 5:s2(D);break;case 4:F?gP(v,D):z&&z&&(D=D.stateNode.containerInfo,v=ou(D),TA(D,v))}}function AP(v,D){for(var Q=D;;)if(ky(v,Q),Q.child===null||F&&Q.tag===4){if(Q===D)break;for(;Q.sibling===null;){if(Q.return===null||Q.return===D)return;Q=Q.return}Q.sibling.return=Q.return,Q=Q.sibling}else Q.child.return=Q,Q=Q.child}function Qy(v){v.alternate=null,v.child=null,v.dependencies=null,v.firstEffect=null,v.lastEffect=null,v.memoizedProps=null,v.memoizedState=null,v.pendingProps=null,v.return=null,v.updateQueue=null}function pP(v){return v.tag===5||v.tag===3||v.tag===4}function hP(v){if(F){e:{for(var D=v.return;D!==null;){if(pP(D))break e;D=D.return}throw Error(c(160))}var Q=D;switch(D=Q.stateNode,Q.tag){case 5:var H=!1;break;case 3:D=D.containerInfo,H=!0;break;case 4:D=D.containerInfo,H=!0;break;default:throw Error(c(161))}Q.flags&16&&(Af(D),Q.flags&=-17);e:t:for(Q=v;;){for(;Q.sibling===null;){if(Q.return===null||pP(Q.return)){Q=null;break e}Q=Q.return}for(Q.sibling.return=Q.return,Q=Q.sibling;Q.tag!==5&&Q.tag!==6&&Q.tag!==18;){if(Q.flags&2||Q.child===null||Q.tag===4)continue t;Q.child.return=Q,Q=Q.child}if(!(Q.flags&2)){Q=Q.stateNode;break e}}H?o2(v,Q,D):a2(v,Q,D)}}function o2(v,D,Q){var H=v.tag,V=H===5||H===6;if(V)v=V?v.stateNode:v.stateNode.instance,D?eo(Q,v,D):Io(Q,v);else if(H!==4&&(v=v.child,v!==null))for(o2(v,D,Q),v=v.sibling;v!==null;)o2(v,D,Q),v=v.sibling}function a2(v,D,Q){var H=v.tag,V=H===5||H===6;if(V)v=V?v.stateNode:v.stateNode.instance,D?ji(Q,v,D):ai(Q,v);else if(H!==4&&(v=v.child,v!==null))for(a2(v,D,Q),v=v.sibling;v!==null;)a2(v,D,Q),v=v.sibling}function gP(v,D){for(var Q=D,H=!1,V,ne;;){if(!H){H=Q.return;e:for(;;){if(H===null)throw Error(c(160));switch(V=H.stateNode,H.tag){case 5:ne=!1;break e;case 3:V=V.containerInfo,ne=!0;break e;case 4:V=V.containerInfo,ne=!0;break e}H=H.return}H=!0}if(Q.tag===5||Q.tag===6)AP(v,Q),ne?QA(V,Q.stateNode):wo(V,Q.stateNode);else if(Q.tag===4){if(Q.child!==null){V=Q.stateNode.containerInfo,ne=!0,Q.child.return=Q,Q=Q.child;continue}}else if(ky(v,Q),Q.child!==null){Q.child.return=Q,Q=Q.child;continue}if(Q===D)break;for(;Q.sibling===null;){if(Q.return===null||Q.return===D)return;Q=Q.return,Q.tag===4&&(H=!1)}Q.sibling.return=Q.return,Q=Q.sibling}}function l2(v,D){if(F){switch(D.tag){case 0:case 11:case 14:case 15:case 22:Th(3,D);return;case 1:return;case 5:var Q=D.stateNode;if(Q!=null){var H=D.memoizedProps;v=v!==null?v.memoizedProps:H;var V=D.type,ne=D.updateQueue;D.updateQueue=null,ne!==null&&Co(Q,ne,V,v,H,D)}return;case 6:if(D.stateNode===null)throw Error(c(162));Q=D.memoizedProps,rs(D.stateNode,v!==null?v.memoizedProps:Q,Q);return;case 3:X&&(D=D.stateNode,D.hydrate&&(D.hydrate=!1,OA(D.containerInfo)));return;case 12:return;case 13:dP(D),Kg(D);return;case 19:Kg(D);return;case 17:return;case 23:case 24:fP(D,D.memoizedState!==null);return}throw Error(c(163))}switch(D.tag){case 0:case 11:case 14:case 15:case 22:Th(3,D);return;case 12:return;case 13:dP(D),Kg(D);return;case 19:Kg(D);return;case 3:X&&(Q=D.stateNode,Q.hydrate&&(Q.hydrate=!1,OA(Q.containerInfo)));break;case 23:case 24:return}e:if(z){switch(D.tag){case 1:case 5:case 6:case 20:break e;case 3:case 4:D=D.stateNode,TA(D.containerInfo,D.pendingChildren);break e}throw Error(c(163))}}function dP(v){v.memoizedState!==null&&(d2=bt(),F&&fP(v.child,!0))}function Kg(v){var D=v.updateQueue;if(D!==null){v.updateQueue=null;var Q=v.stateNode;Q===null&&(Q=v.stateNode=new YL),D.forEach(function(H){var V=nM.bind(null,v,H);Q.has(H)||(Q.add(H),H.then(V,V))})}}function VL(v,D){return v!==null&&(v=v.memoizedState,v===null||v.dehydrated!==null)?(D=D.memoizedState,D!==null&&D.dehydrated===null):!1}var Ty=0,Ry=1,Fy=2,zg=3,Ny=4;if(typeof Symbol=="function"&&Symbol.for){var Xg=Symbol.for;Ty=Xg("selector.component"),Ry=Xg("selector.has_pseudo_class"),Fy=Xg("selector.role"),zg=Xg("selector.test_id"),Ny=Xg("selector.text")}function Oy(v){var D=$(v);if(D!=null){if(typeof D.memoizedProps["data-testname"]!="string")throw Error(c(364));return D}if(v=ir(v),v===null)throw Error(c(362));return v.stateNode.current}function Sf(v,D){switch(D.$$typeof){case Ty:if(v.type===D.value)return!0;break;case Ry:e:{D=D.value,v=[v,0];for(var Q=0;Q";case Ry:return":has("+(Df(v)||"")+")";case Fy:return'[role="'+v.value+'"]';case Ny:return'"'+v.value+'"';case zg:return'[data-testname="'+v.value+'"]';default:throw Error(c(365,v))}}function c2(v,D){var Q=[];v=[v,0];for(var H=0;HV&&(V=Se),Q&=~ne}if(Q=V,Q=bt()-Q,Q=(120>Q?120:480>Q?480:1080>Q?1080:1920>Q?1920:3e3>Q?3e3:4320>Q?4320:1960*KL(Q/1960))-Q,10 component higher in the tree to provide a loading indicator or placeholder to display.`)}ws!==5&&(ws=2),pt=Yg(pt,_e),Zt=Se;do{switch(Zt.tag){case 3:ne=pt,Zt.flags|=4096,D&=-D,Zt.lanes|=D;var Zn=i2(Zt,ne,D);Iy(Zt,Zn);break e;case 1:ne=pt;var kr=Zt.type,Rn=Zt.stateNode;if(!(Zt.flags&64)&&(typeof kr.getDerivedStateFromError=="function"||Rn!==null&&typeof Rn.componentDidCatch=="function"&&(hc===null||!hc.has(Rn)))){Zt.flags|=4096,D&=-D,Zt.lanes|=D;var _n=Jg(Zt,ne,D);Iy(Zt,_n);break e}}Zt=Zt.return}while(Zt!==null)}BP(Q)}catch(zr){D=zr,Xi===Q&&Q!==null&&(Xi=Q=Q.return);continue}break}while(!0)}function CP(){var v=My.current;return My.current=kt,v===null?kt:v}function id(v,D){var Q=xr;xr|=16;var H=CP();so===v&&Ns===D||Oh(v,D);do try{XL();break}catch(V){IP(v,V)}while(!0);if(Fg(),xr=Q,My.current=H,Xi!==null)throw Error(c(261));return so=null,Ns=0,ws}function XL(){for(;Xi!==null;)wP(Xi)}function ZL(){for(;Xi!==null&&!vl();)wP(Xi)}function wP(v){var D=bP(v.alternate,v,ZA);v.memoizedProps=v.pendingProps,D===null?BP(v):Xi=D,f2.current=null}function BP(v){var D=v;do{var Q=D.alternate;if(v=D.return,D.flags&2048){if(Q=qL(D),Q!==null){Q.flags&=2047,Xi=Q;return}v!==null&&(v.firstEffect=v.lastEffect=null,v.flags|=2048)}else{if(Q=jL(Q,D,ZA),Q!==null){Xi=Q;return}if(Q=D,Q.tag!==24&&Q.tag!==23||Q.memoizedState===null||ZA&1073741824||!(Q.mode&4)){for(var H=0,V=Q.child;V!==null;)H|=V.lanes|V.childLanes,V=V.sibling;Q.childLanes=H}v!==null&&!(v.flags&2048)&&(v.firstEffect===null&&(v.firstEffect=D.firstEffect),D.lastEffect!==null&&(v.lastEffect!==null&&(v.lastEffect.nextEffect=D.firstEffect),v.lastEffect=D.lastEffect),1bt()-d2?Oh(v,0):h2|=Q),ga(v,D)}function nM(v,D){var Q=v.stateNode;Q!==null&&Q.delete(D),D=0,D===0&&(D=v.mode,D&2?D&4?(Bu===0&&(Bu=Rh),D=kn(62914560&~Bu),D===0&&(D=4194304)):D=tr()===99?1:2:D=1),Q=ko(),v=Gy(v,D),v!==null&&(Ha(v,D,Q),ga(v,Q))}var bP;bP=function(v,D,Q){var H=D.lanes;if(v!==null)if(v.memoizedProps!==D.pendingProps||Li.current)Je=!0;else if(Q&H)Je=!!(v.flags&16384);else{switch(Je=!1,D.tag){case 3:by(D),jg();break;case 5:Ef(D);break;case 1:Kn(D.type)&&La(D);break;case 4:Ug(D,D.stateNode.containerInfo);break;case 10:Ng(D,D.memoizedProps.value);break;case 13:if(D.memoizedState!==null)return Q&D.child.childLanes?r2(v,D,Q):(xn(di,di.current&1),D=qn(v,D,Q),D!==null?D.sibling:null);xn(di,di.current&1);break;case 19:if(H=(Q&D.childLanes)!==0,v.flags&64){if(H)return cP(v,D,Q);D.flags|=64}var V=D.memoizedState;if(V!==null&&(V.rendering=null,V.tail=null,V.lastEffect=null),xn(di,di.current),H)break;return null;case 23:case 24:return D.lanes=0,mi(v,D,Q)}return qn(v,D,Q)}else Je=!1;switch(D.lanes=0,D.tag){case 2:if(H=D.type,v!==null&&(v.alternate=null,D.alternate=null,D.flags|=2),v=D.pendingProps,V=dn(D,Gi.current),df(D,Q),V=qg(null,D,H,v,V,Q),D.flags|=1,typeof V=="object"&&V!==null&&typeof V.render=="function"&&V.$$typeof===void 0){if(D.tag=1,D.memoizedState=null,D.updateQueue=null,Kn(H)){var ne=!0;La(D)}else ne=!1;D.memoizedState=V.state!==null&&V.state!==void 0?V.state:null,Bh(D);var Se=H.getDerivedStateFromProps;typeof Se=="function"&&_A(D,H,Se,v),V.updater=HA,D.stateNode=V,V._reactInternals=D,bo(D,H,v,Q),D=t2(null,D,H,!0,ne,Q)}else D.tag=0,At(null,D,V,Q),D=D.child;return D;case 16:V=D.elementType;e:{switch(v!==null&&(v.alternate=null,D.alternate=null,D.flags|=2),v=D.pendingProps,ne=V._init,V=ne(V._payload),D.type=V,ne=D.tag=sM(V),v=So(V,v),ne){case 0:D=JA(null,D,V,v,Q);break e;case 1:D=lP(null,D,V,v,Q);break e;case 11:D=dr(null,D,V,v,Q);break e;case 14:D=vr(null,D,V,So(V.type,v),H,Q);break e}throw Error(c(306,V,""))}return D;case 0:return H=D.type,V=D.pendingProps,V=D.elementType===H?V:So(H,V),JA(v,D,H,V,Q);case 1:return H=D.type,V=D.pendingProps,V=D.elementType===H?V:So(H,V),lP(v,D,H,V,Q);case 3:if(by(D),H=D.updateQueue,v===null||H===null)throw Error(c(282));if(H=D.pendingProps,V=D.memoizedState,V=V!==null?V.element:null,Lg(v,D),UA(D,H,null,Q),H=D.memoizedState.element,H===V)jg(),D=qn(v,D,Q);else{if(V=D.stateNode,(ne=V.hydrate)&&(X?(Aa=cu(D.stateNode.containerInfo),Wa=D,ne=Ya=!0):ne=!1),ne){if(X&&(v=V.mutableSourceEagerHydrationData,v!=null))for(V=0;V=Wt&&ne>=Lr&&V<=Sr&&Se<=Zt){v.splice(D,1);break}else if(H!==Wt||Q.width!==pt.width||ZtSe){if(!(ne!==Lr||Q.height!==pt.height||SrV)){Wt>H&&(pt.width+=Wt-H,pt.x=H),Srne&&(pt.height+=Lr-ne,pt.y=ne),ZtQ&&(Q=Se)),Se ")+` + +No matching component was found for: + `)+v.join(" > ")}return null},r.getPublicRootInstance=function(v){if(v=v.current,!v.child)return null;switch(v.child.tag){case 5:return Re(v.child.stateNode);default:return v.child.stateNode}},r.injectIntoDevTools=function(v){if(v={bundleType:v.bundleType,version:v.version,rendererPackageName:v.rendererPackageName,rendererConfig:v.rendererConfig,overrideHookState:null,overrideHookStateDeletePath:null,overrideHookStateRenamePath:null,overrideProps:null,overridePropsDeletePath:null,overridePropsRenamePath:null,setSuspenseHandler:null,scheduleUpdate:null,currentDispatcherRef:f.ReactCurrentDispatcher,findHostInstanceByFiber:aM,findFiberByHostInstance:v.findFiberByHostInstance||lM,findHostInstancesForRefresh:null,scheduleRefresh:null,scheduleRoot:null,setRefreshHandler:null,getCurrentFiber:null},typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>"u")v=!1;else{var D=__REACT_DEVTOOLS_GLOBAL_HOOK__;if(!D.isDisabled&&D.supportsFiber)try{$e=D.inject(v),Ua=D}catch{}v=!0}return v},r.observeVisibleRects=function(v,D,Q,H){if(!qt)throw Error(c(363));v=u2(v,D);var V=on(v,Q,H).disconnect;return{disconnect:function(){V()}}},r.registerMutableSourceForHydration=function(v,D){var Q=D._getVersion;Q=Q(D._source),v.mutableSourceEagerHydrationData==null?v.mutableSourceEagerHydrationData=[D,Q]:v.mutableSourceEagerHydrationData.push(D,Q)},r.runWithPriority=function(v,D){var Q=lc;try{return lc=v,D()}finally{lc=Q}},r.shouldSuspend=function(){return!1},r.unbatchedUpdates=function(v,D){var Q=xr;xr&=-2,xr|=8;try{return v(D)}finally{xr=Q,xr===0&&(bf(),Tn())}},r.updateContainer=function(v,D,Q,H){var V=D.current,ne=ko(),Se=Bs(V);e:if(Q){Q=Q._reactInternals;t:{if(we(Q)!==Q||Q.tag!==1)throw Error(c(170));var _e=Q;do{switch(_e.tag){case 3:_e=_e.stateNode.context;break t;case 1:if(Kn(_e.type)){_e=_e.stateNode.__reactInternalMemoizedMergedChildContext;break t}}_e=_e.return}while(_e!==null);throw Error(c(171))}if(Q.tag===1){var pt=Q.type;if(Kn(pt)){Q=Oa(Q,pt,_e);break e}}Q=_e}else Q=la;return D.context===null?D.context=Q:D.pendingContext=Q,D=Dl(ne,Se),D.payload={element:v},H=H===void 0?null:H,H!==null&&(D.callback=H),bl(V,D),Tl(V,Se,ne),Se},r}});var Swe=_((vKt,vwe)=>{"use strict";vwe.exports=Bwe()});var bwe=_((SKt,Dwe)=>{"use strict";var Spt={ALIGN_COUNT:8,ALIGN_AUTO:0,ALIGN_FLEX_START:1,ALIGN_CENTER:2,ALIGN_FLEX_END:3,ALIGN_STRETCH:4,ALIGN_BASELINE:5,ALIGN_SPACE_BETWEEN:6,ALIGN_SPACE_AROUND:7,DIMENSION_COUNT:2,DIMENSION_WIDTH:0,DIMENSION_HEIGHT:1,DIRECTION_COUNT:3,DIRECTION_INHERIT:0,DIRECTION_LTR:1,DIRECTION_RTL:2,DISPLAY_COUNT:2,DISPLAY_FLEX:0,DISPLAY_NONE:1,EDGE_COUNT:9,EDGE_LEFT:0,EDGE_TOP:1,EDGE_RIGHT:2,EDGE_BOTTOM:3,EDGE_START:4,EDGE_END:5,EDGE_HORIZONTAL:6,EDGE_VERTICAL:7,EDGE_ALL:8,EXPERIMENTAL_FEATURE_COUNT:1,EXPERIMENTAL_FEATURE_WEB_FLEX_BASIS:0,FLEX_DIRECTION_COUNT:4,FLEX_DIRECTION_COLUMN:0,FLEX_DIRECTION_COLUMN_REVERSE:1,FLEX_DIRECTION_ROW:2,FLEX_DIRECTION_ROW_REVERSE:3,JUSTIFY_COUNT:6,JUSTIFY_FLEX_START:0,JUSTIFY_CENTER:1,JUSTIFY_FLEX_END:2,JUSTIFY_SPACE_BETWEEN:3,JUSTIFY_SPACE_AROUND:4,JUSTIFY_SPACE_EVENLY:5,LOG_LEVEL_COUNT:6,LOG_LEVEL_ERROR:0,LOG_LEVEL_WARN:1,LOG_LEVEL_INFO:2,LOG_LEVEL_DEBUG:3,LOG_LEVEL_VERBOSE:4,LOG_LEVEL_FATAL:5,MEASURE_MODE_COUNT:3,MEASURE_MODE_UNDEFINED:0,MEASURE_MODE_EXACTLY:1,MEASURE_MODE_AT_MOST:2,NODE_TYPE_COUNT:2,NODE_TYPE_DEFAULT:0,NODE_TYPE_TEXT:1,OVERFLOW_COUNT:3,OVERFLOW_VISIBLE:0,OVERFLOW_HIDDEN:1,OVERFLOW_SCROLL:2,POSITION_TYPE_COUNT:2,POSITION_TYPE_RELATIVE:0,POSITION_TYPE_ABSOLUTE:1,PRINT_OPTIONS_COUNT:3,PRINT_OPTIONS_LAYOUT:1,PRINT_OPTIONS_STYLE:2,PRINT_OPTIONS_CHILDREN:4,UNIT_COUNT:4,UNIT_UNDEFINED:0,UNIT_POINT:1,UNIT_PERCENT:2,UNIT_AUTO:3,WRAP_COUNT:3,WRAP_NO_WRAP:0,WRAP_WRAP:1,WRAP_WRAP_REVERSE:2};Dwe.exports=Spt});var Qwe=_((DKt,kwe)=>{"use strict";var Dpt=Object.assign||function(t){for(var e=1;e"}}]),t}(),Pwe=function(){FF(t,null,[{key:"fromJS",value:function(r){var s=r.width,a=r.height;return new t(s,a)}}]);function t(e,r){J9(this,t),this.width=e,this.height=r}return FF(t,[{key:"fromJS",value:function(r){r(this.width,this.height)}},{key:"toString",value:function(){return""}}]),t}(),xwe=function(){function t(e,r){J9(this,t),this.unit=e,this.value=r}return FF(t,[{key:"fromJS",value:function(r){r(this.unit,this.value)}},{key:"toString",value:function(){switch(this.unit){case tf.UNIT_POINT:return String(this.value);case tf.UNIT_PERCENT:return this.value+"%";case tf.UNIT_AUTO:return"auto";default:return this.value+"?"}}},{key:"valueOf",value:function(){return this.value}}]),t}();kwe.exports=function(t,e){function r(c,f,p){var h=c[f];c[f]=function(){for(var E=arguments.length,C=Array(E),S=0;S1?C-1:0),P=1;P1&&arguments[1]!==void 0?arguments[1]:NaN,p=arguments.length>2&&arguments[2]!==void 0?arguments[2]:NaN,h=arguments.length>3&&arguments[3]!==void 0?arguments[3]:tf.DIRECTION_LTR;return c.call(this,f,p,h)}),Dpt({Config:e.Config,Node:e.Node,Layout:t("Layout",bpt),Size:t("Size",Pwe),Value:t("Value",xwe),getInstanceCount:function(){return e.getInstanceCount.apply(e,arguments)}},tf)}});var Twe=_((exports,module)=>{(function(t,e){typeof define=="function"&&define.amd?define([],function(){return e}):typeof module=="object"&&module.exports?module.exports=e:(t.nbind=t.nbind||{}).init=e})(exports,function(Module,cb){typeof Module=="function"&&(cb=Module,Module={}),Module.onRuntimeInitialized=function(t,e){return function(){t&&t.apply(this,arguments);try{Module.ccall("nbind_init")}catch(r){e(r);return}e(null,{bind:Module._nbind_value,reflect:Module.NBind.reflect,queryType:Module.NBind.queryType,toggleLightGC:Module.toggleLightGC,lib:Module})}}(Module.onRuntimeInitialized,cb);var Module;Module||(Module=(typeof Module<"u"?Module:null)||{});var moduleOverrides={};for(var key in Module)Module.hasOwnProperty(key)&&(moduleOverrides[key]=Module[key]);var ENVIRONMENT_IS_WEB=!1,ENVIRONMENT_IS_WORKER=!1,ENVIRONMENT_IS_NODE=!1,ENVIRONMENT_IS_SHELL=!1;if(Module.ENVIRONMENT)if(Module.ENVIRONMENT==="WEB")ENVIRONMENT_IS_WEB=!0;else if(Module.ENVIRONMENT==="WORKER")ENVIRONMENT_IS_WORKER=!0;else if(Module.ENVIRONMENT==="NODE")ENVIRONMENT_IS_NODE=!0;else if(Module.ENVIRONMENT==="SHELL")ENVIRONMENT_IS_SHELL=!0;else throw new Error("The provided Module['ENVIRONMENT'] value is not valid. It must be one of: WEB|WORKER|NODE|SHELL.");else ENVIRONMENT_IS_WEB=typeof window=="object",ENVIRONMENT_IS_WORKER=typeof importScripts=="function",ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof Ie=="function"&&!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_WORKER,ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;if(ENVIRONMENT_IS_NODE){Module.print||(Module.print=console.log),Module.printErr||(Module.printErr=console.warn);var nodeFS,nodePath;Module.read=function(e,r){nodeFS||(nodeFS={}("")),nodePath||(nodePath={}("")),e=nodePath.normalize(e);var s=nodeFS.readFileSync(e);return r?s:s.toString()},Module.readBinary=function(e){var r=Module.read(e,!0);return r.buffer||(r=new Uint8Array(r)),assert(r.buffer),r},Module.load=function(e){globalEval(read(e))},Module.thisProgram||(process.argv.length>1?Module.thisProgram=process.argv[1].replace(/\\/g,"/"):Module.thisProgram="unknown-program"),Module.arguments=process.argv.slice(2),typeof module<"u"&&(module.exports=Module),Module.inspect=function(){return"[Emscripten Module object]"}}else if(ENVIRONMENT_IS_SHELL)Module.print||(Module.print=print),typeof printErr<"u"&&(Module.printErr=printErr),typeof read<"u"?Module.read=read:Module.read=function(){throw"no read() available"},Module.readBinary=function(e){if(typeof readbuffer=="function")return new Uint8Array(readbuffer(e));var r=read(e,"binary");return assert(typeof r=="object"),r},typeof scriptArgs<"u"?Module.arguments=scriptArgs:typeof arguments<"u"&&(Module.arguments=arguments),typeof quit=="function"&&(Module.quit=function(t,e){quit(t)});else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(Module.read=function(e){var r=new XMLHttpRequest;return r.open("GET",e,!1),r.send(null),r.responseText},ENVIRONMENT_IS_WORKER&&(Module.readBinary=function(e){var r=new XMLHttpRequest;return r.open("GET",e,!1),r.responseType="arraybuffer",r.send(null),new Uint8Array(r.response)}),Module.readAsync=function(e,r,s){var a=new XMLHttpRequest;a.open("GET",e,!0),a.responseType="arraybuffer",a.onload=function(){a.status==200||a.status==0&&a.response?r(a.response):s()},a.onerror=s,a.send(null)},typeof arguments<"u"&&(Module.arguments=arguments),typeof console<"u")Module.print||(Module.print=function(e){console.log(e)}),Module.printErr||(Module.printErr=function(e){console.warn(e)});else{var TRY_USE_DUMP=!1;Module.print||(Module.print=TRY_USE_DUMP&&typeof dump<"u"?function(t){dump(t)}:function(t){})}ENVIRONMENT_IS_WORKER&&(Module.load=importScripts),typeof Module.setWindowTitle>"u"&&(Module.setWindowTitle=function(t){document.title=t})}else throw"Unknown runtime environment. Where are we?";function globalEval(t){eval.call(null,t)}!Module.load&&Module.read&&(Module.load=function(e){globalEval(Module.read(e))}),Module.print||(Module.print=function(){}),Module.printErr||(Module.printErr=Module.print),Module.arguments||(Module.arguments=[]),Module.thisProgram||(Module.thisProgram="./this.program"),Module.quit||(Module.quit=function(t,e){throw e}),Module.print=Module.print,Module.printErr=Module.printErr,Module.preRun=[],Module.postRun=[];for(var key in moduleOverrides)moduleOverrides.hasOwnProperty(key)&&(Module[key]=moduleOverrides[key]);moduleOverrides=void 0;var Runtime={setTempRet0:function(t){return tempRet0=t,t},getTempRet0:function(){return tempRet0},stackSave:function(){return STACKTOP},stackRestore:function(t){STACKTOP=t},getNativeTypeSize:function(t){switch(t){case"i1":case"i8":return 1;case"i16":return 2;case"i32":return 4;case"i64":return 8;case"float":return 4;case"double":return 8;default:{if(t[t.length-1]==="*")return Runtime.QUANTUM_SIZE;if(t[0]==="i"){var e=parseInt(t.substr(1));return assert(e%8===0),e/8}else return 0}}},getNativeFieldSize:function(t){return Math.max(Runtime.getNativeTypeSize(t),Runtime.QUANTUM_SIZE)},STACK_ALIGN:16,prepVararg:function(t,e){return e==="double"||e==="i64"?t&7&&(assert((t&7)===4),t+=4):assert((t&3)===0),t},getAlignSize:function(t,e,r){return!r&&(t=="i64"||t=="double")?8:t?Math.min(e||(t?Runtime.getNativeFieldSize(t):0),Runtime.QUANTUM_SIZE):Math.min(e,8)},dynCall:function(t,e,r){return r&&r.length?Module["dynCall_"+t].apply(null,[e].concat(r)):Module["dynCall_"+t].call(null,e)},functionPointers:[],addFunction:function(t){for(var e=0;e>2],r=(e+t+15|0)&-16;if(HEAP32[DYNAMICTOP_PTR>>2]=r,r>=TOTAL_MEMORY){var s=enlargeMemory();if(!s)return HEAP32[DYNAMICTOP_PTR>>2]=e,0}return e},alignMemory:function(t,e){var r=t=Math.ceil(t/(e||16))*(e||16);return r},makeBigInt:function(t,e,r){var s=r?+(t>>>0)+ +(e>>>0)*4294967296:+(t>>>0)+ +(e|0)*4294967296;return s},GLOBAL_BASE:8,QUANTUM_SIZE:4,__dummy__:0};Module.Runtime=Runtime;var ABORT=0,EXITSTATUS=0;function assert(t,e){t||abort("Assertion failed: "+e)}function getCFunc(ident){var func=Module["_"+ident];if(!func)try{func=eval("_"+ident)}catch(t){}return assert(func,"Cannot call unknown function "+ident+" (perhaps LLVM optimizations or closure removed it?)"),func}var cwrap,ccall;(function(){var JSfuncs={stackSave:function(){Runtime.stackSave()},stackRestore:function(){Runtime.stackRestore()},arrayToC:function(t){var e=Runtime.stackAlloc(t.length);return writeArrayToMemory(t,e),e},stringToC:function(t){var e=0;if(t!=null&&t!==0){var r=(t.length<<2)+1;e=Runtime.stackAlloc(r),stringToUTF8(t,e,r)}return e}},toC={string:JSfuncs.stringToC,array:JSfuncs.arrayToC};ccall=function(e,r,s,a,n){var c=getCFunc(e),f=[],p=0;if(a)for(var h=0;h>0]=e;break;case"i8":HEAP8[t>>0]=e;break;case"i16":HEAP16[t>>1]=e;break;case"i32":HEAP32[t>>2]=e;break;case"i64":tempI64=[e>>>0,(tempDouble=e,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[t>>2]=tempI64[0],HEAP32[t+4>>2]=tempI64[1];break;case"float":HEAPF32[t>>2]=e;break;case"double":HEAPF64[t>>3]=e;break;default:abort("invalid type for setValue: "+r)}}Module.setValue=setValue;function getValue(t,e,r){switch(e=e||"i8",e.charAt(e.length-1)==="*"&&(e="i32"),e){case"i1":return HEAP8[t>>0];case"i8":return HEAP8[t>>0];case"i16":return HEAP16[t>>1];case"i32":return HEAP32[t>>2];case"i64":return HEAP32[t>>2];case"float":return HEAPF32[t>>2];case"double":return HEAPF64[t>>3];default:abort("invalid type for setValue: "+e)}return null}Module.getValue=getValue;var ALLOC_NORMAL=0,ALLOC_STACK=1,ALLOC_STATIC=2,ALLOC_DYNAMIC=3,ALLOC_NONE=4;Module.ALLOC_NORMAL=ALLOC_NORMAL,Module.ALLOC_STACK=ALLOC_STACK,Module.ALLOC_STATIC=ALLOC_STATIC,Module.ALLOC_DYNAMIC=ALLOC_DYNAMIC,Module.ALLOC_NONE=ALLOC_NONE;function allocate(t,e,r,s){var a,n;typeof t=="number"?(a=!0,n=t):(a=!1,n=t.length);var c=typeof e=="string"?e:null,f;if(r==ALLOC_NONE?f=s:f=[typeof _malloc=="function"?_malloc:Runtime.staticAlloc,Runtime.stackAlloc,Runtime.staticAlloc,Runtime.dynamicAlloc][r===void 0?ALLOC_STATIC:r](Math.max(n,c?1:e.length)),a){var s=f,p;for(assert((f&3)==0),p=f+(n&-4);s>2]=0;for(p=f+n;s>0]=0;return f}if(c==="i8")return t.subarray||t.slice?HEAPU8.set(t,f):HEAPU8.set(new Uint8Array(t),f),f;for(var h=0,E,C,S;h>0],r|=s,!(s==0&&!e||(a++,e&&a==e)););e||(e=a);var n="";if(r<128){for(var c=1024,f;e>0;)f=String.fromCharCode.apply(String,HEAPU8.subarray(t,t+Math.min(e,c))),n=n?n+f:f,t+=c,e-=c;return n}return Module.UTF8ToString(t)}Module.Pointer_stringify=Pointer_stringify;function AsciiToString(t){for(var e="";;){var r=HEAP8[t++>>0];if(!r)return e;e+=String.fromCharCode(r)}}Module.AsciiToString=AsciiToString;function stringToAscii(t,e){return writeAsciiToMemory(t,e,!1)}Module.stringToAscii=stringToAscii;var UTF8Decoder=typeof TextDecoder<"u"?new TextDecoder("utf8"):void 0;function UTF8ArrayToString(t,e){for(var r=e;t[r];)++r;if(r-e>16&&t.subarray&&UTF8Decoder)return UTF8Decoder.decode(t.subarray(e,r));for(var s,a,n,c,f,p,h="";;){if(s=t[e++],!s)return h;if(!(s&128)){h+=String.fromCharCode(s);continue}if(a=t[e++]&63,(s&224)==192){h+=String.fromCharCode((s&31)<<6|a);continue}if(n=t[e++]&63,(s&240)==224?s=(s&15)<<12|a<<6|n:(c=t[e++]&63,(s&248)==240?s=(s&7)<<18|a<<12|n<<6|c:(f=t[e++]&63,(s&252)==248?s=(s&3)<<24|a<<18|n<<12|c<<6|f:(p=t[e++]&63,s=(s&1)<<30|a<<24|n<<18|c<<12|f<<6|p))),s<65536)h+=String.fromCharCode(s);else{var E=s-65536;h+=String.fromCharCode(55296|E>>10,56320|E&1023)}}}Module.UTF8ArrayToString=UTF8ArrayToString;function UTF8ToString(t){return UTF8ArrayToString(HEAPU8,t)}Module.UTF8ToString=UTF8ToString;function stringToUTF8Array(t,e,r,s){if(!(s>0))return 0;for(var a=r,n=r+s-1,c=0;c=55296&&f<=57343&&(f=65536+((f&1023)<<10)|t.charCodeAt(++c)&1023),f<=127){if(r>=n)break;e[r++]=f}else if(f<=2047){if(r+1>=n)break;e[r++]=192|f>>6,e[r++]=128|f&63}else if(f<=65535){if(r+2>=n)break;e[r++]=224|f>>12,e[r++]=128|f>>6&63,e[r++]=128|f&63}else if(f<=2097151){if(r+3>=n)break;e[r++]=240|f>>18,e[r++]=128|f>>12&63,e[r++]=128|f>>6&63,e[r++]=128|f&63}else if(f<=67108863){if(r+4>=n)break;e[r++]=248|f>>24,e[r++]=128|f>>18&63,e[r++]=128|f>>12&63,e[r++]=128|f>>6&63,e[r++]=128|f&63}else{if(r+5>=n)break;e[r++]=252|f>>30,e[r++]=128|f>>24&63,e[r++]=128|f>>18&63,e[r++]=128|f>>12&63,e[r++]=128|f>>6&63,e[r++]=128|f&63}}return e[r]=0,r-a}Module.stringToUTF8Array=stringToUTF8Array;function stringToUTF8(t,e,r){return stringToUTF8Array(t,HEAPU8,e,r)}Module.stringToUTF8=stringToUTF8;function lengthBytesUTF8(t){for(var e=0,r=0;r=55296&&s<=57343&&(s=65536+((s&1023)<<10)|t.charCodeAt(++r)&1023),s<=127?++e:s<=2047?e+=2:s<=65535?e+=3:s<=2097151?e+=4:s<=67108863?e+=5:e+=6}return e}Module.lengthBytesUTF8=lengthBytesUTF8;var UTF16Decoder=typeof TextDecoder<"u"?new TextDecoder("utf-16le"):void 0;function demangle(t){var e=Module.___cxa_demangle||Module.__cxa_demangle;if(e){try{var r=t.substr(1),s=lengthBytesUTF8(r)+1,a=_malloc(s);stringToUTF8(r,a,s);var n=_malloc(4),c=e(a,0,0,n);if(getValue(n,"i32")===0&&c)return Pointer_stringify(c)}catch{}finally{a&&_free(a),n&&_free(n),c&&_free(c)}return t}return Runtime.warnOnce("warning: build with -s DEMANGLE_SUPPORT=1 to link in libcxxabi demangling"),t}function demangleAll(t){var e=/__Z[\w\d_]+/g;return t.replace(e,function(r){var s=demangle(r);return r===s?r:r+" ["+s+"]"})}function jsStackTrace(){var t=new Error;if(!t.stack){try{throw new Error(0)}catch(e){t=e}if(!t.stack)return"(no stack trace available)"}return t.stack.toString()}function stackTrace(){var t=jsStackTrace();return Module.extraStackTrace&&(t+=` +`+Module.extraStackTrace()),demangleAll(t)}Module.stackTrace=stackTrace;var HEAP,buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBufferViews(){Module.HEAP8=HEAP8=new Int8Array(buffer),Module.HEAP16=HEAP16=new Int16Array(buffer),Module.HEAP32=HEAP32=new Int32Array(buffer),Module.HEAPU8=HEAPU8=new Uint8Array(buffer),Module.HEAPU16=HEAPU16=new Uint16Array(buffer),Module.HEAPU32=HEAPU32=new Uint32Array(buffer),Module.HEAPF32=HEAPF32=new Float32Array(buffer),Module.HEAPF64=HEAPF64=new Float64Array(buffer)}var STATIC_BASE,STATICTOP,staticSealed,STACK_BASE,STACKTOP,STACK_MAX,DYNAMIC_BASE,DYNAMICTOP_PTR;STATIC_BASE=STATICTOP=STACK_BASE=STACKTOP=STACK_MAX=DYNAMIC_BASE=DYNAMICTOP_PTR=0,staticSealed=!1;function abortOnCannotGrowMemory(){abort("Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value "+TOTAL_MEMORY+", (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime but prevents some optimizations, (3) set Module.TOTAL_MEMORY to a higher value before the program runs, or (4) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 ")}function enlargeMemory(){abortOnCannotGrowMemory()}var TOTAL_STACK=Module.TOTAL_STACK||5242880,TOTAL_MEMORY=Module.TOTAL_MEMORY||134217728;TOTAL_MEMORY0;){var e=t.shift();if(typeof e=="function"){e();continue}var r=e.func;typeof r=="number"?e.arg===void 0?Module.dynCall_v(r):Module.dynCall_vi(r,e.arg):r(e.arg===void 0?null:e.arg)}}var __ATPRERUN__=[],__ATINIT__=[],__ATMAIN__=[],__ATEXIT__=[],__ATPOSTRUN__=[],runtimeInitialized=!1,runtimeExited=!1;function preRun(){if(Module.preRun)for(typeof Module.preRun=="function"&&(Module.preRun=[Module.preRun]);Module.preRun.length;)addOnPreRun(Module.preRun.shift());callRuntimeCallbacks(__ATPRERUN__)}function ensureInitRuntime(){runtimeInitialized||(runtimeInitialized=!0,callRuntimeCallbacks(__ATINIT__))}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function exitRuntime(){callRuntimeCallbacks(__ATEXIT__),runtimeExited=!0}function postRun(){if(Module.postRun)for(typeof Module.postRun=="function"&&(Module.postRun=[Module.postRun]);Module.postRun.length;)addOnPostRun(Module.postRun.shift());callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(t){__ATPRERUN__.unshift(t)}Module.addOnPreRun=addOnPreRun;function addOnInit(t){__ATINIT__.unshift(t)}Module.addOnInit=addOnInit;function addOnPreMain(t){__ATMAIN__.unshift(t)}Module.addOnPreMain=addOnPreMain;function addOnExit(t){__ATEXIT__.unshift(t)}Module.addOnExit=addOnExit;function addOnPostRun(t){__ATPOSTRUN__.unshift(t)}Module.addOnPostRun=addOnPostRun;function intArrayFromString(t,e,r){var s=r>0?r:lengthBytesUTF8(t)+1,a=new Array(s),n=stringToUTF8Array(t,a,0,a.length);return e&&(a.length=n),a}Module.intArrayFromString=intArrayFromString;function intArrayToString(t){for(var e=[],r=0;r255&&(s&=255),e.push(String.fromCharCode(s))}return e.join("")}Module.intArrayToString=intArrayToString;function writeStringToMemory(t,e,r){Runtime.warnOnce("writeStringToMemory is deprecated and should not be called! Use stringToUTF8() instead!");var s,a;r&&(a=e+lengthBytesUTF8(t),s=HEAP8[a]),stringToUTF8(t,e,1/0),r&&(HEAP8[a]=s)}Module.writeStringToMemory=writeStringToMemory;function writeArrayToMemory(t,e){HEAP8.set(t,e)}Module.writeArrayToMemory=writeArrayToMemory;function writeAsciiToMemory(t,e,r){for(var s=0;s>0]=t.charCodeAt(s);r||(HEAP8[e>>0]=0)}if(Module.writeAsciiToMemory=writeAsciiToMemory,(!Math.imul||Math.imul(4294967295,5)!==-5)&&(Math.imul=function t(e,r){var s=e>>>16,a=e&65535,n=r>>>16,c=r&65535;return a*c+(s*c+a*n<<16)|0}),Math.imul=Math.imul,!Math.fround){var froundBuffer=new Float32Array(1);Math.fround=function(t){return froundBuffer[0]=t,froundBuffer[0]}}Math.fround=Math.fround,Math.clz32||(Math.clz32=function(t){t=t>>>0;for(var e=0;e<32;e++)if(t&1<<31-e)return e;return 32}),Math.clz32=Math.clz32,Math.trunc||(Math.trunc=function(t){return t<0?Math.ceil(t):Math.floor(t)}),Math.trunc=Math.trunc;var Math_abs=Math.abs,Math_cos=Math.cos,Math_sin=Math.sin,Math_tan=Math.tan,Math_acos=Math.acos,Math_asin=Math.asin,Math_atan=Math.atan,Math_atan2=Math.atan2,Math_exp=Math.exp,Math_log=Math.log,Math_sqrt=Math.sqrt,Math_ceil=Math.ceil,Math_floor=Math.floor,Math_pow=Math.pow,Math_imul=Math.imul,Math_fround=Math.fround,Math_round=Math.round,Math_min=Math.min,Math_clz32=Math.clz32,Math_trunc=Math.trunc,runDependencies=0,runDependencyWatcher=null,dependenciesFulfilled=null;function getUniqueRunDependency(t){return t}function addRunDependency(t){runDependencies++,Module.monitorRunDependencies&&Module.monitorRunDependencies(runDependencies)}Module.addRunDependency=addRunDependency;function removeRunDependency(t){if(runDependencies--,Module.monitorRunDependencies&&Module.monitorRunDependencies(runDependencies),runDependencies==0&&(runDependencyWatcher!==null&&(clearInterval(runDependencyWatcher),runDependencyWatcher=null),dependenciesFulfilled)){var e=dependenciesFulfilled;dependenciesFulfilled=null,e()}}Module.removeRunDependency=removeRunDependency,Module.preloadedImages={},Module.preloadedAudios={};var ASM_CONSTS=[function(t,e,r,s,a,n,c,f){return _nbind.callbackSignatureList[t].apply(this,arguments)}];function _emscripten_asm_const_iiiiiiii(t,e,r,s,a,n,c,f){return ASM_CONSTS[t](e,r,s,a,n,c,f)}function _emscripten_asm_const_iiiii(t,e,r,s,a){return ASM_CONSTS[t](e,r,s,a)}function _emscripten_asm_const_iiidddddd(t,e,r,s,a,n,c,f,p){return ASM_CONSTS[t](e,r,s,a,n,c,f,p)}function _emscripten_asm_const_iiididi(t,e,r,s,a,n,c){return ASM_CONSTS[t](e,r,s,a,n,c)}function _emscripten_asm_const_iiii(t,e,r,s){return ASM_CONSTS[t](e,r,s)}function _emscripten_asm_const_iiiid(t,e,r,s,a){return ASM_CONSTS[t](e,r,s,a)}function _emscripten_asm_const_iiiiii(t,e,r,s,a,n){return ASM_CONSTS[t](e,r,s,a,n)}STATIC_BASE=Runtime.GLOBAL_BASE,STATICTOP=STATIC_BASE+12800,__ATINIT__.push({func:function(){__GLOBAL__sub_I_Yoga_cpp()}},{func:function(){__GLOBAL__sub_I_nbind_cc()}},{func:function(){__GLOBAL__sub_I_common_cc()}},{func:function(){__GLOBAL__sub_I_Binding_cc()}}),allocate([0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,4,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,192,127,0,0,192,127,0,0,192,127,0,0,192,127,3,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,3,0,0,0,0,0,192,127,3,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,127,0,0,192,127,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,192,127,0,0,0,0,0,0,0,0,255,255,255,255,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,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,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,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,192,127,0,0,192,127,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,0,0,128,191,0,0,128,191,0,0,192,127,0,0,0,0,0,0,0,0,0,0,128,63,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,3,0,0,0,1,0,0,0,2,0,0,0,0,0,0,0,190,12,0,0,200,12,0,0,208,12,0,0,216,12,0,0,230,12,0,0,242,12,0,0,1,0,0,0,3,0,0,0,0,0,0,0,2,0,0,0,0,0,192,127,3,0,0,0,180,45,0,0,181,45,0,0,182,45,0,0,181,45,0,0,182,45,0,0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,3,0,0,0,1,0,0,0,4,0,0,0,183,45,0,0,181,45,0,0,181,45,0,0,181,45,0,0,181,45,0,0,181,45,0,0,181,45,0,0,184,45,0,0,185,45,0,0,181,45,0,0,181,45,0,0,182,45,0,0,186,45,0,0,185,45,0,0,148,4,0,0,3,0,0,0,187,45,0,0,164,4,0,0,188,45,0,0,2,0,0,0,189,45,0,0,164,4,0,0,188,45,0,0,185,45,0,0,164,4,0,0,185,45,0,0,164,4,0,0,188,45,0,0,181,45,0,0,182,45,0,0,181,45,0,0,0,0,0,0,0,0,0,0,1,0,0,0,5,0,0,0,6,0,0,0,1,0,0,0,7,0,0,0,183,45,0,0,182,45,0,0,181,45,0,0,190,45,0,0,190,45,0,0,182,45,0,0,182,45,0,0,185,45,0,0,181,45,0,0,185,45,0,0,182,45,0,0,181,45,0,0,185,45,0,0,182,45,0,0,185,45,0,0,48,5,0,0,3,0,0,0,56,5,0,0,1,0,0,0,189,45,0,0,185,45,0,0,164,4,0,0,76,5,0,0,2,0,0,0,191,45,0,0,186,45,0,0,182,45,0,0,185,45,0,0,192,45,0,0,185,45,0,0,182,45,0,0,186,45,0,0,185,45,0,0,76,5,0,0,76,5,0,0,136,5,0,0,182,45,0,0,181,45,0,0,2,0,0,0,190,45,0,0,136,5,0,0,56,19,0,0,156,5,0,0,2,0,0,0,184,45,0,0,0,0,0,0,0,0,0,0,1,0,0,0,8,0,0,0,9,0,0,0,1,0,0,0,10,0,0,0,204,5,0,0,181,45,0,0,181,45,0,0,2,0,0,0,180,45,0,0,204,5,0,0,2,0,0,0,195,45,0,0,236,5,0,0,97,19,0,0,198,45,0,0,211,45,0,0,212,45,0,0,213,45,0,0,214,45,0,0,215,45,0,0,188,45,0,0,182,45,0,0,216,45,0,0,217,45,0,0,218,45,0,0,219,45,0,0,192,45,0,0,181,45,0,0,0,0,0,0,185,45,0,0,110,19,0,0,186,45,0,0,115,19,0,0,221,45,0,0,120,19,0,0,148,4,0,0,132,19,0,0,96,6,0,0,145,19,0,0,222,45,0,0,164,19,0,0,223,45,0,0,173,19,0,0,0,0,0,0,3,0,0,0,104,6,0,0,1,0,0,0,187,45,0,0,0,0,0,0,0,0,0,0,1,0,0,0,11,0,0,0,12,0,0,0,1,0,0,0,13,0,0,0,185,45,0,0,224,45,0,0,164,6,0,0,188,45,0,0,172,6,0,0,180,6,0,0,2,0,0,0,188,6,0,0,7,0,0,0,224,45,0,0,7,0,0,0,164,6,0,0,1,0,0,0,213,45,0,0,185,45,0,0,224,45,0,0,172,6,0,0,185,45,0,0,224,45,0,0,164,6,0,0,185,45,0,0,224,45,0,0,211,45,0,0,211,45,0,0,222,45,0,0,211,45,0,0,224,45,0,0,222,45,0,0,211,45,0,0,224,45,0,0,172,6,0,0,222,45,0,0,211,45,0,0,224,45,0,0,188,45,0,0,222,45,0,0,211,45,0,0,40,7,0,0,188,45,0,0,2,0,0,0,224,45,0,0,185,45,0,0,188,45,0,0,188,45,0,0,188,45,0,0,188,45,0,0,222,45,0,0,224,45,0,0,148,4,0,0,185,45,0,0,148,4,0,0,148,4,0,0,148,4,0,0,148,4,0,0,148,4,0,0,185,45,0,0,164,6,0,0,148,4,0,0,0,0,0,0,0,0,0,0,1,0,0,0,14,0,0,0,15,0,0,0,1,0,0,0,16,0,0,0,148,7,0,0,2,0,0,0,225,45,0,0,183,45,0,0,188,45,0,0,168,7,0,0,5,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,234,45,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,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,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,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,148,45,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,28,9,0,0,5,0,0,0,0,0,0,0,0,0,0,0,1,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,0,2,0,0,0,242,45,0,0,0,4,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,255,255,255,255,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,67,111,117,108,100,32,110,111,116,32,97,108,108,111,99,97,116,101,32,109,101,109,111,114,121,32,102,111,114,32,110,111,100,101,0,67,97,110,110,111,116,32,114,101,115,101,116,32,97,32,110,111,100,101,32,119,104,105,99,104,32,115,116,105,108,108,32,104,97,115,32,99,104,105,108,100,114,101,110,32,97,116,116,97,99,104,101,100,0,67,97,110,110,111,116,32,114,101,115,101,116,32,97,32,110,111,100,101,32,115,116,105,108,108,32,97,116,116,97,99,104,101,100,32,116,111,32,97,32,112,97,114,101,110,116,0,67,111,117,108,100,32,110,111,116,32,97,108,108,111,99,97,116,101,32,109,101,109,111,114,121,32,102,111,114,32,99,111,110,102,105,103,0,67,97,110,110,111,116,32,115,101,116,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,58,32,78,111,100,101,115,32,119,105,116,104,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,115,32,99,97,110,110,111,116,32,104,97,118,101,32,99,104,105,108,100,114,101,110,46,0,67,104,105,108,100,32,97,108,114,101,97,100,121,32,104,97,115,32,97,32,112,97,114,101,110,116,44,32,105,116,32,109,117,115,116,32,98,101,32,114,101,109,111,118,101,100,32,102,105,114,115,116,46,0,67,97,110,110,111,116,32,97,100,100,32,99,104,105,108,100,58,32,78,111,100,101,115,32,119,105,116,104,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,115,32,99,97,110,110,111,116,32,104,97,118,101,32,99,104,105,108,100,114,101,110,46,0,79,110,108,121,32,108,101,97,102,32,110,111,100,101,115,32,119,105,116,104,32,99,117,115,116,111,109,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,115,115,104,111,117,108,100,32,109,97,110,117,97,108,108,121,32,109,97,114,107,32,116,104,101,109,115,101,108,118,101,115,32,97,115,32,100,105,114,116,121,0,67,97,110,110,111,116,32,103,101,116,32,108,97,121,111,117,116,32,112,114,111,112,101,114,116,105,101,115,32,111,102,32,109,117,108,116,105,45,101,100,103,101,32,115,104,111,114,116,104,97,110,100,115,0,37,115,37,100,46,123,91,115,107,105,112,112,101,100,93,32,0,119,109,58,32,37,115,44,32,104,109,58,32,37,115,44,32,97,119,58,32,37,102,32,97,104,58,32,37,102,32,61,62,32,100,58,32,40,37,102,44,32,37,102,41,32,37,115,10,0,37,115,37,100,46,123,37,115,0,42,0,119,109,58,32,37,115,44,32,104,109,58,32,37,115,44,32,97,119,58,32,37,102,32,97,104,58,32,37,102,32,37,115,10,0,37,115,37,100,46,125,37,115,0,119,109,58,32,37,115,44,32,104,109,58,32,37,115,44,32,100,58,32,40,37,102,44,32,37,102,41,32,37,115,10,0,79,117,116,32,111,102,32,99,97,99,104,101,32,101,110,116,114,105,101,115,33,10,0,83,99,97,108,101,32,102,97,99,116,111,114,32,115,104,111,117,108,100,32,110,111,116,32,98,101,32,108,101,115,115,32,116,104,97,110,32,122,101,114,111,0,105,110,105,116,105,97,108,0,37,115,10,0,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,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,0,85,78,68,69,70,73,78,69,68,0,69,88,65,67,84,76,89,0,65,84,95,77,79,83,84,0,76,65,89,95,85,78,68,69,70,73,78,69,68,0,76,65,89,95,69,88,65,67,84,76,89,0,76,65,89,95,65,84,95,77,79,83,84,0,97,118,97,105,108,97,98,108,101,87,105,100,116,104,32,105,115,32,105,110,100,101,102,105,110,105,116,101,32,115,111,32,119,105,100,116,104,77,101,97,115,117,114,101,77,111,100,101,32,109,117,115,116,32,98,101,32,89,71,77,101,97,115,117,114,101,77,111,100,101,85,110,100,101,102,105,110,101,100,0,97,118,97,105,108,97,98,108,101,72,101,105,103,104,116,32,105,115,32,105,110,100,101,102,105,110,105,116,101,32,115,111,32,104,101,105,103,104,116,77,101,97,115,117,114,101,77,111,100,101,32,109,117,115,116,32,98,101,32,89,71,77,101,97,115,117,114,101,77,111,100,101,85,110,100,101,102,105,110,101,100,0,102,108,101,120,0,115,116,114,101,116,99,104,0,109,117,108,116,105,108,105,110,101,45,115,116,114,101,116,99,104,0,69,120,112,101,99,116,101,100,32,110,111,100,101,32,116,111,32,104,97,118,101,32,99,117,115,116,111,109,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,0,109,101,97,115,117,114,101,0,69,120,112,101,99,116,32,99,117,115,116,111,109,32,98,97,115,101,108,105,110,101,32,102,117,110,99,116,105,111,110,32,116,111,32,110,111,116,32,114,101,116,117,114,110,32,78,97,78,0,97,98,115,45,109,101,97,115,117,114,101,0,97,98,115,45,108,97,121,111,117,116,0,78,111,100,101,0,99,114,101,97,116,101,68,101,102,97,117,108,116,0,99,114,101,97,116,101,87,105,116,104,67,111,110,102,105,103,0,100,101,115,116,114,111,121,0,114,101,115,101,116,0,99,111,112,121,83,116,121,108,101,0,115,101,116,80,111,115,105,116,105,111,110,84,121,112,101,0,115,101,116,80,111,115,105,116,105,111,110,0,115,101,116,80,111,115,105,116,105,111,110,80,101,114,99,101,110,116,0,115,101,116,65,108,105,103,110,67,111,110,116,101,110,116,0,115,101,116,65,108,105,103,110,73,116,101,109,115,0,115,101,116,65,108,105,103,110,83,101,108,102,0,115,101,116,70,108,101,120,68,105,114,101,99,116,105,111,110,0,115,101,116,70,108,101,120,87,114,97,112,0,115,101,116,74,117,115,116,105,102,121,67,111,110,116,101,110,116,0,115,101,116,77,97,114,103,105,110,0,115,101,116,77,97,114,103,105,110,80,101,114,99,101,110,116,0,115,101,116,77,97,114,103,105,110,65,117,116,111,0,115,101,116,79,118,101,114,102,108,111,119,0,115,101,116,68,105,115,112,108,97,121,0,115,101,116,70,108,101,120,0,115,101,116,70,108,101,120,66,97,115,105,115,0,115,101,116,70,108,101,120,66,97,115,105,115,80,101,114,99,101,110,116,0,115,101,116,70,108,101,120,71,114,111,119,0,115,101,116,70,108,101,120,83,104,114,105,110,107,0,115,101,116,87,105,100,116,104,0,115,101,116,87,105,100,116,104,80,101,114,99,101,110,116,0,115,101,116,87,105,100,116,104,65,117,116,111,0,115,101,116,72,101,105,103,104,116,0,115,101,116,72,101,105,103,104,116,80,101,114,99,101,110,116,0,115,101,116,72,101,105,103,104,116,65,117,116,111,0,115,101,116,77,105,110,87,105,100,116,104,0,115,101,116,77,105,110,87,105,100,116,104,80,101,114,99,101,110,116,0,115,101,116,77,105,110,72,101,105,103,104,116,0,115,101,116,77,105,110,72,101,105,103,104,116,80,101,114,99,101,110,116,0,115,101,116,77,97,120,87,105,100,116,104,0,115,101,116,77,97,120,87,105,100,116,104,80,101,114,99,101,110,116,0,115,101,116,77,97,120,72,101,105,103,104,116,0,115,101,116,77,97,120,72,101,105,103,104,116,80,101,114,99,101,110,116,0,115,101,116,65,115,112,101,99,116,82,97,116,105,111,0,115,101,116,66,111,114,100,101,114,0,115,101,116,80,97,100,100,105,110,103,0,115,101,116,80,97,100,100,105,110,103,80,101,114,99,101,110,116,0,103,101,116,80,111,115,105,116,105,111,110,84,121,112,101,0,103,101,116,80,111,115,105,116,105,111,110,0,103,101,116,65,108,105,103,110,67,111,110,116,101,110,116,0,103,101,116,65,108,105,103,110,73,116,101,109,115,0,103,101,116,65,108,105,103,110,83,101,108,102,0,103,101,116,70,108,101,120,68,105,114,101,99,116,105,111,110,0,103,101,116,70,108,101,120,87,114,97,112,0,103,101,116,74,117,115,116,105,102,121,67,111,110,116,101,110,116,0,103,101,116,77,97,114,103,105,110,0,103,101,116,70,108,101,120,66,97,115,105,115,0,103,101,116,70,108,101,120,71,114,111,119,0,103,101,116,70,108,101,120,83,104,114,105,110,107,0,103,101,116,87,105,100,116,104,0,103,101,116,72,101,105,103,104,116,0,103,101,116,77,105,110,87,105,100,116,104,0,103,101,116,77,105,110,72,101,105,103,104,116,0,103,101,116,77,97,120,87,105,100,116,104,0,103,101,116,77,97,120,72,101,105,103,104,116,0,103,101,116,65,115,112,101,99,116,82,97,116,105,111,0,103,101,116,66,111,114,100,101,114,0,103,101,116,79,118,101,114,102,108,111,119,0,103,101,116,68,105,115,112,108,97,121,0,103,101,116,80,97,100,100,105,110,103,0,105,110,115,101,114,116,67,104,105,108,100,0,114,101,109,111,118,101,67,104,105,108,100,0,103,101,116,67,104,105,108,100,67,111,117,110,116,0,103,101,116,80,97,114,101,110,116,0,103,101,116,67,104,105,108,100,0,115,101,116,77,101,97,115,117,114,101,70,117,110,99,0,117,110,115,101,116,77,101,97,115,117,114,101,70,117,110,99,0,109,97,114,107,68,105,114,116,121,0,105,115,68,105,114,116,121,0,99,97,108,99,117,108,97,116,101,76,97,121,111,117,116,0,103,101,116,67,111,109,112,117,116,101,100,76,101,102,116,0,103,101,116,67,111,109,112,117,116,101,100,82,105,103,104,116,0,103,101,116,67,111,109,112,117,116,101,100,84,111,112,0,103,101,116,67,111,109,112,117,116,101,100,66,111,116,116,111,109,0,103,101,116,67,111,109,112,117,116,101,100,87,105,100,116,104,0,103,101,116,67,111,109,112,117,116,101,100,72,101,105,103,104,116,0,103,101,116,67,111,109,112,117,116,101,100,76,97,121,111,117,116,0,103,101,116,67,111,109,112,117,116,101,100,77,97,114,103,105,110,0,103,101,116,67,111,109,112,117,116,101,100,66,111,114,100,101,114,0,103,101,116,67,111,109,112,117,116,101,100,80,97,100,100,105,110,103,0,67,111,110,102,105,103,0,99,114,101,97,116,101,0,115,101,116,69,120,112,101,114,105,109,101,110,116,97,108,70,101,97,116,117,114,101,69,110,97,98,108,101,100,0,115,101,116,80,111,105,110,116,83,99,97,108,101,70,97,99,116,111,114,0,105,115,69,120,112,101,114,105,109,101,110,116,97,108,70,101,97,116,117,114,101,69,110,97,98,108,101,100,0,86,97,108,117,101,0,76,97,121,111,117,116,0,83,105,122,101,0,103,101,116,73,110,115,116,97,110,99,101,67,111,117,110,116,0,73,110,116,54,52,0,1,1,1,2,2,4,4,4,4,8,8,4,8,118,111,105,100,0,98,111,111,108,0,115,116,100,58,58,115,116,114,105,110,103,0,99,98,70,117,110,99,116,105,111,110,32,38,0,99,111,110,115,116,32,99,98,70,117,110,99,116,105,111,110,32,38,0,69,120,116,101,114,110,97,108,0,66,117,102,102,101,114,0,78,66,105,110,100,73,68,0,78,66,105,110,100,0,98,105,110,100,95,118,97,108,117,101,0,114,101,102,108,101,99,116,0,113,117,101,114,121,84,121,112,101,0,108,97,108,108,111,99,0,108,114,101,115,101,116,0,123,114,101,116,117,114,110,40,95,110,98,105,110,100,46,99,97,108,108,98,97,99,107,83,105,103,110,97,116,117,114,101,76,105,115,116,91,36,48,93,46,97,112,112,108,121,40,116,104,105,115,44,97,114,103,117,109,101,110,116,115,41,41,59,125,0,95,110,98,105,110,100,95,110,101,119,0,17,0,10,0,17,17,17,0,0,0,0,5,0,0,0,0,0,0,9,0,0,0,0,11,0,0,0,0,0,0,0,0,17,0,15,10,17,17,17,3,10,7,0,1,19,9,11,11,0,0,9,6,11,0,0,11,0,6,17,0,0,0,17,17,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,17,0,10,10,17,17,17,0,10,0,0,2,0,9,11,0,0,0,9,0,11,0,0,11,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,12,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,12,0,0,0,0,9,12,0,0,0,0,0,12,0,0,12,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,14,0,0,0,0,0,0,0,0,0,0,0,13,0,0,0,4,13,0,0,0,0,9,14,0,0,0,0,0,14,0,0,14,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,0,0,0,0,0,15,0,0,0,0,15,0,0,0,0,9,16,0,0,0,0,0,16,0,0,16,0,0,18,0,0,0,18,18,18,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,18,0,0,0,18,18,18,0,0,0,0,0,0,9,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,11,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,10,0,0,0,0,9,11,0,0,0,0,0,11,0,0,11,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,12,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,12,0,0,0,0,9,12,0,0,0,0,0,12,0,0,12,0,0,45,43,32,32,32,48,88,48,120,0,40,110,117,108,108,41,0,45,48,88,43,48,88,32,48,88,45,48,120,43,48,120,32,48,120,0,105,110,102,0,73,78,70,0,110,97,110,0,78,65,78,0,48,49,50,51,52,53,54,55,56,57,65,66,67,68,69,70,46,0,84,33,34,25,13,1,2,3,17,75,28,12,16,4,11,29,18,30,39,104,110,111,112,113,98,32,5,6,15,19,20,21,26,8,22,7,40,36,23,24,9,10,14,27,31,37,35,131,130,125,38,42,43,60,61,62,63,67,71,74,77,88,89,90,91,92,93,94,95,96,97,99,100,101,102,103,105,106,107,108,114,115,116,121,122,123,124,0,73,108,108,101,103,97,108,32,98,121,116,101,32,115,101,113,117,101,110,99,101,0,68,111,109,97,105,110,32,101,114,114,111,114,0,82,101,115,117,108,116,32,110,111,116,32,114,101,112,114,101,115,101,110,116,97,98,108,101,0,78,111,116,32,97,32,116,116,121,0,80,101,114,109,105,115,115,105,111,110,32,100,101,110,105,101,100,0,79,112,101,114,97,116,105,111,110,32,110,111,116,32,112,101,114,109,105,116,116,101,100,0,78,111,32,115,117,99,104,32,102,105,108,101,32,111,114,32,100,105,114,101,99,116,111,114,121,0,78,111,32,115,117,99,104,32,112,114,111,99,101,115,115,0,70,105,108,101,32,101,120,105,115,116,115,0,86,97,108,117,101,32,116,111,111,32,108,97,114,103,101,32,102,111,114,32,100,97,116,97,32,116,121,112,101,0,78,111,32,115,112,97,99,101,32,108,101,102,116,32,111,110,32,100,101,118,105,99,101,0,79,117,116,32,111,102,32,109,101,109,111,114,121,0,82,101,115,111,117,114,99,101,32,98,117,115,121,0,73,110,116,101,114,114,117,112,116,101,100,32,115,121,115,116,101,109,32,99,97,108,108,0,82,101,115,111,117,114,99,101,32,116,101,109,112,111,114,97,114,105,108,121,32,117,110,97,118,97,105,108,97,98,108,101,0,73,110,118,97,108,105,100,32,115,101,101,107,0,67,114,111,115,115,45,100,101,118,105,99,101,32,108,105,110,107,0,82,101,97,100,45,111,110,108,121,32,102,105,108,101,32,115,121,115,116,101,109,0,68,105,114,101,99,116,111,114,121,32,110,111,116,32,101,109,112,116,121,0,67,111,110,110,101,99,116,105,111,110,32,114,101,115,101,116,32,98,121,32,112,101,101,114,0,79,112,101,114,97,116,105,111,110,32,116,105,109,101,100,32,111,117,116,0,67,111,110,110,101,99,116,105,111,110,32,114,101,102,117,115,101,100,0,72,111,115,116,32,105,115,32,100,111,119,110,0,72,111,115,116,32,105,115,32,117,110,114,101,97,99,104,97,98,108,101,0,65,100,100,114,101,115,115,32,105,110,32,117,115,101,0,66,114,111,107,101,110,32,112,105,112,101,0,73,47,79,32,101,114,114,111,114,0,78,111,32,115,117,99,104,32,100,101,118,105,99,101,32,111,114,32,97,100,100,114,101,115,115,0,66,108,111,99,107,32,100,101,118,105,99,101,32,114,101,113,117,105,114,101,100,0,78,111,32,115,117,99,104,32,100,101,118,105,99,101,0,78,111,116,32,97,32,100,105,114,101,99,116,111,114,121,0,73,115,32,97,32,100,105,114,101,99,116,111,114,121,0,84,101,120,116,32,102,105,108,101,32,98,117,115,121,0,69,120,101,99,32,102,111,114,109,97,116,32,101,114,114,111,114,0,73,110,118,97,108,105,100,32,97,114,103,117,109,101,110,116,0,65,114,103,117,109,101,110,116,32,108,105,115,116,32,116,111,111,32,108,111,110,103,0,83,121,109,98,111,108,105,99,32,108,105,110,107,32,108,111,111,112,0,70,105,108,101,110,97,109,101,32,116,111,111,32,108,111,110,103,0,84,111,111,32,109,97,110,121,32,111,112,101,110,32,102,105,108,101,115,32,105,110,32,115,121,115,116,101,109,0,78,111,32,102,105,108,101,32,100,101,115,99,114,105,112,116,111,114,115,32,97,118,97,105,108,97,98,108,101,0,66,97,100,32,102,105,108,101,32,100,101,115,99,114,105,112,116,111,114,0,78,111,32,99,104,105,108,100,32,112,114,111,99,101,115,115,0,66,97,100,32,97,100,100,114,101,115,115,0,70,105,108,101,32,116,111,111,32,108,97,114,103,101,0,84,111,111,32,109,97,110,121,32,108,105,110,107,115,0,78,111,32,108,111,99,107,115,32,97,118,97,105,108,97,98,108,101,0,82,101,115,111,117,114,99,101,32,100,101,97,100,108,111,99,107,32,119,111,117,108,100,32,111,99,99,117,114,0,83,116,97,116,101,32,110,111,116,32,114,101,99,111,118,101,114,97,98,108,101,0,80,114,101,118,105,111,117,115,32,111,119,110,101,114,32,100,105,101,100,0,79,112,101,114,97,116,105,111,110,32,99,97,110,99,101,108,101,100,0,70,117,110,99,116,105,111,110,32,110,111,116,32,105,109,112,108,101,109,101,110,116,101,100,0,78,111,32,109,101,115,115,97,103,101,32,111,102,32,100,101,115,105,114,101,100,32,116,121,112,101,0,73,100,101,110,116,105,102,105,101,114,32,114,101,109,111,118,101,100,0,68,101,118,105,99,101,32,110,111,116,32,97,32,115,116,114,101,97,109,0,78,111,32,100,97,116,97,32,97,118,97,105,108,97,98,108,101,0,68,101,118,105,99,101,32,116,105,109,101,111,117,116,0,79,117,116,32,111,102,32,115,116,114,101,97,109,115,32,114,101,115,111,117,114,99,101,115,0,76,105,110,107,32,104,97,115,32,98,101,101,110,32,115,101,118,101,114,101,100,0,80,114,111,116,111,99,111,108,32,101,114,114,111,114,0,66,97,100,32,109,101,115,115,97,103,101,0,70,105,108,101,32,100,101,115,99,114,105,112,116,111,114,32,105,110,32,98,97,100,32,115,116,97,116,101,0,78,111,116,32,97,32,115,111,99,107,101,116,0,68,101,115,116,105,110,97,116,105,111,110,32,97,100,100,114,101,115,115,32,114,101,113,117,105,114,101,100,0,77,101,115,115,97,103,101,32,116,111,111,32,108,97,114,103,101,0,80,114,111,116,111,99,111,108,32,119,114,111,110,103,32,116,121,112,101,32,102,111,114,32,115,111,99,107,101,116,0,80,114,111,116,111,99,111,108,32,110,111,116,32,97,118,97,105,108,97,98,108,101,0,80,114,111,116,111,99,111,108,32,110,111,116,32,115,117,112,112,111,114,116,101,100,0,83,111,99,107,101,116,32,116,121,112,101,32,110,111,116,32,115,117,112,112,111,114,116,101,100,0,78,111,116,32,115,117,112,112,111,114,116,101,100,0,80,114,111,116,111,99,111,108,32,102,97,109,105,108,121,32,110,111,116,32,115,117,112,112,111,114,116,101,100,0,65,100,100,114,101,115,115,32,102,97,109,105,108,121,32,110,111,116,32,115,117,112,112,111,114,116,101,100,32,98,121,32,112,114,111,116,111,99,111,108,0,65,100,100,114,101,115,115,32,110,111,116,32,97,118,97,105,108,97,98,108,101,0,78,101,116,119,111,114,107,32,105,115,32,100,111,119,110,0,78,101,116,119,111,114,107,32,117,110,114,101,97,99,104,97,98,108,101,0,67,111,110,110,101,99,116,105,111,110,32,114,101,115,101,116,32,98,121,32,110,101,116,119,111,114,107,0,67,111,110,110,101,99,116,105,111,110,32,97,98,111,114,116,101,100,0,78,111,32,98,117,102,102,101,114,32,115,112,97,99,101,32,97,118,97,105,108,97,98,108,101,0,83,111,99,107,101,116,32,105,115,32,99,111,110,110,101,99,116,101,100,0,83,111,99,107,101,116,32,110,111,116,32,99,111,110,110,101,99,116,101,100,0,67,97,110,110,111,116,32,115,101,110,100,32,97,102,116,101,114,32,115,111,99,107,101,116,32,115,104,117,116,100,111,119,110,0,79,112,101,114,97,116,105,111,110,32,97,108,114,101,97,100,121,32,105,110,32,112,114,111,103,114,101,115,115,0,79,112,101,114,97,116,105,111,110,32,105,110,32,112,114,111,103,114,101,115,115,0,83,116,97,108,101,32,102,105,108,101,32,104,97,110,100,108,101,0,82,101,109,111,116,101,32,73,47,79,32,101,114,114,111,114,0,81,117,111,116,97,32,101,120,99,101,101,100,101,100,0,78,111,32,109,101,100,105,117,109,32,102,111,117,110,100,0,87,114,111,110,103,32,109,101,100,105,117,109,32,116,121,112,101,0,78,111,32,101,114,114,111,114,32,105,110,102,111,114,109,97,116,105,111,110,0,0],"i8",ALLOC_NONE,Runtime.GLOBAL_BASE);var tempDoublePtr=STATICTOP;STATICTOP+=16;function _atexit(t,e){__ATEXIT__.unshift({func:t,arg:e})}function ___cxa_atexit(){return _atexit.apply(null,arguments)}function _abort(){Module.abort()}function __ZN8facebook4yoga14YGNodeToStringEPNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP6YGNode14YGPrintOptionsj(){Module.printErr("missing function: _ZN8facebook4yoga14YGNodeToStringEPNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP6YGNode14YGPrintOptionsj"),abort(-1)}function __decorate(t,e,r,s){var a=arguments.length,n=a<3?e:s===null?s=Object.getOwnPropertyDescriptor(e,r):s,c;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")n=Reflect.decorate(t,e,r,s);else for(var f=t.length-1;f>=0;f--)(c=t[f])&&(n=(a<3?c(n):a>3?c(e,r,n):c(e,r))||n);return a>3&&n&&Object.defineProperty(e,r,n),n}function _defineHidden(t){return function(e,r){Object.defineProperty(e,r,{configurable:!1,enumerable:!1,value:t,writable:!0})}}var _nbind={};function __nbind_free_external(t){_nbind.externalList[t].dereference(t)}function __nbind_reference_external(t){_nbind.externalList[t].reference()}function _llvm_stackrestore(t){var e=_llvm_stacksave,r=e.LLVM_SAVEDSTACKS[t];e.LLVM_SAVEDSTACKS.splice(t,1),Runtime.stackRestore(r)}function __nbind_register_pool(t,e,r,s){_nbind.Pool.pageSize=t,_nbind.Pool.usedPtr=e/4,_nbind.Pool.rootPtr=r,_nbind.Pool.pagePtr=s/4,HEAP32[e/4]=16909060,HEAP8[e]==1&&(_nbind.bigEndian=!0),HEAP32[e/4]=0,_nbind.makeTypeKindTbl=(n={},n[1024]=_nbind.PrimitiveType,n[64]=_nbind.Int64Type,n[2048]=_nbind.BindClass,n[3072]=_nbind.BindClassPtr,n[4096]=_nbind.SharedClassPtr,n[5120]=_nbind.ArrayType,n[6144]=_nbind.ArrayType,n[7168]=_nbind.CStringType,n[9216]=_nbind.CallbackType,n[10240]=_nbind.BindType,n),_nbind.makeTypeNameTbl={Buffer:_nbind.BufferType,External:_nbind.ExternalType,Int64:_nbind.Int64Type,_nbind_new:_nbind.CreateValueType,bool:_nbind.BooleanType,"cbFunction &":_nbind.CallbackType,"const cbFunction &":_nbind.CallbackType,"const std::string &":_nbind.StringType,"std::string":_nbind.StringType},Module.toggleLightGC=_nbind.toggleLightGC,_nbind.callUpcast=Module.dynCall_ii;var a=_nbind.makeType(_nbind.constructType,{flags:2048,id:0,name:""});a.proto=Module,_nbind.BindClass.list.push(a);var n}function _emscripten_set_main_loop_timing(t,e){if(Browser.mainLoop.timingMode=t,Browser.mainLoop.timingValue=e,!Browser.mainLoop.func)return 1;if(t==0)Browser.mainLoop.scheduler=function(){var c=Math.max(0,Browser.mainLoop.tickStartTime+e-_emscripten_get_now())|0;setTimeout(Browser.mainLoop.runner,c)},Browser.mainLoop.method="timeout";else if(t==1)Browser.mainLoop.scheduler=function(){Browser.requestAnimationFrame(Browser.mainLoop.runner)},Browser.mainLoop.method="rAF";else if(t==2){if(!window.setImmediate){let n=function(c){c.source===window&&c.data===s&&(c.stopPropagation(),r.shift()())};var a=n,r=[],s="setimmediate";window.addEventListener("message",n,!0),window.setImmediate=function(f){r.push(f),ENVIRONMENT_IS_WORKER?(Module.setImmediates===void 0&&(Module.setImmediates=[]),Module.setImmediates.push(f),window.postMessage({target:s})):window.postMessage(s,"*")}}Browser.mainLoop.scheduler=function(){window.setImmediate(Browser.mainLoop.runner)},Browser.mainLoop.method="immediate"}return 0}function _emscripten_get_now(){abort()}function _emscripten_set_main_loop(t,e,r,s,a){Module.noExitRuntime=!0,assert(!Browser.mainLoop.func,"emscripten_set_main_loop: there can only be one main loop function at once: call emscripten_cancel_main_loop to cancel the previous one before setting a new one with different parameters."),Browser.mainLoop.func=t,Browser.mainLoop.arg=s;var n;typeof s<"u"?n=function(){Module.dynCall_vi(t,s)}:n=function(){Module.dynCall_v(t)};var c=Browser.mainLoop.currentlyRunningMainloop;if(Browser.mainLoop.runner=function(){if(!ABORT){if(Browser.mainLoop.queue.length>0){var p=Date.now(),h=Browser.mainLoop.queue.shift();if(h.func(h.arg),Browser.mainLoop.remainingBlockers){var E=Browser.mainLoop.remainingBlockers,C=E%1==0?E-1:Math.floor(E);h.counted?Browser.mainLoop.remainingBlockers=C:(C=C+.5,Browser.mainLoop.remainingBlockers=(8*E+C)/9)}if(console.log('main loop blocker "'+h.name+'" took '+(Date.now()-p)+" ms"),Browser.mainLoop.updateStatus(),c1&&Browser.mainLoop.currentFrameNumber%Browser.mainLoop.timingValue!=0){Browser.mainLoop.scheduler();return}else Browser.mainLoop.timingMode==0&&(Browser.mainLoop.tickStartTime=_emscripten_get_now());Browser.mainLoop.method==="timeout"&&Module.ctx&&(Module.printErr("Looks like you are rendering without using requestAnimationFrame for the main loop. You should use 0 for the frame rate in emscripten_set_main_loop in order to use requestAnimationFrame, as that can greatly improve your frame rates!"),Browser.mainLoop.method=""),Browser.mainLoop.runIter(n),!(c0?_emscripten_set_main_loop_timing(0,1e3/e):_emscripten_set_main_loop_timing(1,1),Browser.mainLoop.scheduler()),r)throw"SimulateInfiniteLoop"}var Browser={mainLoop:{scheduler:null,method:"",currentlyRunningMainloop:0,func:null,arg:0,timingMode:0,timingValue:0,currentFrameNumber:0,queue:[],pause:function(){Browser.mainLoop.scheduler=null,Browser.mainLoop.currentlyRunningMainloop++},resume:function(){Browser.mainLoop.currentlyRunningMainloop++;var t=Browser.mainLoop.timingMode,e=Browser.mainLoop.timingValue,r=Browser.mainLoop.func;Browser.mainLoop.func=null,_emscripten_set_main_loop(r,0,!1,Browser.mainLoop.arg,!0),_emscripten_set_main_loop_timing(t,e),Browser.mainLoop.scheduler()},updateStatus:function(){if(Module.setStatus){var t=Module.statusMessage||"Please wait...",e=Browser.mainLoop.remainingBlockers,r=Browser.mainLoop.expectedBlockers;e?e"u"&&(console.log("warning: Browser does not support creating object URLs. Built-in browser image decoding will not be available."),Module.noImageDecoding=!0);var t={};t.canHandle=function(n){return!Module.noImageDecoding&&/\.(jpg|jpeg|png|bmp)$/i.test(n)},t.handle=function(n,c,f,p){var h=null;if(Browser.hasBlobConstructor)try{h=new Blob([n],{type:Browser.getMimetype(c)}),h.size!==n.length&&(h=new Blob([new Uint8Array(n).buffer],{type:Browser.getMimetype(c)}))}catch(P){Runtime.warnOnce("Blob constructor present but fails: "+P+"; falling back to blob builder")}if(!h){var E=new Browser.BlobBuilder;E.append(new Uint8Array(n).buffer),h=E.getBlob()}var C=Browser.URLObject.createObjectURL(h),S=new Image;S.onload=function(){assert(S.complete,"Image "+c+" could not be decoded");var I=document.createElement("canvas");I.width=S.width,I.height=S.height;var R=I.getContext("2d");R.drawImage(S,0,0),Module.preloadedImages[c]=I,Browser.URLObject.revokeObjectURL(C),f&&f(n)},S.onerror=function(I){console.log("Image "+C+" could not be decoded"),p&&p()},S.src=C},Module.preloadPlugins.push(t);var e={};e.canHandle=function(n){return!Module.noAudioDecoding&&n.substr(-4)in{".ogg":1,".wav":1,".mp3":1}},e.handle=function(n,c,f,p){var h=!1;function E(R){h||(h=!0,Module.preloadedAudios[c]=R,f&&f(n))}function C(){h||(h=!0,Module.preloadedAudios[c]=new Audio,p&&p())}if(Browser.hasBlobConstructor){try{var S=new Blob([n],{type:Browser.getMimetype(c)})}catch{return C()}var P=Browser.URLObject.createObjectURL(S),I=new Audio;I.addEventListener("canplaythrough",function(){E(I)},!1),I.onerror=function(N){if(h)return;console.log("warning: browser could not fully decode audio "+c+", trying slower base64 approach");function U(W){for(var ee="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",ie="=",ue="",le=0,me=0,pe=0;pe=6;){var Be=le>>me-6&63;me-=6,ue+=ee[Be]}return me==2?(ue+=ee[(le&3)<<4],ue+=ie+ie):me==4&&(ue+=ee[(le&15)<<2],ue+=ie),ue}I.src="data:audio/x-"+c.substr(-3)+";base64,"+U(n),E(I)},I.src=P,Browser.safeSetTimeout(function(){E(I)},1e4)}else return C()},Module.preloadPlugins.push(e);function r(){Browser.pointerLock=document.pointerLockElement===Module.canvas||document.mozPointerLockElement===Module.canvas||document.webkitPointerLockElement===Module.canvas||document.msPointerLockElement===Module.canvas}var s=Module.canvas;s&&(s.requestPointerLock=s.requestPointerLock||s.mozRequestPointerLock||s.webkitRequestPointerLock||s.msRequestPointerLock||function(){},s.exitPointerLock=document.exitPointerLock||document.mozExitPointerLock||document.webkitExitPointerLock||document.msExitPointerLock||function(){},s.exitPointerLock=s.exitPointerLock.bind(document),document.addEventListener("pointerlockchange",r,!1),document.addEventListener("mozpointerlockchange",r,!1),document.addEventListener("webkitpointerlockchange",r,!1),document.addEventListener("mspointerlockchange",r,!1),Module.elementPointerLock&&s.addEventListener("click",function(a){!Browser.pointerLock&&Module.canvas.requestPointerLock&&(Module.canvas.requestPointerLock(),a.preventDefault())},!1))},createContext:function(t,e,r,s){if(e&&Module.ctx&&t==Module.canvas)return Module.ctx;var a,n;if(e){var c={antialias:!1,alpha:!1};if(s)for(var f in s)c[f]=s[f];n=GL.createContext(t,c),n&&(a=GL.getContext(n).GLctx)}else a=t.getContext("2d");return a?(r&&(e||assert(typeof GLctx>"u","cannot set in module if GLctx is used, but we are a non-GL context that would replace it"),Module.ctx=a,e&&GL.makeContextCurrent(n),Module.useWebGL=e,Browser.moduleContextCreatedCallbacks.forEach(function(p){p()}),Browser.init()),a):null},destroyContext:function(t,e,r){},fullscreenHandlersInstalled:!1,lockPointer:void 0,resizeCanvas:void 0,requestFullscreen:function(t,e,r){Browser.lockPointer=t,Browser.resizeCanvas=e,Browser.vrDevice=r,typeof Browser.lockPointer>"u"&&(Browser.lockPointer=!0),typeof Browser.resizeCanvas>"u"&&(Browser.resizeCanvas=!1),typeof Browser.vrDevice>"u"&&(Browser.vrDevice=null);var s=Module.canvas;function a(){Browser.isFullscreen=!1;var c=s.parentNode;(document.fullscreenElement||document.mozFullScreenElement||document.msFullscreenElement||document.webkitFullscreenElement||document.webkitCurrentFullScreenElement)===c?(s.exitFullscreen=document.exitFullscreen||document.cancelFullScreen||document.mozCancelFullScreen||document.msExitFullscreen||document.webkitCancelFullScreen||function(){},s.exitFullscreen=s.exitFullscreen.bind(document),Browser.lockPointer&&s.requestPointerLock(),Browser.isFullscreen=!0,Browser.resizeCanvas&&Browser.setFullscreenCanvasSize()):(c.parentNode.insertBefore(s,c),c.parentNode.removeChild(c),Browser.resizeCanvas&&Browser.setWindowedCanvasSize()),Module.onFullScreen&&Module.onFullScreen(Browser.isFullscreen),Module.onFullscreen&&Module.onFullscreen(Browser.isFullscreen),Browser.updateCanvasDimensions(s)}Browser.fullscreenHandlersInstalled||(Browser.fullscreenHandlersInstalled=!0,document.addEventListener("fullscreenchange",a,!1),document.addEventListener("mozfullscreenchange",a,!1),document.addEventListener("webkitfullscreenchange",a,!1),document.addEventListener("MSFullscreenChange",a,!1));var n=document.createElement("div");s.parentNode.insertBefore(n,s),n.appendChild(s),n.requestFullscreen=n.requestFullscreen||n.mozRequestFullScreen||n.msRequestFullscreen||(n.webkitRequestFullscreen?function(){n.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT)}:null)||(n.webkitRequestFullScreen?function(){n.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT)}:null),r?n.requestFullscreen({vrDisplay:r}):n.requestFullscreen()},requestFullScreen:function(t,e,r){return Module.printErr("Browser.requestFullScreen() is deprecated. Please call Browser.requestFullscreen instead."),Browser.requestFullScreen=function(s,a,n){return Browser.requestFullscreen(s,a,n)},Browser.requestFullscreen(t,e,r)},nextRAF:0,fakeRequestAnimationFrame:function(t){var e=Date.now();if(Browser.nextRAF===0)Browser.nextRAF=e+1e3/60;else for(;e+2>=Browser.nextRAF;)Browser.nextRAF+=1e3/60;var r=Math.max(Browser.nextRAF-e,0);setTimeout(t,r)},requestAnimationFrame:function t(e){typeof window>"u"?Browser.fakeRequestAnimationFrame(e):(window.requestAnimationFrame||(window.requestAnimationFrame=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame||window.oRequestAnimationFrame||Browser.fakeRequestAnimationFrame),window.requestAnimationFrame(e))},safeCallback:function(t){return function(){if(!ABORT)return t.apply(null,arguments)}},allowAsyncCallbacks:!0,queuedAsyncCallbacks:[],pauseAsyncCallbacks:function(){Browser.allowAsyncCallbacks=!1},resumeAsyncCallbacks:function(){if(Browser.allowAsyncCallbacks=!0,Browser.queuedAsyncCallbacks.length>0){var t=Browser.queuedAsyncCallbacks;Browser.queuedAsyncCallbacks=[],t.forEach(function(e){e()})}},safeRequestAnimationFrame:function(t){return Browser.requestAnimationFrame(function(){ABORT||(Browser.allowAsyncCallbacks?t():Browser.queuedAsyncCallbacks.push(t))})},safeSetTimeout:function(t,e){return Module.noExitRuntime=!0,setTimeout(function(){ABORT||(Browser.allowAsyncCallbacks?t():Browser.queuedAsyncCallbacks.push(t))},e)},safeSetInterval:function(t,e){return Module.noExitRuntime=!0,setInterval(function(){ABORT||Browser.allowAsyncCallbacks&&t()},e)},getMimetype:function(t){return{jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",bmp:"image/bmp",ogg:"audio/ogg",wav:"audio/wav",mp3:"audio/mpeg"}[t.substr(t.lastIndexOf(".")+1)]},getUserMedia:function(t){window.getUserMedia||(window.getUserMedia=navigator.getUserMedia||navigator.mozGetUserMedia),window.getUserMedia(t)},getMovementX:function(t){return t.movementX||t.mozMovementX||t.webkitMovementX||0},getMovementY:function(t){return t.movementY||t.mozMovementY||t.webkitMovementY||0},getMouseWheelDelta:function(t){var e=0;switch(t.type){case"DOMMouseScroll":e=t.detail;break;case"mousewheel":e=t.wheelDelta;break;case"wheel":e=t.deltaY;break;default:throw"unrecognized mouse wheel event: "+t.type}return e},mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,touches:{},lastTouches:{},calculateMouseEvent:function(t){if(Browser.pointerLock)t.type!="mousemove"&&"mozMovementX"in t?Browser.mouseMovementX=Browser.mouseMovementY=0:(Browser.mouseMovementX=Browser.getMovementX(t),Browser.mouseMovementY=Browser.getMovementY(t)),typeof SDL<"u"?(Browser.mouseX=SDL.mouseX+Browser.mouseMovementX,Browser.mouseY=SDL.mouseY+Browser.mouseMovementY):(Browser.mouseX+=Browser.mouseMovementX,Browser.mouseY+=Browser.mouseMovementY);else{var e=Module.canvas.getBoundingClientRect(),r=Module.canvas.width,s=Module.canvas.height,a=typeof window.scrollX<"u"?window.scrollX:window.pageXOffset,n=typeof window.scrollY<"u"?window.scrollY:window.pageYOffset;if(t.type==="touchstart"||t.type==="touchend"||t.type==="touchmove"){var c=t.touch;if(c===void 0)return;var f=c.pageX-(a+e.left),p=c.pageY-(n+e.top);f=f*(r/e.width),p=p*(s/e.height);var h={x:f,y:p};if(t.type==="touchstart")Browser.lastTouches[c.identifier]=h,Browser.touches[c.identifier]=h;else if(t.type==="touchend"||t.type==="touchmove"){var E=Browser.touches[c.identifier];E||(E=h),Browser.lastTouches[c.identifier]=E,Browser.touches[c.identifier]=h}return}var C=t.pageX-(a+e.left),S=t.pageY-(n+e.top);C=C*(r/e.width),S=S*(s/e.height),Browser.mouseMovementX=C-Browser.mouseX,Browser.mouseMovementY=S-Browser.mouseY,Browser.mouseX=C,Browser.mouseY=S}},asyncLoad:function(t,e,r,s){var a=s?"":"al "+t;Module.readAsync(t,function(n){assert(n,'Loading data file "'+t+'" failed (no arrayBuffer).'),e(new Uint8Array(n)),a&&removeRunDependency(a)},function(n){if(r)r();else throw'Loading data file "'+t+'" failed.'}),a&&addRunDependency(a)},resizeListeners:[],updateResizeListeners:function(){var t=Module.canvas;Browser.resizeListeners.forEach(function(e){e(t.width,t.height)})},setCanvasSize:function(t,e,r){var s=Module.canvas;Browser.updateCanvasDimensions(s,t,e),r||Browser.updateResizeListeners()},windowedWidth:0,windowedHeight:0,setFullscreenCanvasSize:function(){if(typeof SDL<"u"){var t=HEAPU32[SDL.screen+Runtime.QUANTUM_SIZE*0>>2];t=t|8388608,HEAP32[SDL.screen+Runtime.QUANTUM_SIZE*0>>2]=t}Browser.updateResizeListeners()},setWindowedCanvasSize:function(){if(typeof SDL<"u"){var t=HEAPU32[SDL.screen+Runtime.QUANTUM_SIZE*0>>2];t=t&-8388609,HEAP32[SDL.screen+Runtime.QUANTUM_SIZE*0>>2]=t}Browser.updateResizeListeners()},updateCanvasDimensions:function(t,e,r){e&&r?(t.widthNative=e,t.heightNative=r):(e=t.widthNative,r=t.heightNative);var s=e,a=r;if(Module.forcedAspectRatio&&Module.forcedAspectRatio>0&&(s/a>2];return e},getStr:function(){var t=Pointer_stringify(SYSCALLS.get());return t},get64:function(){var t=SYSCALLS.get(),e=SYSCALLS.get();return t>=0?assert(e===0):assert(e===-1),t},getZero:function(){assert(SYSCALLS.get()===0)}};function ___syscall6(t,e){SYSCALLS.varargs=e;try{var r=SYSCALLS.getStreamFromFD();return FS.close(r),0}catch(s){return(typeof FS>"u"||!(s instanceof FS.ErrnoError))&&abort(s),-s.errno}}function ___syscall54(t,e){SYSCALLS.varargs=e;try{return 0}catch(r){return(typeof FS>"u"||!(r instanceof FS.ErrnoError))&&abort(r),-r.errno}}function _typeModule(t){var e=[[0,1,"X"],[1,1,"const X"],[128,1,"X *"],[256,1,"X &"],[384,1,"X &&"],[512,1,"std::shared_ptr"],[640,1,"std::unique_ptr"],[5120,1,"std::vector"],[6144,2,"std::array"],[9216,-1,"std::function"]];function r(p,h,E,C,S,P){if(h==1){var I=C&896;(I==128||I==256||I==384)&&(p="X const")}var R;return P?R=E.replace("X",p).replace("Y",S):R=p.replace("X",E).replace("Y",S),R.replace(/([*&]) (?=[*&])/g,"$1")}function s(p,h,E,C,S){throw new Error(p+" type "+E.replace("X",h+"?")+(C?" with flag "+C:"")+" in "+S)}function a(p,h,E,C,S,P,I,R){P===void 0&&(P="X"),R===void 0&&(R=1);var N=E(p);if(N)return N;var U=C(p),W=U.placeholderFlag,ee=e[W];I&&ee&&(P=r(I[2],I[0],P,ee[0],"?",!0));var ie;W==0&&(ie="Unbound"),W>=10&&(ie="Corrupt"),R>20&&(ie="Deeply nested"),ie&&s(ie,p,P,W,S||"?");var ue=U.paramList[0],le=a(ue,h,E,C,S,P,ee,R+1),me,pe={flags:ee[0],id:p,name:"",paramList:[le]},Be=[],Ce="?";switch(U.placeholderFlag){case 1:me=le.spec;break;case 2:if((le.flags&15360)==1024&&le.spec.ptrSize==1){pe.flags=7168;break}case 3:case 6:case 5:me=le.spec,le.flags&15360;break;case 8:Ce=""+U.paramList[1],pe.paramList.push(U.paramList[1]);break;case 9:for(var g=0,we=U.paramList[1];g>2]=t),t}function _llvm_stacksave(){var t=_llvm_stacksave;return t.LLVM_SAVEDSTACKS||(t.LLVM_SAVEDSTACKS=[]),t.LLVM_SAVEDSTACKS.push(Runtime.stackSave()),t.LLVM_SAVEDSTACKS.length-1}function ___syscall140(t,e){SYSCALLS.varargs=e;try{var r=SYSCALLS.getStreamFromFD(),s=SYSCALLS.get(),a=SYSCALLS.get(),n=SYSCALLS.get(),c=SYSCALLS.get(),f=a;return FS.llseek(r,f,c),HEAP32[n>>2]=r.position,r.getdents&&f===0&&c===0&&(r.getdents=null),0}catch(p){return(typeof FS>"u"||!(p instanceof FS.ErrnoError))&&abort(p),-p.errno}}function ___syscall146(t,e){SYSCALLS.varargs=e;try{var r=SYSCALLS.get(),s=SYSCALLS.get(),a=SYSCALLS.get(),n=0;___syscall146.buffer||(___syscall146.buffers=[null,[],[]],___syscall146.printChar=function(E,C){var S=___syscall146.buffers[E];assert(S),C===0||C===10?((E===1?Module.print:Module.printErr)(UTF8ArrayToString(S,0)),S.length=0):S.push(C)});for(var c=0;c>2],p=HEAP32[s+(c*8+4)>>2],h=0;h"u"||!(E instanceof FS.ErrnoError))&&abort(E),-E.errno}}function __nbind_finish(){for(var t=0,e=_nbind.BindClass.list;tt.pageSize/2||e>t.pageSize-r){var s=_nbind.typeNameTbl.NBind.proto;return s.lalloc(e)}else return HEAPU32[t.usedPtr]=r+e,t.rootPtr+r},t.lreset=function(e,r){var s=HEAPU32[t.pagePtr];if(s){var a=_nbind.typeNameTbl.NBind.proto;a.lreset(e,r)}else HEAPU32[t.usedPtr]=e},t}();_nbind.Pool=Pool;function constructType(t,e){var r=t==10240?_nbind.makeTypeNameTbl[e.name]||_nbind.BindType:_nbind.makeTypeKindTbl[t],s=new r(e);return typeIdTbl[e.id]=s,_nbind.typeNameTbl[e.name]=s,s}_nbind.constructType=constructType;function getType(t){return typeIdTbl[t]}_nbind.getType=getType;function queryType(t){var e=HEAPU8[t],r=_nbind.structureList[e][1];t/=4,r<0&&(++t,r=HEAPU32[t]+1);var s=Array.prototype.slice.call(HEAPU32.subarray(t+1,t+1+r));return e==9&&(s=[s[0],s.slice(1)]),{paramList:s,placeholderFlag:e}}_nbind.queryType=queryType;function getTypes(t,e){return t.map(function(r){return typeof r=="number"?_nbind.getComplexType(r,constructType,getType,queryType,e):_nbind.typeNameTbl[r]})}_nbind.getTypes=getTypes;function readTypeIdList(t,e){return Array.prototype.slice.call(HEAPU32,t/4,t/4+e)}_nbind.readTypeIdList=readTypeIdList;function readAsciiString(t){for(var e=t;HEAPU8[e++];);return String.fromCharCode.apply("",HEAPU8.subarray(t,e-1))}_nbind.readAsciiString=readAsciiString;function readPolicyList(t){var e={};if(t)for(;;){var r=HEAPU32[t/4];if(!r)break;e[readAsciiString(r)]=!0,t+=4}return e}_nbind.readPolicyList=readPolicyList;function getDynCall(t,e){var r={float32_t:"d",float64_t:"d",int64_t:"d",uint64_t:"d",void:"v"},s=t.map(function(n){return r[n.name]||"i"}).join(""),a=Module["dynCall_"+s];if(!a)throw new Error("dynCall_"+s+" not found for "+e+"("+t.map(function(n){return n.name}).join(", ")+")");return a}_nbind.getDynCall=getDynCall;function addMethod(t,e,r,s){var a=t[e];t.hasOwnProperty(e)&&a?((a.arity||a.arity===0)&&(a=_nbind.makeOverloader(a,a.arity),t[e]=a),a.addMethod(r,s)):(r.arity=s,t[e]=r)}_nbind.addMethod=addMethod;function throwError(t){throw new Error(t)}_nbind.throwError=throwError,_nbind.bigEndian=!1,_a=_typeModule(_typeModule),_nbind.Type=_a.Type,_nbind.makeType=_a.makeType,_nbind.getComplexType=_a.getComplexType,_nbind.structureList=_a.structureList;var BindType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.heap=HEAPU32,r.ptrSize=4,r}return e.prototype.needsWireRead=function(r){return!!this.wireRead||!!this.makeWireRead},e.prototype.needsWireWrite=function(r){return!!this.wireWrite||!!this.makeWireWrite},e}(_nbind.Type);_nbind.BindType=BindType;var PrimitiveType=function(t){__extends(e,t);function e(r){var s=t.call(this,r)||this,a=r.flags&32?{32:HEAPF32,64:HEAPF64}:r.flags&8?{8:HEAPU8,16:HEAPU16,32:HEAPU32}:{8:HEAP8,16:HEAP16,32:HEAP32};return s.heap=a[r.ptrSize*8],s.ptrSize=r.ptrSize,s}return e.prototype.needsWireWrite=function(r){return!!r&&!!r.Strict},e.prototype.makeWireWrite=function(r,s){return s&&s.Strict&&function(a){if(typeof a=="number")return a;throw new Error("Type mismatch")}},e}(BindType);_nbind.PrimitiveType=PrimitiveType;function pushCString(t,e){if(t==null){if(e&&e.Nullable)return 0;throw new Error("Type mismatch")}if(e&&e.Strict){if(typeof t!="string")throw new Error("Type mismatch")}else t=t.toString();var r=Module.lengthBytesUTF8(t)+1,s=_nbind.Pool.lalloc(r);return Module.stringToUTF8Array(t,HEAPU8,s,r),s}_nbind.pushCString=pushCString;function popCString(t){return t===0?null:Module.Pointer_stringify(t)}_nbind.popCString=popCString;var CStringType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.wireRead=popCString,r.wireWrite=pushCString,r.readResources=[_nbind.resources.pool],r.writeResources=[_nbind.resources.pool],r}return e.prototype.makeWireWrite=function(r,s){return function(a){return pushCString(a,s)}},e}(BindType);_nbind.CStringType=CStringType;var BooleanType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.wireRead=function(s){return!!s},r}return e.prototype.needsWireWrite=function(r){return!!r&&!!r.Strict},e.prototype.makeWireRead=function(r){return"!!("+r+")"},e.prototype.makeWireWrite=function(r,s){return s&&s.Strict&&function(a){if(typeof a=="boolean")return a;throw new Error("Type mismatch")}||r},e}(BindType);_nbind.BooleanType=BooleanType;var Wrapper=function(){function t(){}return t.prototype.persist=function(){this.__nbindState|=1},t}();_nbind.Wrapper=Wrapper;function makeBound(t,e){var r=function(s){__extends(a,s);function a(n,c,f,p){var h=s.call(this)||this;if(!(h instanceof a))return new(Function.prototype.bind.apply(a,Array.prototype.concat.apply([null],arguments)));var E=c,C=f,S=p;if(n!==_nbind.ptrMarker){var P=h.__nbindConstructor.apply(h,arguments);E=4608,S=HEAPU32[P/4],C=HEAPU32[P/4+1]}var I={configurable:!0,enumerable:!1,value:null,writable:!1},R={__nbindFlags:E,__nbindPtr:C};S&&(R.__nbindShared=S,_nbind.mark(h));for(var N=0,U=Object.keys(R);N>=1;var r=_nbind.valueList[t];return _nbind.valueList[t]=firstFreeValue,firstFreeValue=t,r}else{if(e)return _nbind.popShared(t,e);throw new Error("Invalid value slot "+t)}}_nbind.popValue=popValue;var valueBase=18446744073709552e3;function push64(t){return typeof t=="number"?t:pushValue(t)*4096+valueBase}function pop64(t){return t=3?c=Buffer.from(n):c=new Buffer(n),c.copy(s)}else getBuffer(s).set(n)}}_nbind.commitBuffer=commitBuffer;var dirtyList=[],gcTimer=0;function sweep(){for(var t=0,e=dirtyList;t>2]=DYNAMIC_BASE,staticSealed=!0;function invoke_viiiii(t,e,r,s,a,n){try{Module.dynCall_viiiii(t,e,r,s,a,n)}catch(c){if(typeof c!="number"&&c!=="longjmp")throw c;Module.setThrew(1,0)}}function invoke_vif(t,e,r){try{Module.dynCall_vif(t,e,r)}catch(s){if(typeof s!="number"&&s!=="longjmp")throw s;Module.setThrew(1,0)}}function invoke_vid(t,e,r){try{Module.dynCall_vid(t,e,r)}catch(s){if(typeof s!="number"&&s!=="longjmp")throw s;Module.setThrew(1,0)}}function invoke_fiff(t,e,r,s){try{return Module.dynCall_fiff(t,e,r,s)}catch(a){if(typeof a!="number"&&a!=="longjmp")throw a;Module.setThrew(1,0)}}function invoke_vi(t,e){try{Module.dynCall_vi(t,e)}catch(r){if(typeof r!="number"&&r!=="longjmp")throw r;Module.setThrew(1,0)}}function invoke_vii(t,e,r){try{Module.dynCall_vii(t,e,r)}catch(s){if(typeof s!="number"&&s!=="longjmp")throw s;Module.setThrew(1,0)}}function invoke_ii(t,e){try{return Module.dynCall_ii(t,e)}catch(r){if(typeof r!="number"&&r!=="longjmp")throw r;Module.setThrew(1,0)}}function invoke_viddi(t,e,r,s,a){try{Module.dynCall_viddi(t,e,r,s,a)}catch(n){if(typeof n!="number"&&n!=="longjmp")throw n;Module.setThrew(1,0)}}function invoke_vidd(t,e,r,s){try{Module.dynCall_vidd(t,e,r,s)}catch(a){if(typeof a!="number"&&a!=="longjmp")throw a;Module.setThrew(1,0)}}function invoke_iiii(t,e,r,s){try{return Module.dynCall_iiii(t,e,r,s)}catch(a){if(typeof a!="number"&&a!=="longjmp")throw a;Module.setThrew(1,0)}}function invoke_diii(t,e,r,s){try{return Module.dynCall_diii(t,e,r,s)}catch(a){if(typeof a!="number"&&a!=="longjmp")throw a;Module.setThrew(1,0)}}function invoke_di(t,e){try{return Module.dynCall_di(t,e)}catch(r){if(typeof r!="number"&&r!=="longjmp")throw r;Module.setThrew(1,0)}}function invoke_iid(t,e,r){try{return Module.dynCall_iid(t,e,r)}catch(s){if(typeof s!="number"&&s!=="longjmp")throw s;Module.setThrew(1,0)}}function invoke_iii(t,e,r){try{return Module.dynCall_iii(t,e,r)}catch(s){if(typeof s!="number"&&s!=="longjmp")throw s;Module.setThrew(1,0)}}function invoke_viiddi(t,e,r,s,a,n){try{Module.dynCall_viiddi(t,e,r,s,a,n)}catch(c){if(typeof c!="number"&&c!=="longjmp")throw c;Module.setThrew(1,0)}}function invoke_viiiiii(t,e,r,s,a,n,c){try{Module.dynCall_viiiiii(t,e,r,s,a,n,c)}catch(f){if(typeof f!="number"&&f!=="longjmp")throw f;Module.setThrew(1,0)}}function invoke_dii(t,e,r){try{return Module.dynCall_dii(t,e,r)}catch(s){if(typeof s!="number"&&s!=="longjmp")throw s;Module.setThrew(1,0)}}function invoke_i(t){try{return Module.dynCall_i(t)}catch(e){if(typeof e!="number"&&e!=="longjmp")throw e;Module.setThrew(1,0)}}function invoke_iiiiii(t,e,r,s,a,n){try{return Module.dynCall_iiiiii(t,e,r,s,a,n)}catch(c){if(typeof c!="number"&&c!=="longjmp")throw c;Module.setThrew(1,0)}}function invoke_viiid(t,e,r,s,a){try{Module.dynCall_viiid(t,e,r,s,a)}catch(n){if(typeof n!="number"&&n!=="longjmp")throw n;Module.setThrew(1,0)}}function invoke_viififi(t,e,r,s,a,n,c){try{Module.dynCall_viififi(t,e,r,s,a,n,c)}catch(f){if(typeof f!="number"&&f!=="longjmp")throw f;Module.setThrew(1,0)}}function invoke_viii(t,e,r,s){try{Module.dynCall_viii(t,e,r,s)}catch(a){if(typeof a!="number"&&a!=="longjmp")throw a;Module.setThrew(1,0)}}function invoke_v(t){try{Module.dynCall_v(t)}catch(e){if(typeof e!="number"&&e!=="longjmp")throw e;Module.setThrew(1,0)}}function invoke_viid(t,e,r,s){try{Module.dynCall_viid(t,e,r,s)}catch(a){if(typeof a!="number"&&a!=="longjmp")throw a;Module.setThrew(1,0)}}function invoke_idd(t,e,r){try{return Module.dynCall_idd(t,e,r)}catch(s){if(typeof s!="number"&&s!=="longjmp")throw s;Module.setThrew(1,0)}}function invoke_viiii(t,e,r,s,a){try{Module.dynCall_viiii(t,e,r,s,a)}catch(n){if(typeof n!="number"&&n!=="longjmp")throw n;Module.setThrew(1,0)}}Module.asmGlobalArg={Math,Int8Array,Int16Array,Int32Array,Uint8Array,Uint16Array,Uint32Array,Float32Array,Float64Array,NaN:NaN,Infinity:1/0},Module.asmLibraryArg={abort,assert,enlargeMemory,getTotalMemory,abortOnCannotGrowMemory,invoke_viiiii,invoke_vif,invoke_vid,invoke_fiff,invoke_vi,invoke_vii,invoke_ii,invoke_viddi,invoke_vidd,invoke_iiii,invoke_diii,invoke_di,invoke_iid,invoke_iii,invoke_viiddi,invoke_viiiiii,invoke_dii,invoke_i,invoke_iiiiii,invoke_viiid,invoke_viififi,invoke_viii,invoke_v,invoke_viid,invoke_idd,invoke_viiii,_emscripten_asm_const_iiiii,_emscripten_asm_const_iiidddddd,_emscripten_asm_const_iiiid,__nbind_reference_external,_emscripten_asm_const_iiiiiiii,_removeAccessorPrefix,_typeModule,__nbind_register_pool,__decorate,_llvm_stackrestore,___cxa_atexit,__extends,__nbind_get_value_object,__ZN8facebook4yoga14YGNodeToStringEPNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP6YGNode14YGPrintOptionsj,_emscripten_set_main_loop_timing,__nbind_register_primitive,__nbind_register_type,_emscripten_memcpy_big,__nbind_register_function,___setErrNo,__nbind_register_class,__nbind_finish,_abort,_nbind_value,_llvm_stacksave,___syscall54,_defineHidden,_emscripten_set_main_loop,_emscripten_get_now,__nbind_register_callback_signature,_emscripten_asm_const_iiiiii,__nbind_free_external,_emscripten_asm_const_iiii,_emscripten_asm_const_iiididi,___syscall6,_atexit,___syscall140,___syscall146,DYNAMICTOP_PTR,tempDoublePtr,ABORT,STACKTOP,STACK_MAX,cttz_i8,___dso_handle};var asm=function(t,e,r){var s=new t.Int8Array(r),a=new t.Int16Array(r),n=new t.Int32Array(r),c=new t.Uint8Array(r),f=new t.Uint16Array(r),p=new t.Uint32Array(r),h=new t.Float32Array(r),E=new t.Float64Array(r),C=e.DYNAMICTOP_PTR|0,S=e.tempDoublePtr|0,P=e.ABORT|0,I=e.STACKTOP|0,R=e.STACK_MAX|0,N=e.cttz_i8|0,U=e.___dso_handle|0,W=0,ee=0,ie=0,ue=0,le=t.NaN,me=t.Infinity,pe=0,Be=0,Ce=0,g=0,we=0,ye=0,Ae=t.Math.floor,se=t.Math.abs,Z=t.Math.sqrt,De=t.Math.pow,Re=t.Math.cos,mt=t.Math.sin,j=t.Math.tan,rt=t.Math.acos,Fe=t.Math.asin,Ne=t.Math.atan,Pe=t.Math.atan2,Ve=t.Math.exp,ke=t.Math.log,it=t.Math.ceil,Ue=t.Math.imul,x=t.Math.min,w=t.Math.max,b=t.Math.clz32,y=t.Math.fround,F=e.abort,z=e.assert,X=e.enlargeMemory,$=e.getTotalMemory,oe=e.abortOnCannotGrowMemory,xe=e.invoke_viiiii,Te=e.invoke_vif,lt=e.invoke_vid,Ct=e.invoke_fiff,qt=e.invoke_vi,ir=e.invoke_vii,Pt=e.invoke_ii,gn=e.invoke_viddi,Pr=e.invoke_vidd,Ir=e.invoke_iiii,Or=e.invoke_diii,on=e.invoke_di,ai=e.invoke_iid,Io=e.invoke_iii,rs=e.invoke_viiddi,$s=e.invoke_viiiiii,Co=e.invoke_dii,ji=e.invoke_i,eo=e.invoke_iiiiii,wo=e.invoke_viiid,QA=e.invoke_viififi,Af=e.invoke_viii,dh=e.invoke_v,mh=e.invoke_viid,to=e.invoke_idd,jn=e.invoke_viiii,Ts=e._emscripten_asm_const_iiiii,ro=e._emscripten_asm_const_iiidddddd,ou=e._emscripten_asm_const_iiiid,au=e.__nbind_reference_external,lu=e._emscripten_asm_const_iiiiiiii,TA=e._removeAccessorPrefix,RA=e._typeModule,oa=e.__nbind_register_pool,aa=e.__decorate,FA=e._llvm_stackrestore,gr=e.___cxa_atexit,Bo=e.__extends,Me=e.__nbind_get_value_object,cu=e.__ZN8facebook4yoga14YGNodeToStringEPNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP6YGNode14YGPrintOptionsj,Cr=e._emscripten_set_main_loop_timing,pf=e.__nbind_register_primitive,NA=e.__nbind_register_type,OA=e._emscripten_memcpy_big,uu=e.__nbind_register_function,fu=e.___setErrNo,oc=e.__nbind_register_class,ve=e.__nbind_finish,Nt=e._abort,ac=e._nbind_value,Oi=e._llvm_stacksave,no=e.___syscall54,Rt=e._defineHidden,xn=e._emscripten_set_main_loop,la=e._emscripten_get_now,Gi=e.__nbind_register_callback_signature,Li=e._emscripten_asm_const_iiiiii,Na=e.__nbind_free_external,dn=e._emscripten_asm_const_iiii,Kn=e._emscripten_asm_const_iiididi,Au=e.___syscall6,yh=e._atexit,Oa=e.___syscall140,La=e.___syscall146,Ma=y(0);let $e=y(0);function Ua(o){o=o|0;var l=0;return l=I,I=I+o|0,I=I+15&-16,l|0}function hf(){return I|0}function lc(o){o=o|0,I=o}function wn(o,l){o=o|0,l=l|0,I=o,R=l}function ca(o,l){o=o|0,l=l|0,W||(W=o,ee=l)}function LA(o){o=o|0,ye=o}function MA(){return ye|0}function ua(){var o=0,l=0;Qr(8104,8,400)|0,Qr(8504,408,540)|0,o=9044,l=o+44|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));s[9088]=0,s[9089]=1,n[2273]=0,n[2274]=948,n[2275]=948,gr(17,8104,U|0)|0}function Bl(o){o=o|0,dt(o+948|0)}function Mt(o){return o=y(o),((fP(o)|0)&2147483647)>>>0>2139095040|0}function kn(o,l,u){o=o|0,l=l|0,u=u|0;e:do if(n[o+(l<<3)+4>>2]|0)o=o+(l<<3)|0;else{if((l|2|0)==3&&n[o+60>>2]|0){o=o+56|0;break}switch(l|0){case 0:case 2:case 4:case 5:{if(n[o+52>>2]|0){o=o+48|0;break e}break}default:}if(n[o+68>>2]|0){o=o+64|0;break}else{o=(l|1|0)==5?948:u;break}}while(!1);return o|0}function fa(o){o=o|0;var l=0;return l=_P(1e3)|0,Ha(o,(l|0)!=0,2456),n[2276]=(n[2276]|0)+1,Qr(l|0,8104,1e3)|0,s[o+2>>0]|0&&(n[l+4>>2]=2,n[l+12>>2]=4),n[l+976>>2]=o,l|0}function Ha(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0;d=I,I=I+16|0,A=d,l||(n[A>>2]=u,Wg(o,5,3197,A)),I=d}function ns(){return fa(956)|0}function cc(o){o=o|0;var l=0;return l=Kt(1e3)|0,pu(l,o),Ha(n[o+976>>2]|0,1,2456),n[2276]=(n[2276]|0)+1,n[l+944>>2]=0,l|0}function pu(o,l){o=o|0,l=l|0;var u=0;Qr(o|0,l|0,948)|0,Dy(o+948|0,l+948|0),u=o+960|0,o=l+960|0,l=u+40|0;do n[u>>2]=n[o>>2],u=u+4|0,o=o+4|0;while((u|0)<(l|0))}function uc(o){o=o|0;var l=0,u=0,A=0,d=0;if(l=o+944|0,u=n[l>>2]|0,u|0&&(ja(u+948|0,o)|0,n[l>>2]=0),u=Mi(o)|0,u|0){l=0;do n[(Is(o,l)|0)+944>>2]=0,l=l+1|0;while((l|0)!=(u|0))}u=o+948|0,A=n[u>>2]|0,d=o+952|0,l=n[d>>2]|0,(l|0)!=(A|0)&&(n[d>>2]=l+(~((l+-4-A|0)>>>2)<<2)),vl(u),HP(o),n[2276]=(n[2276]|0)+-1}function ja(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0;A=n[o>>2]|0,k=o+4|0,u=n[k>>2]|0,m=u;e:do if((A|0)==(u|0))d=A,B=4;else for(o=A;;){if((n[o>>2]|0)==(l|0)){d=o,B=4;break e}if(o=o+4|0,(o|0)==(u|0)){o=0;break}}while(!1);return(B|0)==4&&((d|0)!=(u|0)?(A=d+4|0,o=m-A|0,l=o>>2,l&&(Q2(d|0,A|0,o|0)|0,u=n[k>>2]|0),o=d+(l<<2)|0,(u|0)==(o|0)||(n[k>>2]=u+(~((u+-4-o|0)>>>2)<<2)),o=1):o=0),o|0}function Mi(o){return o=o|0,(n[o+952>>2]|0)-(n[o+948>>2]|0)>>2|0}function Is(o,l){o=o|0,l=l|0;var u=0;return u=n[o+948>>2]|0,(n[o+952>>2]|0)-u>>2>>>0>l>>>0?o=n[u+(l<<2)>>2]|0:o=0,o|0}function vl(o){o=o|0;var l=0,u=0,A=0,d=0;A=I,I=I+32|0,l=A,d=n[o>>2]|0,u=(n[o+4>>2]|0)-d|0,((n[o+8>>2]|0)-d|0)>>>0>u>>>0&&(d=u>>2,ky(l,d,d,o+8|0),AP(o,l),Qy(l)),I=A}function gf(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0,M=0;M=Mi(o)|0;do if(M|0){if((n[(Is(o,0)|0)+944>>2]|0)==(o|0)){if(!(ja(o+948|0,l)|0))break;Qr(l+400|0,8504,540)|0,n[l+944>>2]=0,Oe(o);break}B=n[(n[o+976>>2]|0)+12>>2]|0,k=o+948|0,T=(B|0)==0,u=0,m=0;do A=n[(n[k>>2]|0)+(m<<2)>>2]|0,(A|0)==(l|0)?Oe(o):(d=cc(A)|0,n[(n[k>>2]|0)+(u<<2)>>2]=d,n[d+944>>2]=o,T||dU[B&15](A,d,o,u),u=u+1|0),m=m+1|0;while((m|0)!=(M|0));if(u>>>0>>0){T=o+948|0,k=o+952|0,B=u,u=n[k>>2]|0;do m=(n[T>>2]|0)+(B<<2)|0,A=m+4|0,d=u-A|0,l=d>>2,l&&(Q2(m|0,A|0,d|0)|0,u=n[k>>2]|0),d=u,A=m+(l<<2)|0,(d|0)!=(A|0)&&(u=d+(~((d+-4-A|0)>>>2)<<2)|0,n[k>>2]=u),B=B+1|0;while((B|0)!=(M|0))}}while(!1)}function fc(o){o=o|0;var l=0,u=0,A=0,d=0;wi(o,(Mi(o)|0)==0,2491),wi(o,(n[o+944>>2]|0)==0,2545),l=o+948|0,u=n[l>>2]|0,A=o+952|0,d=n[A>>2]|0,(d|0)!=(u|0)&&(n[A>>2]=d+(~((d+-4-u|0)>>>2)<<2)),vl(l),l=o+976|0,u=n[l>>2]|0,Qr(o|0,8104,1e3)|0,s[u+2>>0]|0&&(n[o+4>>2]=2,n[o+12>>2]=4),n[l>>2]=u}function wi(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0;d=I,I=I+16|0,A=d,l||(n[A>>2]=u,xo(o,5,3197,A)),I=d}function Qn(){return n[2276]|0}function Ac(){var o=0;return o=_P(20)|0,Ke((o|0)!=0,2592),n[2277]=(n[2277]|0)+1,n[o>>2]=n[239],n[o+4>>2]=n[240],n[o+8>>2]=n[241],n[o+12>>2]=n[242],n[o+16>>2]=n[243],o|0}function Ke(o,l){o=o|0,l=l|0;var u=0,A=0;A=I,I=I+16|0,u=A,o||(n[u>>2]=l,xo(0,5,3197,u)),I=A}function st(o){o=o|0,HP(o),n[2277]=(n[2277]|0)+-1}function St(o,l){o=o|0,l=l|0;var u=0;l?(wi(o,(Mi(o)|0)==0,2629),u=1):(u=0,l=0),n[o+964>>2]=l,n[o+988>>2]=u}function lr(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;A=I,I=I+16|0,m=A+8|0,d=A+4|0,B=A,n[d>>2]=l,wi(o,(n[l+944>>2]|0)==0,2709),wi(o,(n[o+964>>2]|0)==0,2763),te(o),l=o+948|0,n[B>>2]=(n[l>>2]|0)+(u<<2),n[m>>2]=n[B>>2],Ee(l,m,d)|0,n[(n[d>>2]|0)+944>>2]=o,Oe(o),I=A}function te(o){o=o|0;var l=0,u=0,A=0,d=0,m=0,B=0,k=0;if(u=Mi(o)|0,u|0&&(n[(Is(o,0)|0)+944>>2]|0)!=(o|0)){A=n[(n[o+976>>2]|0)+12>>2]|0,d=o+948|0,m=(A|0)==0,l=0;do B=n[(n[d>>2]|0)+(l<<2)>>2]|0,k=cc(B)|0,n[(n[d>>2]|0)+(l<<2)>>2]=k,n[k+944>>2]=o,m||dU[A&15](B,k,o,l),l=l+1|0;while((l|0)!=(u|0))}}function Ee(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0,Ye=0,Le=0,Qe=0,tt=0,Ze=0;tt=I,I=I+64|0,q=tt+52|0,k=tt+48|0,ae=tt+28|0,Ye=tt+24|0,Le=tt+20|0,Qe=tt,A=n[o>>2]|0,m=A,l=A+((n[l>>2]|0)-m>>2<<2)|0,A=o+4|0,d=n[A>>2]|0,B=o+8|0;do if(d>>>0<(n[B>>2]|0)>>>0){if((l|0)==(d|0)){n[l>>2]=n[u>>2],n[A>>2]=(n[A>>2]|0)+4;break}pP(o,l,d,l+4|0),l>>>0<=u>>>0&&(u=(n[A>>2]|0)>>>0>u>>>0?u+4|0:u),n[l>>2]=n[u>>2]}else{A=(d-m>>2)+1|0,d=O(o)|0,d>>>0>>0&&an(o),L=n[o>>2]|0,M=(n[B>>2]|0)-L|0,m=M>>1,ky(Qe,M>>2>>>0>>1>>>0?m>>>0>>0?A:m:d,l-L>>2,o+8|0),L=Qe+8|0,A=n[L>>2]|0,m=Qe+12|0,M=n[m>>2]|0,B=M,T=A;do if((A|0)==(M|0)){if(M=Qe+4|0,A=n[M>>2]|0,Ze=n[Qe>>2]|0,d=Ze,A>>>0<=Ze>>>0){A=B-d>>1,A=A|0?A:1,ky(ae,A,A>>>2,n[Qe+16>>2]|0),n[Ye>>2]=n[M>>2],n[Le>>2]=n[L>>2],n[k>>2]=n[Ye>>2],n[q>>2]=n[Le>>2],o2(ae,k,q),A=n[Qe>>2]|0,n[Qe>>2]=n[ae>>2],n[ae>>2]=A,A=ae+4|0,Ze=n[M>>2]|0,n[M>>2]=n[A>>2],n[A>>2]=Ze,A=ae+8|0,Ze=n[L>>2]|0,n[L>>2]=n[A>>2],n[A>>2]=Ze,A=ae+12|0,Ze=n[m>>2]|0,n[m>>2]=n[A>>2],n[A>>2]=Ze,Qy(ae),A=n[L>>2]|0;break}m=A,B=((m-d>>2)+1|0)/-2|0,k=A+(B<<2)|0,d=T-m|0,m=d>>2,m&&(Q2(k|0,A|0,d|0)|0,A=n[M>>2]|0),Ze=k+(m<<2)|0,n[L>>2]=Ze,n[M>>2]=A+(B<<2),A=Ze}while(!1);n[A>>2]=n[u>>2],n[L>>2]=(n[L>>2]|0)+4,l=hP(o,Qe,l)|0,Qy(Qe)}while(!1);return I=tt,l|0}function Oe(o){o=o|0;var l=0;do{if(l=o+984|0,s[l>>0]|0)break;s[l>>0]=1,h[o+504>>2]=y(le),o=n[o+944>>2]|0}while(o|0)}function dt(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-4-A|0)>>>2)<<2)),It(u))}function Et(o){return o=o|0,n[o+944>>2]|0}function bt(o){o=o|0,wi(o,(n[o+964>>2]|0)!=0,2832),Oe(o)}function tr(o){return o=o|0,(s[o+984>>0]|0)!=0|0}function An(o,l){o=o|0,l=l|0,l6e(o,l,400)|0&&(Qr(o|0,l|0,400)|0,Oe(o))}function li(o){o=o|0;var l=$e;return l=y(h[o+44>>2]),o=Mt(l)|0,y(o?y(0):l)}function qi(o){o=o|0;var l=$e;return l=y(h[o+48>>2]),Mt(l)|0&&(l=s[(n[o+976>>2]|0)+2>>0]|0?y(1):y(0)),y(l)}function Tn(o,l){o=o|0,l=l|0,n[o+980>>2]=l}function Ga(o){return o=o|0,n[o+980>>2]|0}function my(o,l){o=o|0,l=l|0;var u=0;u=o+4|0,(n[u>>2]|0)!=(l|0)&&(n[u>>2]=l,Oe(o))}function Z1(o){return o=o|0,n[o+4>>2]|0}function vo(o,l){o=o|0,l=l|0;var u=0;u=o+8|0,(n[u>>2]|0)!=(l|0)&&(n[u>>2]=l,Oe(o))}function yy(o){return o=o|0,n[o+8>>2]|0}function Eh(o,l){o=o|0,l=l|0;var u=0;u=o+12|0,(n[u>>2]|0)!=(l|0)&&(n[u>>2]=l,Oe(o))}function $1(o){return o=o|0,n[o+12>>2]|0}function So(o,l){o=o|0,l=l|0;var u=0;u=o+16|0,(n[u>>2]|0)!=(l|0)&&(n[u>>2]=l,Oe(o))}function Ih(o){return o=o|0,n[o+16>>2]|0}function Ch(o,l){o=o|0,l=l|0;var u=0;u=o+20|0,(n[u>>2]|0)!=(l|0)&&(n[u>>2]=l,Oe(o))}function hu(o){return o=o|0,n[o+20>>2]|0}function wh(o,l){o=o|0,l=l|0;var u=0;u=o+24|0,(n[u>>2]|0)!=(l|0)&&(n[u>>2]=l,Oe(o))}function Fg(o){return o=o|0,n[o+24>>2]|0}function Ng(o,l){o=o|0,l=l|0;var u=0;u=o+28|0,(n[u>>2]|0)!=(l|0)&&(n[u>>2]=l,Oe(o))}function Og(o){return o=o|0,n[o+28>>2]|0}function Ey(o,l){o=o|0,l=l|0;var u=0;u=o+32|0,(n[u>>2]|0)!=(l|0)&&(n[u>>2]=l,Oe(o))}function df(o){return o=o|0,n[o+32>>2]|0}function Do(o,l){o=o|0,l=l|0;var u=0;u=o+36|0,(n[u>>2]|0)!=(l|0)&&(n[u>>2]=l,Oe(o))}function Sl(o){return o=o|0,n[o+36>>2]|0}function Bh(o,l){o=o|0,l=y(l);var u=0;u=o+40|0,y(h[u>>2])!=l&&(h[u>>2]=l,Oe(o))}function Lg(o,l){o=o|0,l=y(l);var u=0;u=o+44|0,y(h[u>>2])!=l&&(h[u>>2]=l,Oe(o))}function Dl(o,l){o=o|0,l=y(l);var u=0;u=o+48|0,y(h[u>>2])!=l&&(h[u>>2]=l,Oe(o))}function bl(o,l){o=o|0,l=y(l);var u=0,A=0,d=0,m=0;m=Mt(l)|0,u=(m^1)&1,A=o+52|0,d=o+56|0,m|y(h[A>>2])==l&&(n[d>>2]|0)==(u|0)||(h[A>>2]=l,n[d>>2]=u,Oe(o))}function Iy(o,l){o=o|0,l=y(l);var u=0,A=0;A=o+52|0,u=o+56|0,y(h[A>>2])==l&&(n[u>>2]|0)==2||(h[A>>2]=l,A=Mt(l)|0,n[u>>2]=A?3:2,Oe(o))}function UA(o,l){o=o|0,l=l|0;var u=0,A=0;A=l+52|0,u=n[A+4>>2]|0,l=o,n[l>>2]=n[A>>2],n[l+4>>2]=u}function Cy(o,l,u){o=o|0,l=l|0,u=y(u);var A=0,d=0,m=0;m=Mt(u)|0,A=(m^1)&1,d=o+132+(l<<3)|0,l=o+132+(l<<3)+4|0,m|y(h[d>>2])==u&&(n[l>>2]|0)==(A|0)||(h[d>>2]=u,n[l>>2]=A,Oe(o))}function wy(o,l,u){o=o|0,l=l|0,u=y(u);var A=0,d=0,m=0;m=Mt(u)|0,A=m?0:2,d=o+132+(l<<3)|0,l=o+132+(l<<3)+4|0,m|y(h[d>>2])==u&&(n[l>>2]|0)==(A|0)||(h[d>>2]=u,n[l>>2]=A,Oe(o))}function _A(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=l+132+(u<<3)|0,l=n[A+4>>2]|0,u=o,n[u>>2]=n[A>>2],n[u+4>>2]=l}function HA(o,l,u){o=o|0,l=l|0,u=y(u);var A=0,d=0,m=0;m=Mt(u)|0,A=(m^1)&1,d=o+60+(l<<3)|0,l=o+60+(l<<3)+4|0,m|y(h[d>>2])==u&&(n[l>>2]|0)==(A|0)||(h[d>>2]=u,n[l>>2]=A,Oe(o))}function Y(o,l,u){o=o|0,l=l|0,u=y(u);var A=0,d=0,m=0;m=Mt(u)|0,A=m?0:2,d=o+60+(l<<3)|0,l=o+60+(l<<3)+4|0,m|y(h[d>>2])==u&&(n[l>>2]|0)==(A|0)||(h[d>>2]=u,n[l>>2]=A,Oe(o))}function xt(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=l+60+(u<<3)|0,l=n[A+4>>2]|0,u=o,n[u>>2]=n[A>>2],n[u+4>>2]=l}function jA(o,l){o=o|0,l=l|0;var u=0;u=o+60+(l<<3)+4|0,(n[u>>2]|0)!=3&&(h[o+60+(l<<3)>>2]=y(le),n[u>>2]=3,Oe(o))}function bo(o,l,u){o=o|0,l=l|0,u=y(u);var A=0,d=0,m=0;m=Mt(u)|0,A=(m^1)&1,d=o+204+(l<<3)|0,l=o+204+(l<<3)+4|0,m|y(h[d>>2])==u&&(n[l>>2]|0)==(A|0)||(h[d>>2]=u,n[l>>2]=A,Oe(o))}function mf(o,l,u){o=o|0,l=l|0,u=y(u);var A=0,d=0,m=0;m=Mt(u)|0,A=m?0:2,d=o+204+(l<<3)|0,l=o+204+(l<<3)+4|0,m|y(h[d>>2])==u&&(n[l>>2]|0)==(A|0)||(h[d>>2]=u,n[l>>2]=A,Oe(o))}function yt(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=l+204+(u<<3)|0,l=n[A+4>>2]|0,u=o,n[u>>2]=n[A>>2],n[u+4>>2]=l}function gu(o,l,u){o=o|0,l=l|0,u=y(u);var A=0,d=0,m=0;m=Mt(u)|0,A=(m^1)&1,d=o+276+(l<<3)|0,l=o+276+(l<<3)+4|0,m|y(h[d>>2])==u&&(n[l>>2]|0)==(A|0)||(h[d>>2]=u,n[l>>2]=A,Oe(o))}function By(o,l){return o=o|0,l=l|0,y(h[o+276+(l<<3)>>2])}function Mg(o,l){o=o|0,l=y(l);var u=0,A=0,d=0,m=0;m=Mt(l)|0,u=(m^1)&1,A=o+348|0,d=o+352|0,m|y(h[A>>2])==l&&(n[d>>2]|0)==(u|0)||(h[A>>2]=l,n[d>>2]=u,Oe(o))}function e2(o,l){o=o|0,l=y(l);var u=0,A=0;A=o+348|0,u=o+352|0,y(h[A>>2])==l&&(n[u>>2]|0)==2||(h[A>>2]=l,A=Mt(l)|0,n[u>>2]=A?3:2,Oe(o))}function vh(o){o=o|0;var l=0;l=o+352|0,(n[l>>2]|0)!=3&&(h[o+348>>2]=y(le),n[l>>2]=3,Oe(o))}function ur(o,l){o=o|0,l=l|0;var u=0,A=0;A=l+348|0,u=n[A+4>>2]|0,l=o,n[l>>2]=n[A>>2],n[l+4>>2]=u}function zi(o,l){o=o|0,l=y(l);var u=0,A=0,d=0,m=0;m=Mt(l)|0,u=(m^1)&1,A=o+356|0,d=o+360|0,m|y(h[A>>2])==l&&(n[d>>2]|0)==(u|0)||(h[A>>2]=l,n[d>>2]=u,Oe(o))}function yf(o,l){o=o|0,l=y(l);var u=0,A=0;A=o+356|0,u=o+360|0,y(h[A>>2])==l&&(n[u>>2]|0)==2||(h[A>>2]=l,A=Mt(l)|0,n[u>>2]=A?3:2,Oe(o))}function qa(o){o=o|0;var l=0;l=o+360|0,(n[l>>2]|0)!=3&&(h[o+356>>2]=y(le),n[l>>2]=3,Oe(o))}function Ug(o,l){o=o|0,l=l|0;var u=0,A=0;A=l+356|0,u=n[A+4>>2]|0,l=o,n[l>>2]=n[A>>2],n[l+4>>2]=u}function du(o,l){o=o|0,l=y(l);var u=0,A=0,d=0,m=0;m=Mt(l)|0,u=(m^1)&1,A=o+364|0,d=o+368|0,m|y(h[A>>2])==l&&(n[d>>2]|0)==(u|0)||(h[A>>2]=l,n[d>>2]=u,Oe(o))}function Ef(o,l){o=o|0,l=y(l);var u=0,A=0,d=0,m=0;m=Mt(l)|0,u=m?0:2,A=o+364|0,d=o+368|0,m|y(h[A>>2])==l&&(n[d>>2]|0)==(u|0)||(h[A>>2]=l,n[d>>2]=u,Oe(o))}function wt(o,l){o=o|0,l=l|0;var u=0,A=0;A=l+364|0,u=n[A+4>>2]|0,l=o,n[l>>2]=n[A>>2],n[l+4>>2]=u}function di(o,l){o=o|0,l=y(l);var u=0,A=0,d=0,m=0;m=Mt(l)|0,u=(m^1)&1,A=o+372|0,d=o+376|0,m|y(h[A>>2])==l&&(n[d>>2]|0)==(u|0)||(h[A>>2]=l,n[d>>2]=u,Oe(o))}function GA(o,l){o=o|0,l=y(l);var u=0,A=0,d=0,m=0;m=Mt(l)|0,u=m?0:2,A=o+372|0,d=o+376|0,m|y(h[A>>2])==l&&(n[d>>2]|0)==(u|0)||(h[A>>2]=l,n[d>>2]=u,Oe(o))}function Wa(o,l){o=o|0,l=l|0;var u=0,A=0;A=l+372|0,u=n[A+4>>2]|0,l=o,n[l>>2]=n[A>>2],n[l+4>>2]=u}function Aa(o,l){o=o|0,l=y(l);var u=0,A=0,d=0,m=0;m=Mt(l)|0,u=(m^1)&1,A=o+380|0,d=o+384|0,m|y(h[A>>2])==l&&(n[d>>2]|0)==(u|0)||(h[A>>2]=l,n[d>>2]=u,Oe(o))}function Ya(o,l){o=o|0,l=y(l);var u=0,A=0,d=0,m=0;m=Mt(l)|0,u=m?0:2,A=o+380|0,d=o+384|0,m|y(h[A>>2])==l&&(n[d>>2]|0)==(u|0)||(h[A>>2]=l,n[d>>2]=u,Oe(o))}function _g(o,l){o=o|0,l=l|0;var u=0,A=0;A=l+380|0,u=n[A+4>>2]|0,l=o,n[l>>2]=n[A>>2],n[l+4>>2]=u}function Sh(o,l){o=o|0,l=y(l);var u=0,A=0,d=0,m=0;m=Mt(l)|0,u=(m^1)&1,A=o+388|0,d=o+392|0,m|y(h[A>>2])==l&&(n[d>>2]|0)==(u|0)||(h[A>>2]=l,n[d>>2]=u,Oe(o))}function Hg(o,l){o=o|0,l=y(l);var u=0,A=0,d=0,m=0;m=Mt(l)|0,u=m?0:2,A=o+388|0,d=o+392|0,m|y(h[A>>2])==l&&(n[d>>2]|0)==(u|0)||(h[A>>2]=l,n[d>>2]=u,Oe(o))}function vy(o,l){o=o|0,l=l|0;var u=0,A=0;A=l+388|0,u=n[A+4>>2]|0,l=o,n[l>>2]=n[A>>2],n[l+4>>2]=u}function qA(o,l){o=o|0,l=y(l);var u=0;u=o+396|0,y(h[u>>2])!=l&&(h[u>>2]=l,Oe(o))}function jg(o){return o=o|0,y(h[o+396>>2])}function mu(o){return o=o|0,y(h[o+400>>2])}function yu(o){return o=o|0,y(h[o+404>>2])}function If(o){return o=o|0,y(h[o+408>>2])}function Rs(o){return o=o|0,y(h[o+412>>2])}function Eu(o){return o=o|0,y(h[o+416>>2])}function Gn(o){return o=o|0,y(h[o+420>>2])}function is(o,l){switch(o=o|0,l=l|0,wi(o,(l|0)<6,2918),l|0){case 0:{l=(n[o+496>>2]|0)==2?5:4;break}case 2:{l=(n[o+496>>2]|0)==2?4:5;break}default:}return y(h[o+424+(l<<2)>>2])}function Pi(o,l){switch(o=o|0,l=l|0,wi(o,(l|0)<6,2918),l|0){case 0:{l=(n[o+496>>2]|0)==2?5:4;break}case 2:{l=(n[o+496>>2]|0)==2?4:5;break}default:}return y(h[o+448+(l<<2)>>2])}function WA(o,l){switch(o=o|0,l=l|0,wi(o,(l|0)<6,2918),l|0){case 0:{l=(n[o+496>>2]|0)==2?5:4;break}case 2:{l=(n[o+496>>2]|0)==2?4:5;break}default:}return y(h[o+472+(l<<2)>>2])}function Cf(o,l){o=o|0,l=l|0;var u=0,A=$e;return u=n[o+4>>2]|0,(u|0)==(n[l+4>>2]|0)?u?(A=y(h[o>>2]),o=y(se(y(A-y(h[l>>2]))))>2]=0,n[A+4>>2]=0,n[A+8>>2]=0,cu(A|0,o|0,l|0,0),xo(o,3,(s[A+11>>0]|0)<0?n[A>>2]|0:A,u),Q6e(A),I=u}function ss(o,l,u,A){o=y(o),l=y(l),u=u|0,A=A|0;var d=$e;o=y(o*l),d=y(uU(o,y(1)));do if(mn(d,y(0))|0)o=y(o-d);else{if(o=y(o-d),mn(d,y(1))|0){o=y(o+y(1));break}if(u){o=y(o+y(1));break}A||(d>y(.5)?d=y(1):(A=mn(d,y(.5))|0,d=y(A?1:0)),o=y(o+d))}while(!1);return y(o/l)}function Pl(o,l,u,A,d,m,B,k,T,M,L,q,ae){o=o|0,l=y(l),u=u|0,A=y(A),d=d|0,m=y(m),B=B|0,k=y(k),T=y(T),M=y(M),L=y(L),q=y(q),ae=ae|0;var Ye=0,Le=$e,Qe=$e,tt=$e,Ze=$e,ct=$e,He=$e;return T>2]),Le!=y(0))?(tt=y(ss(l,Le,0,0)),Ze=y(ss(A,Le,0,0)),Qe=y(ss(m,Le,0,0)),Le=y(ss(k,Le,0,0))):(Qe=m,tt=l,Le=k,Ze=A),(d|0)==(o|0)?Ye=mn(Qe,tt)|0:Ye=0,(B|0)==(u|0)?ae=mn(Le,Ze)|0:ae=0,!Ye&&(ct=y(l-L),!(Po(o,ct,T)|0))&&!(wf(o,ct,d,T)|0)?Ye=Bf(o,ct,d,m,T)|0:Ye=1,!ae&&(He=y(A-q),!(Po(u,He,M)|0))&&!(wf(u,He,B,M)|0)?ae=Bf(u,He,B,k,M)|0:ae=1,ae=Ye&ae),ae|0}function Po(o,l,u){return o=o|0,l=y(l),u=y(u),(o|0)==1?o=mn(l,u)|0:o=0,o|0}function wf(o,l,u,A){return o=o|0,l=y(l),u=u|0,A=y(A),(o|0)==2&(u|0)==0?l>=A?o=1:o=mn(l,A)|0:o=0,o|0}function Bf(o,l,u,A,d){return o=o|0,l=y(l),u=u|0,A=y(A),d=y(d),(o|0)==2&(u|0)==2&A>l?d<=l?o=1:o=mn(l,d)|0:o=0,o|0}function xl(o,l,u,A,d,m,B,k,T,M,L){o=o|0,l=y(l),u=y(u),A=A|0,d=d|0,m=m|0,B=y(B),k=y(k),T=T|0,M=M|0,L=L|0;var q=0,ae=0,Ye=0,Le=0,Qe=$e,tt=$e,Ze=0,ct=0,He=0,We=0,Lt=0,Gr=0,fr=0,$t=0,Tr=0,Hr=0,cr=0,Hn=$e,To=$e,Ro=$e,Fo=0,Za=0;cr=I,I=I+160|0,$t=cr+152|0,fr=cr+120|0,Gr=cr+104|0,He=cr+72|0,Le=cr+56|0,Lt=cr+8|0,ct=cr,We=(n[2279]|0)+1|0,n[2279]=We,Tr=o+984|0,s[Tr>>0]|0&&(n[o+512>>2]|0)!=(n[2278]|0)?Ze=4:(n[o+516>>2]|0)==(A|0)?Hr=0:Ze=4,(Ze|0)==4&&(n[o+520>>2]=0,n[o+924>>2]=-1,n[o+928>>2]=-1,h[o+932>>2]=y(-1),h[o+936>>2]=y(-1),Hr=1);e:do if(n[o+964>>2]|0)if(Qe=y(yn(o,2,B)),tt=y(yn(o,0,B)),q=o+916|0,Ro=y(h[q>>2]),To=y(h[o+920>>2]),Hn=y(h[o+932>>2]),Pl(d,l,m,u,n[o+924>>2]|0,Ro,n[o+928>>2]|0,To,Hn,y(h[o+936>>2]),Qe,tt,L)|0)Ze=22;else if(Ye=n[o+520>>2]|0,!Ye)Ze=21;else for(ae=0;;){if(q=o+524+(ae*24|0)|0,Hn=y(h[q>>2]),To=y(h[o+524+(ae*24|0)+4>>2]),Ro=y(h[o+524+(ae*24|0)+16>>2]),Pl(d,l,m,u,n[o+524+(ae*24|0)+8>>2]|0,Hn,n[o+524+(ae*24|0)+12>>2]|0,To,Ro,y(h[o+524+(ae*24|0)+20>>2]),Qe,tt,L)|0){Ze=22;break e}if(ae=ae+1|0,ae>>>0>=Ye>>>0){Ze=21;break}}else{if(T){if(q=o+916|0,!(mn(y(h[q>>2]),l)|0)){Ze=21;break}if(!(mn(y(h[o+920>>2]),u)|0)){Ze=21;break}if((n[o+924>>2]|0)!=(d|0)){Ze=21;break}q=(n[o+928>>2]|0)==(m|0)?q:0,Ze=22;break}if(Ye=n[o+520>>2]|0,!Ye)Ze=21;else for(ae=0;;){if(q=o+524+(ae*24|0)|0,mn(y(h[q>>2]),l)|0&&mn(y(h[o+524+(ae*24|0)+4>>2]),u)|0&&(n[o+524+(ae*24|0)+8>>2]|0)==(d|0)&&(n[o+524+(ae*24|0)+12>>2]|0)==(m|0)){Ze=22;break e}if(ae=ae+1|0,ae>>>0>=Ye>>>0){Ze=21;break}}}while(!1);do if((Ze|0)==21)s[11697]|0?(q=0,Ze=28):(q=0,Ze=31);else if((Ze|0)==22){if(ae=(s[11697]|0)!=0,!((q|0)!=0&(Hr^1)))if(ae){Ze=28;break}else{Ze=31;break}Le=q+16|0,n[o+908>>2]=n[Le>>2],Ye=q+20|0,n[o+912>>2]=n[Ye>>2],(s[11698]|0)==0|ae^1||(n[ct>>2]=Iu(We)|0,n[ct+4>>2]=We,xo(o,4,2972,ct),ae=n[o+972>>2]|0,ae|0&&ip[ae&127](o),d=pa(d,T)|0,m=pa(m,T)|0,Za=+y(h[Le>>2]),Fo=+y(h[Ye>>2]),n[Lt>>2]=d,n[Lt+4>>2]=m,E[Lt+8>>3]=+l,E[Lt+16>>3]=+u,E[Lt+24>>3]=Za,E[Lt+32>>3]=Fo,n[Lt+40>>2]=M,xo(o,4,2989,Lt))}while(!1);return(Ze|0)==28&&(ae=Iu(We)|0,n[Le>>2]=ae,n[Le+4>>2]=We,n[Le+8>>2]=Hr?3047:11699,xo(o,4,3038,Le),ae=n[o+972>>2]|0,ae|0&&ip[ae&127](o),Lt=pa(d,T)|0,Ze=pa(m,T)|0,n[He>>2]=Lt,n[He+4>>2]=Ze,E[He+8>>3]=+l,E[He+16>>3]=+u,n[He+24>>2]=M,xo(o,4,3049,He),Ze=31),(Ze|0)==31&&(Fs(o,l,u,A,d,m,B,k,T,L),s[11697]|0&&(ae=n[2279]|0,Lt=Iu(ae)|0,n[Gr>>2]=Lt,n[Gr+4>>2]=ae,n[Gr+8>>2]=Hr?3047:11699,xo(o,4,3083,Gr),ae=n[o+972>>2]|0,ae|0&&ip[ae&127](o),Lt=pa(d,T)|0,Gr=pa(m,T)|0,Fo=+y(h[o+908>>2]),Za=+y(h[o+912>>2]),n[fr>>2]=Lt,n[fr+4>>2]=Gr,E[fr+8>>3]=Fo,E[fr+16>>3]=Za,n[fr+24>>2]=M,xo(o,4,3092,fr)),n[o+516>>2]=A,q||(ae=o+520|0,q=n[ae>>2]|0,(q|0)==16&&(s[11697]|0&&xo(o,4,3124,$t),n[ae>>2]=0,q=0),T?q=o+916|0:(n[ae>>2]=q+1,q=o+524+(q*24|0)|0),h[q>>2]=l,h[q+4>>2]=u,n[q+8>>2]=d,n[q+12>>2]=m,n[q+16>>2]=n[o+908>>2],n[q+20>>2]=n[o+912>>2],q=0)),T&&(n[o+416>>2]=n[o+908>>2],n[o+420>>2]=n[o+912>>2],s[o+985>>0]=1,s[Tr>>0]=0),n[2279]=(n[2279]|0)+-1,n[o+512>>2]=n[2278],I=cr,Hr|(q|0)==0|0}function yn(o,l,u){o=o|0,l=l|0,u=y(u);var A=$e;return A=y(K(o,l,u)),y(A+y(re(o,l,u)))}function xo(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0;m=I,I=I+16|0,d=m,n[d>>2]=A,o?A=n[o+976>>2]|0:A=0,Ph(A,o,l,u,d),I=m}function Iu(o){return o=o|0,(o>>>0>60?3201:3201+(60-o)|0)|0}function pa(o,l){o=o|0,l=l|0;var u=0,A=0,d=0;return d=I,I=I+32|0,u=d+12|0,A=d,n[u>>2]=n[254],n[u+4>>2]=n[255],n[u+8>>2]=n[256],n[A>>2]=n[257],n[A+4>>2]=n[258],n[A+8>>2]=n[259],(o|0)>2?o=11699:o=n[(l?A:u)+(o<<2)>>2]|0,I=d,o|0}function Fs(o,l,u,A,d,m,B,k,T,M){o=o|0,l=y(l),u=y(u),A=A|0,d=d|0,m=m|0,B=y(B),k=y(k),T=T|0,M=M|0;var L=0,q=0,ae=0,Ye=0,Le=$e,Qe=$e,tt=$e,Ze=$e,ct=$e,He=$e,We=$e,Lt=0,Gr=0,fr=0,$t=$e,Tr=$e,Hr=0,cr=$e,Hn=0,To=0,Ro=0,Fo=0,Za=0,Wh=0,Yh=0,gc=0,Vh=0,Rf=0,Ff=0,Jh=0,Kh=0,zh=0,ln=0,dc=0,Xh=0,Pu=0,Zh=$e,$h=$e,Nf=$e,Of=$e,xu=$e,oo=0,Ll=0,ma=0,mc=0,op=0,ap=$e,Lf=$e,lp=$e,cp=$e,ao=$e,Ms=$e,yc=0,Wn=$e,up=$e,No=$e,ku=$e,Oo=$e,Qu=$e,fp=0,Ap=0,Tu=$e,lo=$e,Ec=0,pp=0,hp=0,gp=0,Nr=$e,ui=0,Us=0,Lo=0,co=0,Mr=0,Ar=0,Ic=0,zt=$e,dp=0,Bi=0;Ic=I,I=I+16|0,oo=Ic+12|0,Ll=Ic+8|0,ma=Ic+4|0,mc=Ic,wi(o,(d|0)==0|(Mt(l)|0)^1,3326),wi(o,(m|0)==0|(Mt(u)|0)^1,3406),Us=At(o,A)|0,n[o+496>>2]=Us,Mr=dr(2,Us)|0,Ar=dr(0,Us)|0,h[o+440>>2]=y(K(o,Mr,B)),h[o+444>>2]=y(re(o,Mr,B)),h[o+428>>2]=y(K(o,Ar,B)),h[o+436>>2]=y(re(o,Ar,B)),h[o+464>>2]=y(vr(o,Mr)),h[o+468>>2]=y(Un(o,Mr)),h[o+452>>2]=y(vr(o,Ar)),h[o+460>>2]=y(Un(o,Ar)),h[o+488>>2]=y(mi(o,Mr,B)),h[o+492>>2]=y(Cs(o,Mr,B)),h[o+476>>2]=y(mi(o,Ar,B)),h[o+484>>2]=y(Cs(o,Ar,B));do if(n[o+964>>2]|0)JA(o,l,u,d,m,B,k);else{if(Lo=o+948|0,co=(n[o+952>>2]|0)-(n[Lo>>2]|0)>>2,!co){lP(o,l,u,d,m,B,k);break}if(!T&&t2(o,l,u,d,m,B,k)|0)break;te(o),dc=o+508|0,s[dc>>0]=0,Mr=dr(n[o+4>>2]|0,Us)|0,Ar=by(Mr,Us)|0,ui=de(Mr)|0,Xh=n[o+8>>2]|0,pp=o+28|0,Pu=(n[pp>>2]|0)!=0,Oo=ui?B:k,Tu=ui?k:B,Zh=y(kh(o,Mr,B)),$h=y(r2(o,Mr,B)),Le=y(kh(o,Ar,B)),Qu=y(Va(o,Mr,B)),lo=y(Va(o,Ar,B)),fr=ui?d:m,Ec=ui?m:d,Nr=ui?Qu:lo,ct=ui?lo:Qu,ku=y(yn(o,2,B)),Ze=y(yn(o,0,B)),Qe=y(y(Zr(o+364|0,B))-Nr),tt=y(y(Zr(o+380|0,B))-Nr),He=y(y(Zr(o+372|0,k))-ct),We=y(y(Zr(o+388|0,k))-ct),Nf=ui?Qe:He,Of=ui?tt:We,ku=y(l-ku),l=y(ku-Nr),Mt(l)|0?Nr=l:Nr=y($n(y(pd(l,tt)),Qe)),up=y(u-Ze),l=y(up-ct),Mt(l)|0?No=l:No=y($n(y(pd(l,We)),He)),Qe=ui?Nr:No,Wn=ui?No:Nr;e:do if((fr|0)==1)for(A=0,q=0;;){if(L=Is(o,q)|0,!A)y(KA(L))>y(0)&&y(Qh(L))>y(0)?A=L:A=0;else if(n2(L)|0){Ye=0;break e}if(q=q+1|0,q>>>0>=co>>>0){Ye=A;break}}else Ye=0;while(!1);Lt=Ye+500|0,Gr=Ye+504|0,A=0,L=0,l=y(0),ae=0;do{if(q=n[(n[Lo>>2]|0)+(ae<<2)>>2]|0,(n[q+36>>2]|0)==1)Py(q),s[q+985>>0]=1,s[q+984>>0]=0;else{vf(q),T&&bh(q,At(q,Us)|0,Qe,Wn,Nr);do if((n[q+24>>2]|0)!=1)if((q|0)==(Ye|0)){n[Lt>>2]=n[2278],h[Gr>>2]=y(0);break}else{cP(o,q,Nr,d,No,Nr,No,m,Us,M);break}else L|0&&(n[L+960>>2]=q),n[q+960>>2]=0,L=q,A=A|0?A:q;while(!1);Ms=y(h[q+504>>2]),l=y(l+y(Ms+y(yn(q,Mr,Nr))))}ae=ae+1|0}while((ae|0)!=(co|0));for(Ro=l>Qe,yc=Pu&((fr|0)==2&Ro)?1:fr,Hn=(Ec|0)==1,Za=Hn&(T^1),Wh=(yc|0)==1,Yh=(yc|0)==2,gc=976+(Mr<<2)|0,Vh=(Ec|2|0)==2,zh=Hn&(Pu^1),Rf=1040+(Ar<<2)|0,Ff=1040+(Mr<<2)|0,Jh=976+(Ar<<2)|0,Kh=(Ec|0)!=1,Ro=Pu&((fr|0)!=0&Ro),To=o+976|0,Hn=Hn^1,l=Qe,Hr=0,Fo=0,Ms=y(0),xu=y(0);;){e:do if(Hr>>>0>>0)for(Gr=n[Lo>>2]|0,ae=0,We=y(0),He=y(0),tt=y(0),Qe=y(0),q=0,L=0,Ye=Hr;;){if(Lt=n[Gr+(Ye<<2)>>2]|0,(n[Lt+36>>2]|0)!=1&&(n[Lt+940>>2]=Fo,(n[Lt+24>>2]|0)!=1)){if(Ze=y(yn(Lt,Mr,Nr)),ln=n[gc>>2]|0,u=y(Zr(Lt+380+(ln<<3)|0,Oo)),ct=y(h[Lt+504>>2]),u=y(pd(u,ct)),u=y($n(y(Zr(Lt+364+(ln<<3)|0,Oo)),u)),Pu&(ae|0)!=0&y(Ze+y(He+u))>l){m=ae,Ze=We,fr=Ye;break e}Ze=y(Ze+u),u=y(He+Ze),Ze=y(We+Ze),n2(Lt)|0&&(tt=y(tt+y(KA(Lt))),Qe=y(Qe-y(ct*y(Qh(Lt))))),L|0&&(n[L+960>>2]=Lt),n[Lt+960>>2]=0,ae=ae+1|0,L=Lt,q=q|0?q:Lt}else Ze=We,u=He;if(Ye=Ye+1|0,Ye>>>0>>0)We=Ze,He=u;else{m=ae,fr=Ye;break}}else m=0,Ze=y(0),tt=y(0),Qe=y(0),q=0,fr=Hr;while(!1);ln=tt>y(0)&tty(0)&QeOf&((Mt(Of)|0)^1))l=Of,ln=51;else if(s[(n[To>>2]|0)+3>>0]|0)ln=51;else{if($t!=y(0)&&y(KA(o))!=y(0)){ln=53;break}l=Ze,ln=53}while(!1);if((ln|0)==51&&(ln=0,Mt(l)|0?ln=53:(Tr=y(l-Ze),cr=l)),(ln|0)==53&&(ln=0,Ze>2]|0,Ye=Try(0),He=y(Tr/$t),tt=y(0),Ze=y(0),l=y(0),L=q;do u=y(Zr(L+380+(ae<<3)|0,Oo)),Qe=y(Zr(L+364+(ae<<3)|0,Oo)),Qe=y(pd(u,y($n(Qe,y(h[L+504>>2]))))),Ye?(u=y(Qe*y(Qh(L))),u!=y(-0)&&(zt=y(Qe-y(ct*u)),ap=y(qn(L,Mr,zt,cr,Nr)),zt!=ap)&&(tt=y(tt-y(ap-Qe)),l=y(l+u))):Lt&&(Lf=y(KA(L)),Lf!=y(0))&&(zt=y(Qe+y(He*Lf)),lp=y(qn(L,Mr,zt,cr,Nr)),zt!=lp)&&(tt=y(tt-y(lp-Qe)),Ze=y(Ze-Lf)),L=n[L+960>>2]|0;while(L|0);if(l=y(We+l),Qe=y(Tr+tt),op)l=y(0);else{ct=y($t+Ze),Ye=n[gc>>2]|0,Lt=Qey(0),ct=y(Qe/ct),l=y(0);do{zt=y(Zr(q+380+(Ye<<3)|0,Oo)),tt=y(Zr(q+364+(Ye<<3)|0,Oo)),tt=y(pd(zt,y($n(tt,y(h[q+504>>2]))))),Lt?(zt=y(tt*y(Qh(q))),Qe=y(-zt),zt!=y(-0)?(zt=y(He*Qe),Qe=y(qn(q,Mr,y(tt+(Gr?Qe:zt)),cr,Nr))):Qe=tt):ae&&(cp=y(KA(q)),cp!=y(0))?Qe=y(qn(q,Mr,y(tt+y(ct*cp)),cr,Nr)):Qe=tt,l=y(l-y(Qe-tt)),Ze=y(yn(q,Mr,Nr)),u=y(yn(q,Ar,Nr)),Qe=y(Qe+Ze),h[Ll>>2]=Qe,n[mc>>2]=1,tt=y(h[q+396>>2]);e:do if(Mt(tt)|0){L=Mt(Wn)|0;do if(!L){if(Ro|(io(q,Ar,Wn)|0|Hn)||(os(o,q)|0)!=4||(n[(kl(q,Ar)|0)+4>>2]|0)==3||(n[(Ql(q,Ar)|0)+4>>2]|0)==3)break;h[oo>>2]=Wn,n[ma>>2]=1;break e}while(!1);if(io(q,Ar,Wn)|0){L=n[q+992+(n[Jh>>2]<<2)>>2]|0,zt=y(u+y(Zr(L,Wn))),h[oo>>2]=zt,L=Kh&(n[L+4>>2]|0)==2,n[ma>>2]=((Mt(zt)|0|L)^1)&1;break}else{h[oo>>2]=Wn,n[ma>>2]=L?0:2;break}}else zt=y(Qe-Ze),$t=y(zt/tt),zt=y(tt*zt),n[ma>>2]=1,h[oo>>2]=y(u+(ui?$t:zt));while(!1);Cu(q,Mr,cr,Nr,mc,Ll),Cu(q,Ar,Wn,Nr,ma,oo);do if(!(io(q,Ar,Wn)|0)&&(os(o,q)|0)==4){if((n[(kl(q,Ar)|0)+4>>2]|0)==3){L=0;break}L=(n[(Ql(q,Ar)|0)+4>>2]|0)!=3}else L=0;while(!1);zt=y(h[Ll>>2]),$t=y(h[oo>>2]),dp=n[mc>>2]|0,Bi=n[ma>>2]|0,xl(q,ui?zt:$t,ui?$t:zt,Us,ui?dp:Bi,ui?Bi:dp,Nr,No,T&(L^1),3488,M)|0,s[dc>>0]=s[dc>>0]|s[q+508>>0],q=n[q+960>>2]|0}while(q|0)}}else l=y(0);if(l=y(Tr+l),Bi=l>0]=Bi|c[dc>>0],Yh&l>y(0)?(L=n[gc>>2]|0,n[o+364+(L<<3)+4>>2]|0&&(ao=y(Zr(o+364+(L<<3)|0,Oo)),ao>=y(0))?Qe=y($n(y(0),y(ao-y(cr-l)))):Qe=y(0)):Qe=l,Lt=Hr>>>0>>0,Lt){Ye=n[Lo>>2]|0,ae=Hr,L=0;do q=n[Ye+(ae<<2)>>2]|0,n[q+24>>2]|0||(L=((n[(kl(q,Mr)|0)+4>>2]|0)==3&1)+L|0,L=L+((n[(Ql(q,Mr)|0)+4>>2]|0)==3&1)|0),ae=ae+1|0;while((ae|0)!=(fr|0));L?(Ze=y(0),u=y(0)):ln=101}else ln=101;e:do if((ln|0)==101)switch(ln=0,Xh|0){case 1:{L=0,Ze=y(Qe*y(.5)),u=y(0);break e}case 2:{L=0,Ze=Qe,u=y(0);break e}case 3:{if(m>>>0<=1){L=0,Ze=y(0),u=y(0);break e}u=y((m+-1|0)>>>0),L=0,Ze=y(0),u=y(y($n(Qe,y(0)))/u);break e}case 5:{u=y(Qe/y((m+1|0)>>>0)),L=0,Ze=u;break e}case 4:{u=y(Qe/y(m>>>0)),L=0,Ze=y(u*y(.5));break e}default:{L=0,Ze=y(0),u=y(0);break e}}while(!1);if(l=y(Zh+Ze),Lt){tt=y(Qe/y(L|0)),ae=n[Lo>>2]|0,q=Hr,Qe=y(0);do{L=n[ae+(q<<2)>>2]|0;e:do if((n[L+36>>2]|0)!=1){switch(n[L+24>>2]|0){case 1:{if(ha(L,Mr)|0){if(!T)break e;zt=y(zA(L,Mr,cr)),zt=y(zt+y(vr(o,Mr))),zt=y(zt+y(K(L,Mr,Nr))),h[L+400+(n[Ff>>2]<<2)>>2]=zt;break e}break}case 0:if(Bi=(n[(kl(L,Mr)|0)+4>>2]|0)==3,zt=y(tt+l),l=Bi?zt:l,T&&(Bi=L+400+(n[Ff>>2]<<2)|0,h[Bi>>2]=y(l+y(h[Bi>>2]))),Bi=(n[(Ql(L,Mr)|0)+4>>2]|0)==3,zt=y(tt+l),l=Bi?zt:l,Za){zt=y(u+y(yn(L,Mr,Nr))),Qe=Wn,l=y(l+y(zt+y(h[L+504>>2])));break e}else{l=y(l+y(u+y(XA(L,Mr,Nr)))),Qe=y($n(Qe,y(XA(L,Ar,Nr))));break e}default:}T&&(zt=y(Ze+y(vr(o,Mr))),Bi=L+400+(n[Ff>>2]<<2)|0,h[Bi>>2]=y(zt+y(h[Bi>>2])))}while(!1);q=q+1|0}while((q|0)!=(fr|0))}else Qe=y(0);if(u=y($h+l),Vh?Ze=y(y(qn(o,Ar,y(lo+Qe),Tu,B))-lo):Ze=Wn,tt=y(y(qn(o,Ar,y(lo+(zh?Wn:Qe)),Tu,B))-lo),Lt&T){q=Hr;do{ae=n[(n[Lo>>2]|0)+(q<<2)>>2]|0;do if((n[ae+36>>2]|0)!=1){if((n[ae+24>>2]|0)==1){if(ha(ae,Ar)|0){if(zt=y(zA(ae,Ar,Wn)),zt=y(zt+y(vr(o,Ar))),zt=y(zt+y(K(ae,Ar,Nr))),L=n[Rf>>2]|0,h[ae+400+(L<<2)>>2]=zt,!(Mt(zt)|0))break}else L=n[Rf>>2]|0;zt=y(vr(o,Ar)),h[ae+400+(L<<2)>>2]=y(zt+y(K(ae,Ar,Nr)));break}L=os(o,ae)|0;do if((L|0)==4){if((n[(kl(ae,Ar)|0)+4>>2]|0)==3){ln=139;break}if((n[(Ql(ae,Ar)|0)+4>>2]|0)==3){ln=139;break}if(io(ae,Ar,Wn)|0){l=Le;break}dp=n[ae+908+(n[gc>>2]<<2)>>2]|0,n[oo>>2]=dp,l=y(h[ae+396>>2]),Bi=Mt(l)|0,Qe=(n[S>>2]=dp,y(h[S>>2])),Bi?l=tt:(Tr=y(yn(ae,Ar,Nr)),zt=y(Qe/l),l=y(l*Qe),l=y(Tr+(ui?zt:l))),h[Ll>>2]=l,h[oo>>2]=y(y(yn(ae,Mr,Nr))+Qe),n[ma>>2]=1,n[mc>>2]=1,Cu(ae,Mr,cr,Nr,ma,oo),Cu(ae,Ar,Wn,Nr,mc,Ll),l=y(h[oo>>2]),Tr=y(h[Ll>>2]),zt=ui?l:Tr,l=ui?Tr:l,Bi=((Mt(zt)|0)^1)&1,xl(ae,zt,l,Us,Bi,((Mt(l)|0)^1)&1,Nr,No,1,3493,M)|0,l=Le}else ln=139;while(!1);e:do if((ln|0)==139){ln=0,l=y(Ze-y(XA(ae,Ar,Nr)));do if((n[(kl(ae,Ar)|0)+4>>2]|0)==3){if((n[(Ql(ae,Ar)|0)+4>>2]|0)!=3)break;l=y(Le+y($n(y(0),y(l*y(.5)))));break e}while(!1);if((n[(Ql(ae,Ar)|0)+4>>2]|0)==3){l=Le;break}if((n[(kl(ae,Ar)|0)+4>>2]|0)==3){l=y(Le+y($n(y(0),l)));break}switch(L|0){case 1:{l=Le;break e}case 2:{l=y(Le+y(l*y(.5)));break e}default:{l=y(Le+l);break e}}}while(!1);zt=y(Ms+l),Bi=ae+400+(n[Rf>>2]<<2)|0,h[Bi>>2]=y(zt+y(h[Bi>>2]))}while(!1);q=q+1|0}while((q|0)!=(fr|0))}if(Ms=y(Ms+tt),xu=y($n(xu,u)),m=Fo+1|0,fr>>>0>=co>>>0)break;l=cr,Hr=fr,Fo=m}do if(T){if(L=m>>>0>1,!L&&!(jL(o)|0))break;if(!(Mt(Wn)|0)){l=y(Wn-Ms);e:do switch(n[o+12>>2]|0){case 3:{Le=y(Le+l),He=y(0);break}case 2:{Le=y(Le+y(l*y(.5))),He=y(0);break}case 4:{Wn>Ms?He=y(l/y(m>>>0)):He=y(0);break}case 7:if(Wn>Ms){Le=y(Le+y(l/y(m<<1>>>0))),He=y(l/y(m>>>0)),He=L?He:y(0);break e}else{Le=y(Le+y(l*y(.5))),He=y(0);break e}case 6:{He=y(l/y(Fo>>>0)),He=Wn>Ms&L?He:y(0);break}default:He=y(0)}while(!1);if(m|0)for(Lt=1040+(Ar<<2)|0,Gr=976+(Ar<<2)|0,Ye=0,q=0;;){e:do if(q>>>0>>0)for(Qe=y(0),tt=y(0),l=y(0),ae=q;;){L=n[(n[Lo>>2]|0)+(ae<<2)>>2]|0;do if((n[L+36>>2]|0)!=1&&!(n[L+24>>2]|0)){if((n[L+940>>2]|0)!=(Ye|0))break e;if(qL(L,Ar)|0&&(zt=y(h[L+908+(n[Gr>>2]<<2)>>2]),l=y($n(l,y(zt+y(yn(L,Ar,Nr)))))),(os(o,L)|0)!=5)break;ao=y(Yg(L)),ao=y(ao+y(K(L,0,Nr))),zt=y(h[L+912>>2]),zt=y(y(zt+y(yn(L,0,Nr)))-ao),ao=y($n(tt,ao)),zt=y($n(Qe,zt)),Qe=zt,tt=ao,l=y($n(l,y(ao+zt)))}while(!1);if(L=ae+1|0,L>>>0>>0)ae=L;else{ae=L;break}}else tt=y(0),l=y(0),ae=q;while(!1);if(ct=y(He+l),u=Le,Le=y(Le+ct),q>>>0>>0){Ze=y(u+tt),L=q;do{q=n[(n[Lo>>2]|0)+(L<<2)>>2]|0;e:do if((n[q+36>>2]|0)!=1&&!(n[q+24>>2]|0))switch(os(o,q)|0){case 1:{zt=y(u+y(K(q,Ar,Nr))),h[q+400+(n[Lt>>2]<<2)>>2]=zt;break e}case 3:{zt=y(y(Le-y(re(q,Ar,Nr)))-y(h[q+908+(n[Gr>>2]<<2)>>2])),h[q+400+(n[Lt>>2]<<2)>>2]=zt;break e}case 2:{zt=y(u+y(y(ct-y(h[q+908+(n[Gr>>2]<<2)>>2]))*y(.5))),h[q+400+(n[Lt>>2]<<2)>>2]=zt;break e}case 4:{if(zt=y(u+y(K(q,Ar,Nr))),h[q+400+(n[Lt>>2]<<2)>>2]=zt,io(q,Ar,Wn)|0||(ui?(Qe=y(h[q+908>>2]),l=y(Qe+y(yn(q,Mr,Nr))),tt=ct):(tt=y(h[q+912>>2]),tt=y(tt+y(yn(q,Ar,Nr))),l=ct,Qe=y(h[q+908>>2])),mn(l,Qe)|0&&mn(tt,y(h[q+912>>2]))|0))break e;xl(q,l,tt,Us,1,1,Nr,No,1,3501,M)|0;break e}case 5:{h[q+404>>2]=y(y(Ze-y(Yg(q)))+y(zA(q,0,Wn)));break e}default:break e}while(!1);L=L+1|0}while((L|0)!=(ae|0))}if(Ye=Ye+1|0,(Ye|0)==(m|0))break;q=ae}}}while(!1);if(h[o+908>>2]=y(qn(o,2,ku,B,B)),h[o+912>>2]=y(qn(o,0,up,k,B)),yc|0&&(fp=n[o+32>>2]|0,Ap=(yc|0)==2,!(Ap&(fp|0)!=2))?Ap&(fp|0)==2&&(l=y(Qu+cr),l=y($n(y(pd(l,y(Vg(o,Mr,xu,Oo)))),Qu)),ln=198):(l=y(qn(o,Mr,xu,Oo,B)),ln=198),(ln|0)==198&&(h[o+908+(n[976+(Mr<<2)>>2]<<2)>>2]=l),Ec|0&&(hp=n[o+32>>2]|0,gp=(Ec|0)==2,!(gp&(hp|0)!=2))?gp&(hp|0)==2&&(l=y(lo+Wn),l=y($n(y(pd(l,y(Vg(o,Ar,y(lo+Ms),Tu)))),lo)),ln=204):(l=y(qn(o,Ar,y(lo+Ms),Tu,B)),ln=204),(ln|0)==204&&(h[o+908+(n[976+(Ar<<2)>>2]<<2)>>2]=l),T){if((n[pp>>2]|0)==2){q=976+(Ar<<2)|0,ae=1040+(Ar<<2)|0,L=0;do Ye=Is(o,L)|0,n[Ye+24>>2]|0||(dp=n[q>>2]|0,zt=y(h[o+908+(dp<<2)>>2]),Bi=Ye+400+(n[ae>>2]<<2)|0,zt=y(zt-y(h[Bi>>2])),h[Bi>>2]=y(zt-y(h[Ye+908+(dp<<2)>>2]))),L=L+1|0;while((L|0)!=(co|0))}if(A|0){L=ui?yc:d;do WL(o,A,Nr,L,No,Us,M),A=n[A+960>>2]|0;while(A|0)}if(L=(Mr|2|0)==3,q=(Ar|2|0)==3,L|q){A=0;do ae=n[(n[Lo>>2]|0)+(A<<2)>>2]|0,(n[ae+36>>2]|0)!=1&&(L&&i2(o,ae,Mr),q&&i2(o,ae,Ar)),A=A+1|0;while((A|0)!=(co|0))}}}while(!1);I=Ic}function Dh(o,l){o=o|0,l=y(l);var u=0;Ha(o,l>=y(0),3147),u=l==y(0),h[o+4>>2]=u?y(0):l}function YA(o,l,u,A){o=o|0,l=y(l),u=y(u),A=A|0;var d=$e,m=$e,B=0,k=0,T=0;n[2278]=(n[2278]|0)+1,vf(o),io(o,2,l)|0?(d=y(Zr(n[o+992>>2]|0,l)),T=1,d=y(d+y(yn(o,2,l)))):(d=y(Zr(o+380|0,l)),d>=y(0)?T=2:(T=((Mt(l)|0)^1)&1,d=l)),io(o,0,u)|0?(m=y(Zr(n[o+996>>2]|0,u)),k=1,m=y(m+y(yn(o,0,l)))):(m=y(Zr(o+388|0,u)),m>=y(0)?k=2:(k=((Mt(u)|0)^1)&1,m=u)),B=o+976|0,xl(o,d,m,A,T,k,l,u,1,3189,n[B>>2]|0)|0&&(bh(o,n[o+496>>2]|0,l,u,l),VA(o,y(h[(n[B>>2]|0)+4>>2]),y(0),y(0)),s[11696]|0)&&Gg(o,7)}function vf(o){o=o|0;var l=0,u=0,A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0;k=I,I=I+32|0,B=k+24|0,m=k+16|0,A=k+8|0,d=k,u=0;do l=o+380+(u<<3)|0,n[o+380+(u<<3)+4>>2]|0&&(T=l,M=n[T+4>>2]|0,L=A,n[L>>2]=n[T>>2],n[L+4>>2]=M,L=o+364+(u<<3)|0,M=n[L+4>>2]|0,T=d,n[T>>2]=n[L>>2],n[T+4>>2]=M,n[m>>2]=n[A>>2],n[m+4>>2]=n[A+4>>2],n[B>>2]=n[d>>2],n[B+4>>2]=n[d+4>>2],Cf(m,B)|0)||(l=o+348+(u<<3)|0),n[o+992+(u<<2)>>2]=l,u=u+1|0;while((u|0)!=2);I=k}function io(o,l,u){o=o|0,l=l|0,u=y(u);var A=0;switch(o=n[o+992+(n[976+(l<<2)>>2]<<2)>>2]|0,n[o+4>>2]|0){case 0:case 3:{o=0;break}case 1:{y(h[o>>2])>2])>2]|0){case 2:{l=y(y(y(h[o>>2])*l)/y(100));break}case 1:{l=y(h[o>>2]);break}default:l=y(le)}return y(l)}function bh(o,l,u,A,d){o=o|0,l=l|0,u=y(u),A=y(A),d=y(d);var m=0,B=$e;l=n[o+944>>2]|0?l:1,m=dr(n[o+4>>2]|0,l)|0,l=by(m,l)|0,u=y(uP(o,m,u)),A=y(uP(o,l,A)),B=y(u+y(K(o,m,d))),h[o+400+(n[1040+(m<<2)>>2]<<2)>>2]=B,u=y(u+y(re(o,m,d))),h[o+400+(n[1e3+(m<<2)>>2]<<2)>>2]=u,u=y(A+y(K(o,l,d))),h[o+400+(n[1040+(l<<2)>>2]<<2)>>2]=u,d=y(A+y(re(o,l,d))),h[o+400+(n[1e3+(l<<2)>>2]<<2)>>2]=d}function VA(o,l,u,A){o=o|0,l=y(l),u=y(u),A=y(A);var d=0,m=0,B=$e,k=$e,T=0,M=0,L=$e,q=0,ae=$e,Ye=$e,Le=$e,Qe=$e;if(l!=y(0)&&(d=o+400|0,Qe=y(h[d>>2]),m=o+404|0,Le=y(h[m>>2]),q=o+416|0,Ye=y(h[q>>2]),M=o+420|0,B=y(h[M>>2]),ae=y(Qe+u),L=y(Le+A),A=y(ae+Ye),k=y(L+B),T=(n[o+988>>2]|0)==1,h[d>>2]=y(ss(Qe,l,0,T)),h[m>>2]=y(ss(Le,l,0,T)),u=y(uU(y(Ye*l),y(1))),mn(u,y(0))|0?m=0:m=(mn(u,y(1))|0)^1,u=y(uU(y(B*l),y(1))),mn(u,y(0))|0?d=0:d=(mn(u,y(1))|0)^1,Qe=y(ss(A,l,T&m,T&(m^1))),h[q>>2]=y(Qe-y(ss(ae,l,0,T))),Qe=y(ss(k,l,T&d,T&(d^1))),h[M>>2]=y(Qe-y(ss(L,l,0,T))),m=(n[o+952>>2]|0)-(n[o+948>>2]|0)>>2,m|0)){d=0;do VA(Is(o,d)|0,l,ae,L),d=d+1|0;while((d|0)!=(m|0))}}function Sy(o,l,u,A,d){switch(o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,u|0){case 5:case 0:{o=IZ(n[489]|0,A,d)|0;break}default:o=b6e(A,d)|0}return o|0}function Wg(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0;d=I,I=I+16|0,m=d,n[m>>2]=A,Ph(o,0,l,u,m),I=d}function Ph(o,l,u,A,d){if(o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,o=o|0?o:956,HZ[n[o+8>>2]&1](o,l,u,A,d)|0,(u|0)==5)Nt();else return}function pc(o,l,u){o=o|0,l=l|0,u=u|0,s[o+l>>0]=u&1}function Dy(o,l){o=o|0,l=l|0;var u=0,A=0;n[o>>2]=0,n[o+4>>2]=0,n[o+8>>2]=0,u=l+4|0,A=(n[u>>2]|0)-(n[l>>2]|0)>>2,A|0&&(xh(o,A),kt(o,n[l>>2]|0,n[u>>2]|0,A))}function xh(o,l){o=o|0,l=l|0;var u=0;if((O(o)|0)>>>0>>0&&an(o),l>>>0>1073741823)Nt();else{u=Kt(l<<2)|0,n[o+4>>2]=u,n[o>>2]=u,n[o+8>>2]=u+(l<<2);return}}function kt(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0,A=o+4|0,o=u-l|0,(o|0)>0&&(Qr(n[A>>2]|0,l|0,o|0)|0,n[A>>2]=(n[A>>2]|0)+(o>>>2<<2))}function O(o){return o=o|0,1073741823}function K(o,l,u){return o=o|0,l=l|0,u=y(u),de(l)|0&&n[o+96>>2]|0?o=o+92|0:o=kn(o+60|0,n[1040+(l<<2)>>2]|0,992)|0,y(Je(o,u))}function re(o,l,u){return o=o|0,l=l|0,u=y(u),de(l)|0&&n[o+104>>2]|0?o=o+100|0:o=kn(o+60|0,n[1e3+(l<<2)>>2]|0,992)|0,y(Je(o,u))}function de(o){return o=o|0,(o|1|0)==3|0}function Je(o,l){return o=o|0,l=y(l),(n[o+4>>2]|0)==3?l=y(0):l=y(Zr(o,l)),y(l)}function At(o,l){return o=o|0,l=l|0,o=n[o>>2]|0,(o|0?o:(l|0)>1?l:1)|0}function dr(o,l){o=o|0,l=l|0;var u=0;e:do if((l|0)==2){switch(o|0){case 2:{o=3;break e}case 3:break;default:{u=4;break e}}o=2}else u=4;while(!1);return o|0}function vr(o,l){o=o|0,l=l|0;var u=$e;return de(l)|0&&n[o+312>>2]|0&&(u=y(h[o+308>>2]),u>=y(0))||(u=y($n(y(h[(kn(o+276|0,n[1040+(l<<2)>>2]|0,992)|0)>>2]),y(0)))),y(u)}function Un(o,l){o=o|0,l=l|0;var u=$e;return de(l)|0&&n[o+320>>2]|0&&(u=y(h[o+316>>2]),u>=y(0))||(u=y($n(y(h[(kn(o+276|0,n[1e3+(l<<2)>>2]|0,992)|0)>>2]),y(0)))),y(u)}function mi(o,l,u){o=o|0,l=l|0,u=y(u);var A=$e;return de(l)|0&&n[o+240>>2]|0&&(A=y(Zr(o+236|0,u)),A>=y(0))||(A=y($n(y(Zr(kn(o+204|0,n[1040+(l<<2)>>2]|0,992)|0,u)),y(0)))),y(A)}function Cs(o,l,u){o=o|0,l=l|0,u=y(u);var A=$e;return de(l)|0&&n[o+248>>2]|0&&(A=y(Zr(o+244|0,u)),A>=y(0))||(A=y($n(y(Zr(kn(o+204|0,n[1e3+(l<<2)>>2]|0,992)|0,u)),y(0)))),y(A)}function JA(o,l,u,A,d,m,B){o=o|0,l=y(l),u=y(u),A=A|0,d=d|0,m=y(m),B=y(B);var k=$e,T=$e,M=$e,L=$e,q=$e,ae=$e,Ye=0,Le=0,Qe=0;Qe=I,I=I+16|0,Ye=Qe,Le=o+964|0,wi(o,(n[Le>>2]|0)!=0,3519),k=y(Va(o,2,l)),T=y(Va(o,0,l)),M=y(yn(o,2,l)),L=y(yn(o,0,l)),Mt(l)|0?q=l:q=y($n(y(0),y(y(l-M)-k))),Mt(u)|0?ae=u:ae=y($n(y(0),y(y(u-L)-T))),(A|0)==1&(d|0)==1?(h[o+908>>2]=y(qn(o,2,y(l-M),m,m)),l=y(qn(o,0,y(u-L),B,m))):(jZ[n[Le>>2]&1](Ye,o,q,A,ae,d),q=y(k+y(h[Ye>>2])),ae=y(l-M),h[o+908>>2]=y(qn(o,2,(A|2|0)==2?q:ae,m,m)),ae=y(T+y(h[Ye+4>>2])),l=y(u-L),l=y(qn(o,0,(d|2|0)==2?ae:l,B,m))),h[o+912>>2]=l,I=Qe}function lP(o,l,u,A,d,m,B){o=o|0,l=y(l),u=y(u),A=A|0,d=d|0,m=y(m),B=y(B);var k=$e,T=$e,M=$e,L=$e;M=y(Va(o,2,m)),k=y(Va(o,0,m)),L=y(yn(o,2,m)),T=y(yn(o,0,m)),l=y(l-L),h[o+908>>2]=y(qn(o,2,(A|2|0)==2?M:l,m,m)),u=y(u-T),h[o+912>>2]=y(qn(o,0,(d|2|0)==2?k:u,B,m))}function t2(o,l,u,A,d,m,B){o=o|0,l=y(l),u=y(u),A=A|0,d=d|0,m=y(m),B=y(B);var k=0,T=$e,M=$e;return k=(A|0)==2,!(l<=y(0)&k)&&!(u<=y(0)&(d|0)==2)&&!((A|0)==1&(d|0)==1)?o=0:(T=y(yn(o,0,m)),M=y(yn(o,2,m)),k=l>2]=y(qn(o,2,k?y(0):l,m,m)),l=y(u-T),k=u>2]=y(qn(o,0,k?y(0):l,B,m)),o=1),o|0}function by(o,l){return o=o|0,l=l|0,Jg(o)|0?o=dr(2,l)|0:o=0,o|0}function kh(o,l,u){return o=o|0,l=l|0,u=y(u),u=y(mi(o,l,u)),y(u+y(vr(o,l)))}function r2(o,l,u){return o=o|0,l=l|0,u=y(u),u=y(Cs(o,l,u)),y(u+y(Un(o,l)))}function Va(o,l,u){o=o|0,l=l|0,u=y(u);var A=$e;return A=y(kh(o,l,u)),y(A+y(r2(o,l,u)))}function n2(o){return o=o|0,n[o+24>>2]|0?o=0:y(KA(o))!=y(0)?o=1:o=y(Qh(o))!=y(0),o|0}function KA(o){o=o|0;var l=$e;if(n[o+944>>2]|0){if(l=y(h[o+44>>2]),Mt(l)|0)return l=y(h[o+40>>2]),o=l>y(0)&((Mt(l)|0)^1),y(o?l:y(0))}else l=y(0);return y(l)}function Qh(o){o=o|0;var l=$e,u=0,A=$e;do if(n[o+944>>2]|0){if(l=y(h[o+48>>2]),Mt(l)|0){if(u=s[(n[o+976>>2]|0)+2>>0]|0,!(u<<24>>24)&&(A=y(h[o+40>>2]),A>24?y(1):y(0)}}else l=y(0);while(!1);return y(l)}function Py(o){o=o|0;var l=0,u=0;if(eE(o+400|0,0,540)|0,s[o+985>>0]=1,te(o),u=Mi(o)|0,u|0){l=o+948|0,o=0;do Py(n[(n[l>>2]|0)+(o<<2)>>2]|0),o=o+1|0;while((o|0)!=(u|0))}}function cP(o,l,u,A,d,m,B,k,T,M){o=o|0,l=l|0,u=y(u),A=A|0,d=y(d),m=y(m),B=y(B),k=k|0,T=T|0,M=M|0;var L=0,q=$e,ae=0,Ye=0,Le=$e,Qe=$e,tt=0,Ze=$e,ct=0,He=$e,We=0,Lt=0,Gr=0,fr=0,$t=0,Tr=0,Hr=0,cr=0,Hn=0,To=0;Hn=I,I=I+16|0,Gr=Hn+12|0,fr=Hn+8|0,$t=Hn+4|0,Tr=Hn,cr=dr(n[o+4>>2]|0,T)|0,We=de(cr)|0,q=y(Zr(YL(l)|0,We?m:B)),Lt=io(l,2,m)|0,Hr=io(l,0,B)|0;do if(!(Mt(q)|0)&&!(Mt(We?u:d)|0)){if(L=l+504|0,!(Mt(y(h[L>>2]))|0)&&(!(s2(n[l+976>>2]|0,0)|0)||(n[l+500>>2]|0)==(n[2278]|0)))break;h[L>>2]=y($n(q,y(Va(l,cr,m))))}else ae=7;while(!1);do if((ae|0)==7){if(ct=We^1,!(ct|Lt^1)){B=y(Zr(n[l+992>>2]|0,m)),h[l+504>>2]=y($n(B,y(Va(l,2,m))));break}if(!(We|Hr^1)){B=y(Zr(n[l+996>>2]|0,B)),h[l+504>>2]=y($n(B,y(Va(l,0,m))));break}h[Gr>>2]=y(le),h[fr>>2]=y(le),n[$t>>2]=0,n[Tr>>2]=0,Ze=y(yn(l,2,m)),He=y(yn(l,0,m)),Lt?(Le=y(Ze+y(Zr(n[l+992>>2]|0,m))),h[Gr>>2]=Le,n[$t>>2]=1,Ye=1):(Ye=0,Le=y(le)),Hr?(q=y(He+y(Zr(n[l+996>>2]|0,B))),h[fr>>2]=q,n[Tr>>2]=1,L=1):(L=0,q=y(le)),ae=n[o+32>>2]|0,We&(ae|0)==2?ae=2:Mt(Le)|0&&!(Mt(u)|0)&&(h[Gr>>2]=u,n[$t>>2]=2,Ye=2,Le=u),!((ae|0)==2&ct)&&Mt(q)|0&&!(Mt(d)|0)&&(h[fr>>2]=d,n[Tr>>2]=2,L=2,q=d),Qe=y(h[l+396>>2]),tt=Mt(Qe)|0;do if(tt)ae=Ye;else{if((Ye|0)==1&ct){h[fr>>2]=y(y(Le-Ze)/Qe),n[Tr>>2]=1,L=1,ae=1;break}We&(L|0)==1?(h[Gr>>2]=y(Qe*y(q-He)),n[$t>>2]=1,L=1,ae=1):ae=Ye}while(!1);To=Mt(u)|0,Ye=(os(o,l)|0)!=4,!(We|Lt|((A|0)!=1|To)|(Ye|(ae|0)==1))&&(h[Gr>>2]=u,n[$t>>2]=1,!tt)&&(h[fr>>2]=y(y(u-Ze)/Qe),n[Tr>>2]=1,L=1),!(Hr|ct|((k|0)!=1|(Mt(d)|0))|(Ye|(L|0)==1))&&(h[fr>>2]=d,n[Tr>>2]=1,!tt)&&(h[Gr>>2]=y(Qe*y(d-He)),n[$t>>2]=1),Cu(l,2,m,m,$t,Gr),Cu(l,0,B,m,Tr,fr),u=y(h[Gr>>2]),d=y(h[fr>>2]),xl(l,u,d,T,n[$t>>2]|0,n[Tr>>2]|0,m,B,0,3565,M)|0,B=y(h[l+908+(n[976+(cr<<2)>>2]<<2)>>2]),h[l+504>>2]=y($n(B,y(Va(l,cr,m))))}while(!1);n[l+500>>2]=n[2278],I=Hn}function qn(o,l,u,A,d){return o=o|0,l=l|0,u=y(u),A=y(A),d=y(d),A=y(Vg(o,l,u,A)),y($n(A,y(Va(o,l,d))))}function os(o,l){return o=o|0,l=l|0,l=l+20|0,l=n[(n[l>>2]|0?l:o+16|0)>>2]|0,(l|0)==5&&Jg(n[o+4>>2]|0)|0&&(l=1),l|0}function kl(o,l){return o=o|0,l=l|0,de(l)|0&&n[o+96>>2]|0?l=4:l=n[1040+(l<<2)>>2]|0,o+60+(l<<3)|0}function Ql(o,l){return o=o|0,l=l|0,de(l)|0&&n[o+104>>2]|0?l=5:l=n[1e3+(l<<2)>>2]|0,o+60+(l<<3)|0}function Cu(o,l,u,A,d,m){switch(o=o|0,l=l|0,u=y(u),A=y(A),d=d|0,m=m|0,u=y(Zr(o+380+(n[976+(l<<2)>>2]<<3)|0,u)),u=y(u+y(yn(o,l,A))),n[d>>2]|0){case 2:case 1:{d=Mt(u)|0,A=y(h[m>>2]),h[m>>2]=d|A>2]=2,h[m>>2]=u);break}default:}}function ha(o,l){return o=o|0,l=l|0,o=o+132|0,de(l)|0&&n[(kn(o,4,948)|0)+4>>2]|0?o=1:o=(n[(kn(o,n[1040+(l<<2)>>2]|0,948)|0)+4>>2]|0)!=0,o|0}function zA(o,l,u){o=o|0,l=l|0,u=y(u);var A=0,d=0;return o=o+132|0,de(l)|0&&(A=kn(o,4,948)|0,(n[A+4>>2]|0)!=0)?d=4:(A=kn(o,n[1040+(l<<2)>>2]|0,948)|0,n[A+4>>2]|0?d=4:u=y(0)),(d|0)==4&&(u=y(Zr(A,u))),y(u)}function XA(o,l,u){o=o|0,l=l|0,u=y(u);var A=$e;return A=y(h[o+908+(n[976+(l<<2)>>2]<<2)>>2]),A=y(A+y(K(o,l,u))),y(A+y(re(o,l,u)))}function jL(o){o=o|0;var l=0,u=0,A=0;e:do if(Jg(n[o+4>>2]|0)|0)l=0;else if((n[o+16>>2]|0)!=5)if(u=Mi(o)|0,!u)l=0;else for(l=0;;){if(A=Is(o,l)|0,!(n[A+24>>2]|0)&&(n[A+20>>2]|0)==5){l=1;break e}if(l=l+1|0,l>>>0>=u>>>0){l=0;break}}else l=1;while(!1);return l|0}function qL(o,l){o=o|0,l=l|0;var u=$e;return u=y(h[o+908+(n[976+(l<<2)>>2]<<2)>>2]),u>=y(0)&((Mt(u)|0)^1)|0}function Yg(o){o=o|0;var l=$e,u=0,A=0,d=0,m=0,B=0,k=0,T=$e;if(u=n[o+968>>2]|0,u)T=y(h[o+908>>2]),l=y(h[o+912>>2]),l=y(LZ[u&0](o,T,l)),wi(o,(Mt(l)|0)^1,3573);else{m=Mi(o)|0;do if(m|0){for(u=0,d=0;;){if(A=Is(o,d)|0,n[A+940>>2]|0){B=8;break}if((n[A+24>>2]|0)!=1)if(k=(os(o,A)|0)==5,k){u=A;break}else u=u|0?u:A;if(d=d+1|0,d>>>0>=m>>>0){B=8;break}}if((B|0)==8&&!u)break;return l=y(Yg(u)),y(l+y(h[u+404>>2]))}while(!1);l=y(h[o+912>>2])}return y(l)}function Vg(o,l,u,A){o=o|0,l=l|0,u=y(u),A=y(A);var d=$e,m=0;return Jg(l)|0?(l=1,m=3):de(l)|0?(l=0,m=3):(A=y(le),d=y(le)),(m|0)==3&&(d=y(Zr(o+364+(l<<3)|0,A)),A=y(Zr(o+380+(l<<3)|0,A))),m=A=y(0)&((Mt(A)|0)^1)),u=m?A:u,m=d>=y(0)&((Mt(d)|0)^1)&u>2]|0,m)|0,Le=by(tt,m)|0,Qe=de(tt)|0,q=y(yn(l,2,u)),ae=y(yn(l,0,u)),io(l,2,u)|0?k=y(q+y(Zr(n[l+992>>2]|0,u))):ha(l,2)|0&&xy(l,2)|0?(k=y(h[o+908>>2]),T=y(vr(o,2)),T=y(k-y(T+y(Un(o,2)))),k=y(zA(l,2,u)),k=y(qn(l,2,y(T-y(k+y(Th(l,2,u)))),u,u))):k=y(le),io(l,0,d)|0?T=y(ae+y(Zr(n[l+996>>2]|0,d))):ha(l,0)|0&&xy(l,0)|0?(T=y(h[o+912>>2]),ct=y(vr(o,0)),ct=y(T-y(ct+y(Un(o,0)))),T=y(zA(l,0,d)),T=y(qn(l,0,y(ct-y(T+y(Th(l,0,d)))),d,u))):T=y(le),M=Mt(k)|0,L=Mt(T)|0;do if(M^L&&(Ye=y(h[l+396>>2]),!(Mt(Ye)|0)))if(M){k=y(q+y(y(T-ae)*Ye));break}else{ct=y(ae+y(y(k-q)/Ye)),T=L?ct:T;break}while(!1);L=Mt(k)|0,M=Mt(T)|0,L|M&&(He=(L^1)&1,A=u>y(0)&((A|0)!=0&L),k=Qe?k:A?u:k,xl(l,k,T,m,Qe?He:A?2:He,L&(M^1)&1,k,T,0,3623,B)|0,k=y(h[l+908>>2]),k=y(k+y(yn(l,2,u))),T=y(h[l+912>>2]),T=y(T+y(yn(l,0,u)))),xl(l,k,T,m,1,1,k,T,1,3635,B)|0,xy(l,tt)|0&&!(ha(l,tt)|0)?(He=n[976+(tt<<2)>>2]|0,ct=y(h[o+908+(He<<2)>>2]),ct=y(ct-y(h[l+908+(He<<2)>>2])),ct=y(ct-y(Un(o,tt))),ct=y(ct-y(re(l,tt,u))),ct=y(ct-y(Th(l,tt,Qe?u:d))),h[l+400+(n[1040+(tt<<2)>>2]<<2)>>2]=ct):Ze=21;do if((Ze|0)==21){if(!(ha(l,tt)|0)&&(n[o+8>>2]|0)==1){He=n[976+(tt<<2)>>2]|0,ct=y(h[o+908+(He<<2)>>2]),ct=y(y(ct-y(h[l+908+(He<<2)>>2]))*y(.5)),h[l+400+(n[1040+(tt<<2)>>2]<<2)>>2]=ct;break}!(ha(l,tt)|0)&&(n[o+8>>2]|0)==2&&(He=n[976+(tt<<2)>>2]|0,ct=y(h[o+908+(He<<2)>>2]),ct=y(ct-y(h[l+908+(He<<2)>>2])),h[l+400+(n[1040+(tt<<2)>>2]<<2)>>2]=ct)}while(!1);xy(l,Le)|0&&!(ha(l,Le)|0)?(He=n[976+(Le<<2)>>2]|0,ct=y(h[o+908+(He<<2)>>2]),ct=y(ct-y(h[l+908+(He<<2)>>2])),ct=y(ct-y(Un(o,Le))),ct=y(ct-y(re(l,Le,u))),ct=y(ct-y(Th(l,Le,Qe?d:u))),h[l+400+(n[1040+(Le<<2)>>2]<<2)>>2]=ct):Ze=30;do if((Ze|0)==30&&!(ha(l,Le)|0)){if((os(o,l)|0)==2){He=n[976+(Le<<2)>>2]|0,ct=y(h[o+908+(He<<2)>>2]),ct=y(y(ct-y(h[l+908+(He<<2)>>2]))*y(.5)),h[l+400+(n[1040+(Le<<2)>>2]<<2)>>2]=ct;break}He=(os(o,l)|0)==3,He^(n[o+28>>2]|0)==2&&(He=n[976+(Le<<2)>>2]|0,ct=y(h[o+908+(He<<2)>>2]),ct=y(ct-y(h[l+908+(He<<2)>>2])),h[l+400+(n[1040+(Le<<2)>>2]<<2)>>2]=ct)}while(!1)}function i2(o,l,u){o=o|0,l=l|0,u=u|0;var A=$e,d=0;d=n[976+(u<<2)>>2]|0,A=y(h[l+908+(d<<2)>>2]),A=y(y(h[o+908+(d<<2)>>2])-A),A=y(A-y(h[l+400+(n[1040+(u<<2)>>2]<<2)>>2])),h[l+400+(n[1e3+(u<<2)>>2]<<2)>>2]=A}function Jg(o){return o=o|0,(o|1|0)==1|0}function YL(o){o=o|0;var l=$e;switch(n[o+56>>2]|0){case 0:case 3:{l=y(h[o+40>>2]),l>y(0)&((Mt(l)|0)^1)?o=s[(n[o+976>>2]|0)+2>>0]|0?1056:992:o=1056;break}default:o=o+52|0}return o|0}function s2(o,l){return o=o|0,l=l|0,(s[o+l>>0]|0)!=0|0}function xy(o,l){return o=o|0,l=l|0,o=o+132|0,de(l)|0&&n[(kn(o,5,948)|0)+4>>2]|0?o=1:o=(n[(kn(o,n[1e3+(l<<2)>>2]|0,948)|0)+4>>2]|0)!=0,o|0}function Th(o,l,u){o=o|0,l=l|0,u=y(u);var A=0,d=0;return o=o+132|0,de(l)|0&&(A=kn(o,5,948)|0,(n[A+4>>2]|0)!=0)?d=4:(A=kn(o,n[1e3+(l<<2)>>2]|0,948)|0,n[A+4>>2]|0?d=4:u=y(0)),(d|0)==4&&(u=y(Zr(A,u))),y(u)}function uP(o,l,u){return o=o|0,l=l|0,u=y(u),ha(o,l)|0?u=y(zA(o,l,u)):u=y(-y(Th(o,l,u))),y(u)}function fP(o){return o=y(o),h[S>>2]=o,n[S>>2]|0|0}function ky(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>1073741823)Nt();else{d=Kt(l<<2)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u<<2)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l<<2)}function AP(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(0-(d>>2)<<2)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function Qy(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~((A+-4-l|0)>>>2)<<2)),o=n[o>>2]|0,o|0&&It(o)}function pP(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0;if(B=o+4|0,k=n[B>>2]|0,d=k-A|0,m=d>>2,o=l+(m<<2)|0,o>>>0>>0){A=k;do n[A>>2]=n[o>>2],o=o+4|0,A=(n[B>>2]|0)+4|0,n[B>>2]=A;while(o>>>0>>0)}m|0&&Q2(k+(0-m<<2)|0,l|0,d|0)|0}function hP(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0;return k=l+4|0,T=n[k>>2]|0,d=n[o>>2]|0,B=u,m=B-d|0,A=T+(0-(m>>2)<<2)|0,n[k>>2]=A,(m|0)>0&&Qr(A|0,d|0,m|0)|0,d=o+4|0,m=l+8|0,A=(n[d>>2]|0)-B|0,(A|0)>0&&(Qr(n[m>>2]|0,u|0,A|0)|0,n[m>>2]=(n[m>>2]|0)+(A>>>2<<2)),B=n[o>>2]|0,n[o>>2]=n[k>>2],n[k>>2]=B,B=n[d>>2]|0,n[d>>2]=n[m>>2],n[m>>2]=B,B=o+8|0,u=l+12|0,o=n[B>>2]|0,n[B>>2]=n[u>>2],n[u>>2]=o,n[l>>2]=n[k>>2],T|0}function o2(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;if(B=n[l>>2]|0,m=n[u>>2]|0,(B|0)!=(m|0)){d=o+8|0,u=((m+-4-B|0)>>>2)+1|0,o=B,A=n[d>>2]|0;do n[A>>2]=n[o>>2],A=(n[d>>2]|0)+4|0,n[d>>2]=A,o=o+4|0;while((o|0)!=(m|0));n[l>>2]=B+(u<<2)}}function a2(){ua()}function gP(){var o=0;return o=Kt(4)|0,l2(o),o|0}function l2(o){o=o|0,n[o>>2]=Ac()|0}function dP(o){o=o|0,o|0&&(Kg(o),It(o))}function Kg(o){o=o|0,st(n[o>>2]|0)}function VL(o,l,u){o=o|0,l=l|0,u=u|0,pc(n[o>>2]|0,l,u)}function Ty(o,l){o=o|0,l=y(l),Dh(n[o>>2]|0,l)}function Ry(o,l){return o=o|0,l=l|0,s2(n[o>>2]|0,l)|0}function Fy(){var o=0;return o=Kt(8)|0,zg(o,0),o|0}function zg(o,l){o=o|0,l=l|0,l?l=fa(n[l>>2]|0)|0:l=ns()|0,n[o>>2]=l,n[o+4>>2]=0,Tn(l,o)}function Ny(o){o=o|0;var l=0;return l=Kt(8)|0,zg(l,o),l|0}function Xg(o){o=o|0,o|0&&(Oy(o),It(o))}function Oy(o){o=o|0;var l=0;uc(n[o>>2]|0),l=o+4|0,o=n[l>>2]|0,n[l>>2]=0,o|0&&(Sf(o),It(o))}function Sf(o){o=o|0,Df(o)}function Df(o){o=o|0,o=n[o>>2]|0,o|0&&Na(o|0)}function c2(o){return o=o|0,Ga(o)|0}function u2(o){o=o|0;var l=0,u=0;u=o+4|0,l=n[u>>2]|0,n[u>>2]=0,l|0&&(Sf(l),It(l)),fc(n[o>>2]|0)}function Ly(o,l){o=o|0,l=l|0,An(n[o>>2]|0,n[l>>2]|0)}function JL(o,l){o=o|0,l=l|0,wh(n[o>>2]|0,l)}function KL(o,l,u){o=o|0,l=l|0,u=+u,Cy(n[o>>2]|0,l,y(u))}function My(o,l,u){o=o|0,l=l|0,u=+u,wy(n[o>>2]|0,l,y(u))}function f2(o,l){o=o|0,l=l|0,Eh(n[o>>2]|0,l)}function A2(o,l){o=o|0,l=l|0,So(n[o>>2]|0,l)}function xr(o,l){o=o|0,l=l|0,Ch(n[o>>2]|0,l)}function so(o,l){o=o|0,l=l|0,my(n[o>>2]|0,l)}function Xi(o,l){o=o|0,l=l|0,Ng(n[o>>2]|0,l)}function Ns(o,l){o=o|0,l=l|0,vo(n[o>>2]|0,l)}function ZA(o,l,u){o=o|0,l=l|0,u=+u,HA(n[o>>2]|0,l,y(u))}function p2(o,l,u){o=o|0,l=l|0,u=+u,Y(n[o>>2]|0,l,y(u))}function ws(o,l){o=o|0,l=l|0,jA(n[o>>2]|0,l)}function Uy(o,l){o=o|0,l=l|0,Ey(n[o>>2]|0,l)}function Rh(o,l){o=o|0,l=l|0,Do(n[o>>2]|0,l)}function Zg(o,l){o=o|0,l=+l,Bh(n[o>>2]|0,y(l))}function Fh(o,l){o=o|0,l=+l,bl(n[o>>2]|0,y(l))}function h2(o,l){o=o|0,l=+l,Iy(n[o>>2]|0,y(l))}function g2(o,l){o=o|0,l=+l,Lg(n[o>>2]|0,y(l))}function d2(o,l){o=o|0,l=+l,Dl(n[o>>2]|0,y(l))}function m2(o,l){o=o|0,l=+l,Mg(n[o>>2]|0,y(l))}function bf(o,l){o=o|0,l=+l,e2(n[o>>2]|0,y(l))}function sr(o){o=o|0,vh(n[o>>2]|0)}function _y(o,l){o=o|0,l=+l,zi(n[o>>2]|0,y(l))}function y2(o,l){o=o|0,l=+l,yf(n[o>>2]|0,y(l))}function hc(o){o=o|0,qa(n[o>>2]|0)}function Pf(o,l){o=o|0,l=+l,du(n[o>>2]|0,y(l))}function $g(o,l){o=o|0,l=+l,Ef(n[o>>2]|0,y(l))}function ed(o,l){o=o|0,l=+l,di(n[o>>2]|0,y(l))}function E2(o,l){o=o|0,l=+l,GA(n[o>>2]|0,y(l))}function I2(o,l){o=o|0,l=+l,Aa(n[o>>2]|0,y(l))}function wu(o,l){o=o|0,l=+l,Ya(n[o>>2]|0,y(l))}function td(o,l){o=o|0,l=+l,Sh(n[o>>2]|0,y(l))}function C2(o,l){o=o|0,l=+l,Hg(n[o>>2]|0,y(l))}function Hy(o,l){o=o|0,l=+l,qA(n[o>>2]|0,y(l))}function Bu(o,l,u){o=o|0,l=l|0,u=+u,gu(n[o>>2]|0,l,y(u))}function jy(o,l,u){o=o|0,l=l|0,u=+u,bo(n[o>>2]|0,l,y(u))}function rd(o,l,u){o=o|0,l=l|0,u=+u,mf(n[o>>2]|0,l,y(u))}function nd(o){return o=o|0,Fg(n[o>>2]|0)|0}function ko(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0;A=I,I=I+16|0,d=A,_A(d,n[l>>2]|0,u),Bs(o,d),I=A}function Bs(o,l){o=o|0,l=l|0,Tl(o,n[l+4>>2]|0,+y(h[l>>2]))}function Tl(o,l,u){o=o|0,l=l|0,u=+u,n[o>>2]=l,E[o+8>>3]=u}function Gy(o){return o=o|0,$1(n[o>>2]|0)|0}function ga(o){return o=o|0,Ih(n[o>>2]|0)|0}function mP(o){return o=o|0,hu(n[o>>2]|0)|0}function Nh(o){return o=o|0,Z1(n[o>>2]|0)|0}function w2(o){return o=o|0,Og(n[o>>2]|0)|0}function zL(o){return o=o|0,yy(n[o>>2]|0)|0}function yP(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0;A=I,I=I+16|0,d=A,xt(d,n[l>>2]|0,u),Bs(o,d),I=A}function EP(o){return o=o|0,df(n[o>>2]|0)|0}function qy(o){return o=o|0,Sl(n[o>>2]|0)|0}function B2(o,l){o=o|0,l=l|0;var u=0,A=0;u=I,I=I+16|0,A=u,UA(A,n[l>>2]|0),Bs(o,A),I=u}function Oh(o){return o=o|0,+ +y(li(n[o>>2]|0))}function IP(o){return o=o|0,+ +y(qi(n[o>>2]|0))}function CP(o,l){o=o|0,l=l|0;var u=0,A=0;u=I,I=I+16|0,A=u,ur(A,n[l>>2]|0),Bs(o,A),I=u}function id(o,l){o=o|0,l=l|0;var u=0,A=0;u=I,I=I+16|0,A=u,Ug(A,n[l>>2]|0),Bs(o,A),I=u}function XL(o,l){o=o|0,l=l|0;var u=0,A=0;u=I,I=I+16|0,A=u,wt(A,n[l>>2]|0),Bs(o,A),I=u}function ZL(o,l){o=o|0,l=l|0;var u=0,A=0;u=I,I=I+16|0,A=u,Wa(A,n[l>>2]|0),Bs(o,A),I=u}function wP(o,l){o=o|0,l=l|0;var u=0,A=0;u=I,I=I+16|0,A=u,_g(A,n[l>>2]|0),Bs(o,A),I=u}function BP(o,l){o=o|0,l=l|0;var u=0,A=0;u=I,I=I+16|0,A=u,vy(A,n[l>>2]|0),Bs(o,A),I=u}function $A(o){return o=o|0,+ +y(jg(n[o>>2]|0))}function $L(o,l){return o=o|0,l=l|0,+ +y(By(n[o>>2]|0,l))}function eM(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0;A=I,I=I+16|0,d=A,yt(d,n[l>>2]|0,u),Bs(o,d),I=A}function vu(o,l,u){o=o|0,l=l|0,u=u|0,lr(n[o>>2]|0,n[l>>2]|0,u)}function tM(o,l){o=o|0,l=l|0,gf(n[o>>2]|0,n[l>>2]|0)}function vP(o){return o=o|0,Mi(n[o>>2]|0)|0}function rM(o){return o=o|0,o=Et(n[o>>2]|0)|0,o?o=c2(o)|0:o=0,o|0}function SP(o,l){return o=o|0,l=l|0,o=Is(n[o>>2]|0,l)|0,o?o=c2(o)|0:o=0,o|0}function xf(o,l){o=o|0,l=l|0;var u=0,A=0;A=Kt(4)|0,DP(A,l),u=o+4|0,l=n[u>>2]|0,n[u>>2]=A,l|0&&(Sf(l),It(l)),St(n[o>>2]|0,1)}function DP(o,l){o=o|0,l=l|0,oM(o,l)}function nM(o,l,u,A,d,m){o=o|0,l=l|0,u=y(u),A=A|0,d=y(d),m=m|0;var B=0,k=0;B=I,I=I+16|0,k=B,bP(k,Ga(l)|0,+u,A,+d,m),h[o>>2]=y(+E[k>>3]),h[o+4>>2]=y(+E[k+8>>3]),I=B}function bP(o,l,u,A,d,m){o=o|0,l=l|0,u=+u,A=A|0,d=+d,m=m|0;var B=0,k=0,T=0,M=0,L=0;B=I,I=I+32|0,L=B+8|0,M=B+20|0,T=B,k=B+16|0,E[L>>3]=u,n[M>>2]=A,E[T>>3]=d,n[k>>2]=m,Wy(o,n[l+4>>2]|0,L,M,T,k),I=B}function Wy(o,l,u,A,d,m){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0;var B=0,k=0;B=I,I=I+16|0,k=B,Fl(k),l=Os(l)|0,PP(o,l,+E[u>>3],n[A>>2]|0,+E[d>>3],n[m>>2]|0),Nl(k),I=B}function Os(o){return o=o|0,n[o>>2]|0}function PP(o,l,u,A,d,m){o=o|0,l=l|0,u=+u,A=A|0,d=+d,m=m|0;var B=0;B=da(v2()|0)|0,u=+Ja(u),A=Yy(A)|0,d=+Ja(d),iM(o,Kn(0,B|0,l|0,+u,A|0,+d,Yy(m)|0)|0)}function v2(){var o=0;return s[7608]|0||(D2(9120),o=7608,n[o>>2]=1,n[o+4>>2]=0),9120}function da(o){return o=o|0,n[o+8>>2]|0}function Ja(o){return o=+o,+ +kf(o)}function Yy(o){return o=o|0,sd(o)|0}function iM(o,l){o=o|0,l=l|0;var u=0,A=0,d=0;d=I,I=I+32|0,u=d,A=l,A&1?(Ka(u,0),Me(A|0,u|0)|0,S2(o,u),sM(u)):(n[o>>2]=n[l>>2],n[o+4>>2]=n[l+4>>2],n[o+8>>2]=n[l+8>>2],n[o+12>>2]=n[l+12>>2]),I=d}function Ka(o,l){o=o|0,l=l|0,Su(o,l),n[o+8>>2]=0,s[o+24>>0]=0}function S2(o,l){o=o|0,l=l|0,l=l+8|0,n[o>>2]=n[l>>2],n[o+4>>2]=n[l+4>>2],n[o+8>>2]=n[l+8>>2],n[o+12>>2]=n[l+12>>2]}function sM(o){o=o|0,s[o+24>>0]=0}function Su(o,l){o=o|0,l=l|0,n[o>>2]=l}function sd(o){return o=o|0,o|0}function kf(o){return o=+o,+o}function D2(o){o=o|0,Qo(o,b2()|0,4)}function b2(){return 1064}function Qo(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,n[o+4>>2]=u,n[o+8>>2]=Gi(l|0,u+1|0)|0}function oM(o,l){o=o|0,l=l|0,l=n[l>>2]|0,n[o>>2]=l,au(l|0)}function xP(o){o=o|0;var l=0,u=0;u=o+4|0,l=n[u>>2]|0,n[u>>2]=0,l|0&&(Sf(l),It(l)),St(n[o>>2]|0,0)}function kP(o){o=o|0,bt(n[o>>2]|0)}function Vy(o){return o=o|0,tr(n[o>>2]|0)|0}function aM(o,l,u,A){o=o|0,l=+l,u=+u,A=A|0,YA(n[o>>2]|0,y(l),y(u),A)}function lM(o){return o=o|0,+ +y(mu(n[o>>2]|0))}function v(o){return o=o|0,+ +y(If(n[o>>2]|0))}function D(o){return o=o|0,+ +y(yu(n[o>>2]|0))}function Q(o){return o=o|0,+ +y(Rs(n[o>>2]|0))}function H(o){return o=o|0,+ +y(Eu(n[o>>2]|0))}function V(o){return o=o|0,+ +y(Gn(n[o>>2]|0))}function ne(o,l){o=o|0,l=l|0,E[o>>3]=+y(mu(n[l>>2]|0)),E[o+8>>3]=+y(If(n[l>>2]|0)),E[o+16>>3]=+y(yu(n[l>>2]|0)),E[o+24>>3]=+y(Rs(n[l>>2]|0)),E[o+32>>3]=+y(Eu(n[l>>2]|0)),E[o+40>>3]=+y(Gn(n[l>>2]|0))}function Se(o,l){return o=o|0,l=l|0,+ +y(is(n[o>>2]|0,l))}function _e(o,l){return o=o|0,l=l|0,+ +y(Pi(n[o>>2]|0,l))}function pt(o,l){return o=o|0,l=l|0,+ +y(WA(n[o>>2]|0,l))}function Wt(){return Qn()|0}function Sr(){Lr(),Zt(),zn(),yi(),za(),et()}function Lr(){p4e(11713,4938,1)}function Zt(){T_e(10448)}function zn(){p_e(10408)}function yi(){OUe(10324)}function za(){qLe(10096)}function et(){qe(9132)}function qe(o){o=o|0;var l=0,u=0,A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0,Ye=0,Le=0,Qe=0,tt=0,Ze=0,ct=0,He=0,We=0,Lt=0,Gr=0,fr=0,$t=0,Tr=0,Hr=0,cr=0,Hn=0,To=0,Ro=0,Fo=0,Za=0,Wh=0,Yh=0,gc=0,Vh=0,Rf=0,Ff=0,Jh=0,Kh=0,zh=0,ln=0,dc=0,Xh=0,Pu=0,Zh=0,$h=0,Nf=0,Of=0,xu=0,oo=0,Ll=0,ma=0,mc=0,op=0,ap=0,Lf=0,lp=0,cp=0,ao=0,Ms=0,yc=0,Wn=0,up=0,No=0,ku=0,Oo=0,Qu=0,fp=0,Ap=0,Tu=0,lo=0,Ec=0,pp=0,hp=0,gp=0,Nr=0,ui=0,Us=0,Lo=0,co=0,Mr=0,Ar=0,Ic=0;l=I,I=I+672|0,u=l+656|0,Ic=l+648|0,Ar=l+640|0,Mr=l+632|0,co=l+624|0,Lo=l+616|0,Us=l+608|0,ui=l+600|0,Nr=l+592|0,gp=l+584|0,hp=l+576|0,pp=l+568|0,Ec=l+560|0,lo=l+552|0,Tu=l+544|0,Ap=l+536|0,fp=l+528|0,Qu=l+520|0,Oo=l+512|0,ku=l+504|0,No=l+496|0,up=l+488|0,Wn=l+480|0,yc=l+472|0,Ms=l+464|0,ao=l+456|0,cp=l+448|0,lp=l+440|0,Lf=l+432|0,ap=l+424|0,op=l+416|0,mc=l+408|0,ma=l+400|0,Ll=l+392|0,oo=l+384|0,xu=l+376|0,Of=l+368|0,Nf=l+360|0,$h=l+352|0,Zh=l+344|0,Pu=l+336|0,Xh=l+328|0,dc=l+320|0,ln=l+312|0,zh=l+304|0,Kh=l+296|0,Jh=l+288|0,Ff=l+280|0,Rf=l+272|0,Vh=l+264|0,gc=l+256|0,Yh=l+248|0,Wh=l+240|0,Za=l+232|0,Fo=l+224|0,Ro=l+216|0,To=l+208|0,Hn=l+200|0,cr=l+192|0,Hr=l+184|0,Tr=l+176|0,$t=l+168|0,fr=l+160|0,Gr=l+152|0,Lt=l+144|0,We=l+136|0,He=l+128|0,ct=l+120|0,Ze=l+112|0,tt=l+104|0,Qe=l+96|0,Le=l+88|0,Ye=l+80|0,ae=l+72|0,q=l+64|0,L=l+56|0,M=l+48|0,T=l+40|0,k=l+32|0,B=l+24|0,m=l+16|0,d=l+8|0,A=l,gt(o,3646),Xt(o,3651,2)|0,Dr(o,3665,2)|0,Zn(o,3682,18)|0,n[Ic>>2]=19,n[Ic+4>>2]=0,n[u>>2]=n[Ic>>2],n[u+4>>2]=n[Ic+4>>2],kr(o,3690,u)|0,n[Ar>>2]=1,n[Ar+4>>2]=0,n[u>>2]=n[Ar>>2],n[u+4>>2]=n[Ar+4>>2],Rn(o,3696,u)|0,n[Mr>>2]=2,n[Mr+4>>2]=0,n[u>>2]=n[Mr>>2],n[u+4>>2]=n[Mr+4>>2],_n(o,3706,u)|0,n[co>>2]=1,n[co+4>>2]=0,n[u>>2]=n[co>>2],n[u+4>>2]=n[co+4>>2],zr(o,3722,u)|0,n[Lo>>2]=2,n[Lo+4>>2]=0,n[u>>2]=n[Lo>>2],n[u+4>>2]=n[Lo+4>>2],zr(o,3734,u)|0,n[Us>>2]=3,n[Us+4>>2]=0,n[u>>2]=n[Us>>2],n[u+4>>2]=n[Us+4>>2],_n(o,3753,u)|0,n[ui>>2]=4,n[ui+4>>2]=0,n[u>>2]=n[ui>>2],n[u+4>>2]=n[ui+4>>2],_n(o,3769,u)|0,n[Nr>>2]=5,n[Nr+4>>2]=0,n[u>>2]=n[Nr>>2],n[u+4>>2]=n[Nr+4>>2],_n(o,3783,u)|0,n[gp>>2]=6,n[gp+4>>2]=0,n[u>>2]=n[gp>>2],n[u+4>>2]=n[gp+4>>2],_n(o,3796,u)|0,n[hp>>2]=7,n[hp+4>>2]=0,n[u>>2]=n[hp>>2],n[u+4>>2]=n[hp+4>>2],_n(o,3813,u)|0,n[pp>>2]=8,n[pp+4>>2]=0,n[u>>2]=n[pp>>2],n[u+4>>2]=n[pp+4>>2],_n(o,3825,u)|0,n[Ec>>2]=3,n[Ec+4>>2]=0,n[u>>2]=n[Ec>>2],n[u+4>>2]=n[Ec+4>>2],zr(o,3843,u)|0,n[lo>>2]=4,n[lo+4>>2]=0,n[u>>2]=n[lo>>2],n[u+4>>2]=n[lo+4>>2],zr(o,3853,u)|0,n[Tu>>2]=9,n[Tu+4>>2]=0,n[u>>2]=n[Tu>>2],n[u+4>>2]=n[Tu+4>>2],_n(o,3870,u)|0,n[Ap>>2]=10,n[Ap+4>>2]=0,n[u>>2]=n[Ap>>2],n[u+4>>2]=n[Ap+4>>2],_n(o,3884,u)|0,n[fp>>2]=11,n[fp+4>>2]=0,n[u>>2]=n[fp>>2],n[u+4>>2]=n[fp+4>>2],_n(o,3896,u)|0,n[Qu>>2]=1,n[Qu+4>>2]=0,n[u>>2]=n[Qu>>2],n[u+4>>2]=n[Qu+4>>2],ci(o,3907,u)|0,n[Oo>>2]=2,n[Oo+4>>2]=0,n[u>>2]=n[Oo>>2],n[u+4>>2]=n[Oo+4>>2],ci(o,3915,u)|0,n[ku>>2]=3,n[ku+4>>2]=0,n[u>>2]=n[ku>>2],n[u+4>>2]=n[ku+4>>2],ci(o,3928,u)|0,n[No>>2]=4,n[No+4>>2]=0,n[u>>2]=n[No>>2],n[u+4>>2]=n[No+4>>2],ci(o,3948,u)|0,n[up>>2]=5,n[up+4>>2]=0,n[u>>2]=n[up>>2],n[u+4>>2]=n[up+4>>2],ci(o,3960,u)|0,n[Wn>>2]=6,n[Wn+4>>2]=0,n[u>>2]=n[Wn>>2],n[u+4>>2]=n[Wn+4>>2],ci(o,3974,u)|0,n[yc>>2]=7,n[yc+4>>2]=0,n[u>>2]=n[yc>>2],n[u+4>>2]=n[yc+4>>2],ci(o,3983,u)|0,n[Ms>>2]=20,n[Ms+4>>2]=0,n[u>>2]=n[Ms>>2],n[u+4>>2]=n[Ms+4>>2],kr(o,3999,u)|0,n[ao>>2]=8,n[ao+4>>2]=0,n[u>>2]=n[ao>>2],n[u+4>>2]=n[ao+4>>2],ci(o,4012,u)|0,n[cp>>2]=9,n[cp+4>>2]=0,n[u>>2]=n[cp>>2],n[u+4>>2]=n[cp+4>>2],ci(o,4022,u)|0,n[lp>>2]=21,n[lp+4>>2]=0,n[u>>2]=n[lp>>2],n[u+4>>2]=n[lp+4>>2],kr(o,4039,u)|0,n[Lf>>2]=10,n[Lf+4>>2]=0,n[u>>2]=n[Lf>>2],n[u+4>>2]=n[Lf+4>>2],ci(o,4053,u)|0,n[ap>>2]=11,n[ap+4>>2]=0,n[u>>2]=n[ap>>2],n[u+4>>2]=n[ap+4>>2],ci(o,4065,u)|0,n[op>>2]=12,n[op+4>>2]=0,n[u>>2]=n[op>>2],n[u+4>>2]=n[op+4>>2],ci(o,4084,u)|0,n[mc>>2]=13,n[mc+4>>2]=0,n[u>>2]=n[mc>>2],n[u+4>>2]=n[mc+4>>2],ci(o,4097,u)|0,n[ma>>2]=14,n[ma+4>>2]=0,n[u>>2]=n[ma>>2],n[u+4>>2]=n[ma+4>>2],ci(o,4117,u)|0,n[Ll>>2]=15,n[Ll+4>>2]=0,n[u>>2]=n[Ll>>2],n[u+4>>2]=n[Ll+4>>2],ci(o,4129,u)|0,n[oo>>2]=16,n[oo+4>>2]=0,n[u>>2]=n[oo>>2],n[u+4>>2]=n[oo+4>>2],ci(o,4148,u)|0,n[xu>>2]=17,n[xu+4>>2]=0,n[u>>2]=n[xu>>2],n[u+4>>2]=n[xu+4>>2],ci(o,4161,u)|0,n[Of>>2]=18,n[Of+4>>2]=0,n[u>>2]=n[Of>>2],n[u+4>>2]=n[Of+4>>2],ci(o,4181,u)|0,n[Nf>>2]=5,n[Nf+4>>2]=0,n[u>>2]=n[Nf>>2],n[u+4>>2]=n[Nf+4>>2],zr(o,4196,u)|0,n[$h>>2]=6,n[$h+4>>2]=0,n[u>>2]=n[$h>>2],n[u+4>>2]=n[$h+4>>2],zr(o,4206,u)|0,n[Zh>>2]=7,n[Zh+4>>2]=0,n[u>>2]=n[Zh>>2],n[u+4>>2]=n[Zh+4>>2],zr(o,4217,u)|0,n[Pu>>2]=3,n[Pu+4>>2]=0,n[u>>2]=n[Pu>>2],n[u+4>>2]=n[Pu+4>>2],Du(o,4235,u)|0,n[Xh>>2]=1,n[Xh+4>>2]=0,n[u>>2]=n[Xh>>2],n[u+4>>2]=n[Xh+4>>2],cM(o,4251,u)|0,n[dc>>2]=4,n[dc+4>>2]=0,n[u>>2]=n[dc>>2],n[u+4>>2]=n[dc+4>>2],Du(o,4263,u)|0,n[ln>>2]=5,n[ln+4>>2]=0,n[u>>2]=n[ln>>2],n[u+4>>2]=n[ln+4>>2],Du(o,4279,u)|0,n[zh>>2]=6,n[zh+4>>2]=0,n[u>>2]=n[zh>>2],n[u+4>>2]=n[zh+4>>2],Du(o,4293,u)|0,n[Kh>>2]=7,n[Kh+4>>2]=0,n[u>>2]=n[Kh>>2],n[u+4>>2]=n[Kh+4>>2],Du(o,4306,u)|0,n[Jh>>2]=8,n[Jh+4>>2]=0,n[u>>2]=n[Jh>>2],n[u+4>>2]=n[Jh+4>>2],Du(o,4323,u)|0,n[Ff>>2]=9,n[Ff+4>>2]=0,n[u>>2]=n[Ff>>2],n[u+4>>2]=n[Ff+4>>2],Du(o,4335,u)|0,n[Rf>>2]=2,n[Rf+4>>2]=0,n[u>>2]=n[Rf>>2],n[u+4>>2]=n[Rf+4>>2],cM(o,4353,u)|0,n[Vh>>2]=12,n[Vh+4>>2]=0,n[u>>2]=n[Vh>>2],n[u+4>>2]=n[Vh+4>>2],od(o,4363,u)|0,n[gc>>2]=1,n[gc+4>>2]=0,n[u>>2]=n[gc>>2],n[u+4>>2]=n[gc+4>>2],ep(o,4376,u)|0,n[Yh>>2]=2,n[Yh+4>>2]=0,n[u>>2]=n[Yh>>2],n[u+4>>2]=n[Yh+4>>2],ep(o,4388,u)|0,n[Wh>>2]=13,n[Wh+4>>2]=0,n[u>>2]=n[Wh>>2],n[u+4>>2]=n[Wh+4>>2],od(o,4402,u)|0,n[Za>>2]=14,n[Za+4>>2]=0,n[u>>2]=n[Za>>2],n[u+4>>2]=n[Za+4>>2],od(o,4411,u)|0,n[Fo>>2]=15,n[Fo+4>>2]=0,n[u>>2]=n[Fo>>2],n[u+4>>2]=n[Fo+4>>2],od(o,4421,u)|0,n[Ro>>2]=16,n[Ro+4>>2]=0,n[u>>2]=n[Ro>>2],n[u+4>>2]=n[Ro+4>>2],od(o,4433,u)|0,n[To>>2]=17,n[To+4>>2]=0,n[u>>2]=n[To>>2],n[u+4>>2]=n[To+4>>2],od(o,4446,u)|0,n[Hn>>2]=18,n[Hn+4>>2]=0,n[u>>2]=n[Hn>>2],n[u+4>>2]=n[Hn+4>>2],od(o,4458,u)|0,n[cr>>2]=3,n[cr+4>>2]=0,n[u>>2]=n[cr>>2],n[u+4>>2]=n[cr+4>>2],ep(o,4471,u)|0,n[Hr>>2]=1,n[Hr+4>>2]=0,n[u>>2]=n[Hr>>2],n[u+4>>2]=n[Hr+4>>2],QP(o,4486,u)|0,n[Tr>>2]=10,n[Tr+4>>2]=0,n[u>>2]=n[Tr>>2],n[u+4>>2]=n[Tr+4>>2],Du(o,4496,u)|0,n[$t>>2]=11,n[$t+4>>2]=0,n[u>>2]=n[$t>>2],n[u+4>>2]=n[$t+4>>2],Du(o,4508,u)|0,n[fr>>2]=3,n[fr+4>>2]=0,n[u>>2]=n[fr>>2],n[u+4>>2]=n[fr+4>>2],cM(o,4519,u)|0,n[Gr>>2]=4,n[Gr+4>>2]=0,n[u>>2]=n[Gr>>2],n[u+4>>2]=n[Gr+4>>2],Cke(o,4530,u)|0,n[Lt>>2]=19,n[Lt+4>>2]=0,n[u>>2]=n[Lt>>2],n[u+4>>2]=n[Lt+4>>2],wke(o,4542,u)|0,n[We>>2]=12,n[We+4>>2]=0,n[u>>2]=n[We>>2],n[u+4>>2]=n[We+4>>2],Bke(o,4554,u)|0,n[He>>2]=13,n[He+4>>2]=0,n[u>>2]=n[He>>2],n[u+4>>2]=n[He+4>>2],vke(o,4568,u)|0,n[ct>>2]=2,n[ct+4>>2]=0,n[u>>2]=n[ct>>2],n[u+4>>2]=n[ct+4>>2],Ske(o,4578,u)|0,n[Ze>>2]=20,n[Ze+4>>2]=0,n[u>>2]=n[Ze>>2],n[u+4>>2]=n[Ze+4>>2],Dke(o,4587,u)|0,n[tt>>2]=22,n[tt+4>>2]=0,n[u>>2]=n[tt>>2],n[u+4>>2]=n[tt+4>>2],kr(o,4602,u)|0,n[Qe>>2]=23,n[Qe+4>>2]=0,n[u>>2]=n[Qe>>2],n[u+4>>2]=n[Qe+4>>2],kr(o,4619,u)|0,n[Le>>2]=14,n[Le+4>>2]=0,n[u>>2]=n[Le>>2],n[u+4>>2]=n[Le+4>>2],bke(o,4629,u)|0,n[Ye>>2]=1,n[Ye+4>>2]=0,n[u>>2]=n[Ye>>2],n[u+4>>2]=n[Ye+4>>2],Pke(o,4637,u)|0,n[ae>>2]=4,n[ae+4>>2]=0,n[u>>2]=n[ae>>2],n[u+4>>2]=n[ae+4>>2],ep(o,4653,u)|0,n[q>>2]=5,n[q+4>>2]=0,n[u>>2]=n[q>>2],n[u+4>>2]=n[q+4>>2],ep(o,4669,u)|0,n[L>>2]=6,n[L+4>>2]=0,n[u>>2]=n[L>>2],n[u+4>>2]=n[L+4>>2],ep(o,4686,u)|0,n[M>>2]=7,n[M+4>>2]=0,n[u>>2]=n[M>>2],n[u+4>>2]=n[M+4>>2],ep(o,4701,u)|0,n[T>>2]=8,n[T+4>>2]=0,n[u>>2]=n[T>>2],n[u+4>>2]=n[T+4>>2],ep(o,4719,u)|0,n[k>>2]=9,n[k+4>>2]=0,n[u>>2]=n[k>>2],n[u+4>>2]=n[k+4>>2],ep(o,4736,u)|0,n[B>>2]=21,n[B+4>>2]=0,n[u>>2]=n[B>>2],n[u+4>>2]=n[B+4>>2],xke(o,4754,u)|0,n[m>>2]=2,n[m+4>>2]=0,n[u>>2]=n[m>>2],n[u+4>>2]=n[m+4>>2],QP(o,4772,u)|0,n[d>>2]=3,n[d+4>>2]=0,n[u>>2]=n[d>>2],n[u+4>>2]=n[d+4>>2],QP(o,4790,u)|0,n[A>>2]=4,n[A+4>>2]=0,n[u>>2]=n[A>>2],n[u+4>>2]=n[A+4>>2],QP(o,4808,u)|0,I=l}function gt(o,l){o=o|0,l=l|0;var u=0;u=NLe()|0,n[o>>2]=u,OLe(u,l),jh(n[o>>2]|0)}function Xt(o,l,u){return o=o|0,l=l|0,u=u|0,CLe(o,Bn(l)|0,u,0),o|0}function Dr(o,l,u){return o=o|0,l=l|0,u=u|0,sLe(o,Bn(l)|0,u,0),o|0}function Zn(o,l,u){return o=o|0,l=l|0,u=u|0,WOe(o,Bn(l)|0,u,0),o|0}function kr(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],xOe(o,l,d),I=A,o|0}function Rn(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],uOe(o,l,d),I=A,o|0}function _n(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],JNe(o,l,d),I=A,o|0}function zr(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],TNe(o,l,d),I=A,o|0}function ci(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],dNe(o,l,d),I=A,o|0}function Du(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],eNe(o,l,d),I=A,o|0}function cM(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],MFe(o,l,d),I=A,o|0}function od(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],uFe(o,l,d),I=A,o|0}function ep(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],JRe(o,l,d),I=A,o|0}function QP(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],TRe(o,l,d),I=A,o|0}function Cke(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],dRe(o,l,d),I=A,o|0}function wke(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],eRe(o,l,d),I=A,o|0}function Bke(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],UTe(o,l,d),I=A,o|0}function vke(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],vTe(o,l,d),I=A,o|0}function Ske(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],aTe(o,l,d),I=A,o|0}function Dke(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],qQe(o,l,d),I=A,o|0}function bke(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],PQe(o,l,d),I=A,o|0}function Pke(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],uQe(o,l,d),I=A,o|0}function xke(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],kke(o,l,d),I=A,o|0}function kke(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Qke(o,u,d,1),I=A}function Bn(o){return o=o|0,o|0}function Qke(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,T=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,T=n[u+4>>2]|0,B=n[o>>2]|0,o=uM()|0,n[L>>2]=M,n[L+4>>2]=T,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=Tke(m)|0,n[k>>2]=M,n[k+4>>2]=T,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,Rke(m,A)|0,A),I=d}function uM(){var o=0,l=0;if(s[7616]|0||(mz(9136),gr(24,9136,U|0)|0,l=7616,n[l>>2]=1,n[l+4>>2]=0),!(_r(9136)|0)){o=9136,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));mz(9136)}return 9136}function Tke(o){return o=o|0,0}function Rke(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,T=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=uM()|0,M=q+24|0,o=yr(l,4)|0,n[T>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],dz(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(Oke(M,k,T),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function vn(o,l,u,A,d,m){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0;var B=0,k=0,T=0,M=0,L=0,q=0,ae=0,Ye=0;B=I,I=I+32|0,ae=B+24|0,q=B+20|0,T=B+16|0,L=B+12|0,M=B+8|0,k=B+4|0,Ye=B,n[q>>2]=l,n[T>>2]=u,n[L>>2]=A,n[M>>2]=d,n[k>>2]=m,m=o+28|0,n[Ye>>2]=n[m>>2],n[ae>>2]=n[Ye>>2],Fke(o+24|0,ae,q,L,M,T,k)|0,n[m>>2]=n[n[m>>2]>>2],I=B}function Fke(o,l,u,A,d,m,B){return o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0,B=B|0,o=Nke(l)|0,l=Kt(24)|0,gz(l+4|0,n[u>>2]|0,n[A>>2]|0,n[d>>2]|0,n[m>>2]|0,n[B>>2]|0),n[l>>2]=n[o>>2],n[o>>2]=l,l|0}function Nke(o){return o=o|0,n[o>>2]|0}function gz(o,l,u,A,d,m){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0,n[o>>2]=l,n[o+4>>2]=u,n[o+8>>2]=A,n[o+12>>2]=d,n[o+16>>2]=m}function yr(o,l){return o=o|0,l=l|0,l|o|0}function dz(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function Oke(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,T=o+4|0,d=(((n[T>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=Lke(o)|0,m>>>0>>0)an(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,Mke(k,ae>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[T>>2]|0)-L|0)/12|0,o+8|0),T=k+8|0,m=n[T>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],dz(m,A,u),n[T>>2]=(n[T>>2]|0)+12,Uke(o,k),_ke(k),I=M;return}}function Lke(o){return o=o|0,357913941}function Mke(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function Uke(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function _ke(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function mz(o){o=o|0,Gke(o)}function Hke(o){o=o|0,jke(o+24|0)}function _r(o){return o=o|0,n[o>>2]|0}function jke(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function Gke(o){o=o|0;var l=0;l=tn()|0,rn(o,2,3,l,qke()|0,0),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function tn(){return 9228}function qke(){return 1140}function Wke(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0;return u=I,I=I+16|0,A=u+8|0,d=u,m=Yke(o)|0,o=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=o,n[A>>2]=n[d>>2],n[A+4>>2]=n[d+4>>2],l=Vke(l,A)|0,I=u,l|0}function rn(o,l,u,A,d,m){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0,n[o>>2]=l,n[o+4>>2]=u,n[o+8>>2]=A,n[o+12>>2]=d,n[o+16>>2]=m}function Yke(o){return o=o|0,(n[(uM()|0)+24>>2]|0)+(o*12|0)|0}function Vke(o,l){o=o|0,l=l|0;var u=0,A=0,d=0;return d=I,I=I+48|0,A=d,u=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(u=n[(n[o>>2]|0)+u>>2]|0),sp[u&31](A,o),A=Jke(A)|0,I=d,A|0}function Jke(o){o=o|0;var l=0,u=0,A=0,d=0;return d=I,I=I+32|0,l=d+12|0,u=d,A=fM(yz()|0)|0,A?(AM(l,A),pM(u,l),Kke(o,u),o=hM(l)|0):o=zke(o)|0,I=d,o|0}function yz(){var o=0;return s[7632]|0||(oQe(9184),gr(25,9184,U|0)|0,o=7632,n[o>>2]=1,n[o+4>>2]=0),9184}function fM(o){return o=o|0,n[o+36>>2]|0}function AM(o,l){o=o|0,l=l|0,n[o>>2]=l,n[o+4>>2]=o,n[o+8>>2]=0}function pM(o,l){o=o|0,l=l|0,n[o>>2]=n[l>>2],n[o+4>>2]=n[l+4>>2],n[o+8>>2]=0}function Kke(o,l){o=o|0,l=l|0,eQe(l,o,o+8|0,o+16|0,o+24|0,o+32|0,o+40|0)|0}function hM(o){return o=o|0,n[(n[o+4>>2]|0)+8>>2]|0}function zke(o){o=o|0;var l=0,u=0,A=0,d=0,m=0,B=0,k=0,T=0;T=I,I=I+16|0,u=T+4|0,A=T,d=Rl(8)|0,m=d,B=Kt(48)|0,k=B,l=k+48|0;do n[k>>2]=n[o>>2],k=k+4|0,o=o+4|0;while((k|0)<(l|0));return l=m+4|0,n[l>>2]=B,k=Kt(8)|0,B=n[l>>2]|0,n[A>>2]=0,n[u>>2]=n[A>>2],Ez(k,B,u),n[d>>2]=k,I=T,m|0}function Ez(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,u=Kt(16)|0,n[u+4>>2]=0,n[u+8>>2]=0,n[u>>2]=1092,n[u+12>>2]=l,n[o+4>>2]=u}function Xke(o){o=o|0,$y(o),It(o)}function Zke(o){o=o|0,o=n[o+12>>2]|0,o|0&&It(o)}function $ke(o){o=o|0,It(o)}function eQe(o,l,u,A,d,m,B){return o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0,B=B|0,m=tQe(n[o>>2]|0,l,u,A,d,m,B)|0,B=o+4|0,n[(n[B>>2]|0)+8>>2]=m,n[(n[B>>2]|0)+8>>2]|0}function tQe(o,l,u,A,d,m,B){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0,B=B|0;var k=0,T=0;return k=I,I=I+16|0,T=k,Fl(T),o=Os(o)|0,B=rQe(o,+E[l>>3],+E[u>>3],+E[A>>3],+E[d>>3],+E[m>>3],+E[B>>3])|0,Nl(T),I=k,B|0}function rQe(o,l,u,A,d,m,B){o=o|0,l=+l,u=+u,A=+A,d=+d,m=+m,B=+B;var k=0;return k=da(nQe()|0)|0,l=+Ja(l),u=+Ja(u),A=+Ja(A),d=+Ja(d),m=+Ja(m),ro(0,k|0,o|0,+l,+u,+A,+d,+m,+ +Ja(B))|0}function nQe(){var o=0;return s[7624]|0||(iQe(9172),o=7624,n[o>>2]=1,n[o+4>>2]=0),9172}function iQe(o){o=o|0,Qo(o,sQe()|0,6)}function sQe(){return 1112}function oQe(o){o=o|0,Lh(o)}function aQe(o){o=o|0,Iz(o+24|0),Cz(o+16|0)}function Iz(o){o=o|0,cQe(o)}function Cz(o){o=o|0,lQe(o)}function lQe(o){o=o|0;var l=0,u=0;if(l=n[o>>2]|0,l|0)do u=l,l=n[l>>2]|0,It(u);while(l|0);n[o>>2]=0}function cQe(o){o=o|0;var l=0,u=0;if(l=n[o>>2]|0,l|0)do u=l,l=n[l>>2]|0,It(u);while(l|0);n[o>>2]=0}function Lh(o){o=o|0;var l=0;n[o+16>>2]=0,n[o+20>>2]=0,l=o+24|0,n[l>>2]=0,n[o+28>>2]=l,n[o+36>>2]=0,s[o+40>>0]=0,s[o+41>>0]=0}function uQe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],fQe(o,u,d,0),I=A}function fQe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,T=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,T=n[u+4>>2]|0,B=n[o>>2]|0,o=gM()|0,n[L>>2]=M,n[L+4>>2]=T,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=AQe(m)|0,n[k>>2]=M,n[k+4>>2]=T,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,pQe(m,A)|0,A),I=d}function gM(){var o=0,l=0;if(s[7640]|0||(Bz(9232),gr(26,9232,U|0)|0,l=7640,n[l>>2]=1,n[l+4>>2]=0),!(_r(9232)|0)){o=9232,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));Bz(9232)}return 9232}function AQe(o){return o=o|0,0}function pQe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,T=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=gM()|0,M=q+24|0,o=yr(l,4)|0,n[T>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],wz(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(hQe(M,k,T),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function wz(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function hQe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,T=o+4|0,d=(((n[T>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=gQe(o)|0,m>>>0>>0)an(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,dQe(k,ae>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[T>>2]|0)-L|0)/12|0,o+8|0),T=k+8|0,m=n[T>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],wz(m,A,u),n[T>>2]=(n[T>>2]|0)+12,mQe(o,k),yQe(k),I=M;return}}function gQe(o){return o=o|0,357913941}function dQe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function mQe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function yQe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function Bz(o){o=o|0,CQe(o)}function EQe(o){o=o|0,IQe(o+24|0)}function IQe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function CQe(o){o=o|0;var l=0;l=tn()|0,rn(o,2,1,l,wQe()|0,3),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function wQe(){return 1144}function BQe(o,l,u,A,d){o=o|0,l=l|0,u=+u,A=+A,d=d|0;var m=0,B=0,k=0,T=0;m=I,I=I+16|0,B=m+8|0,k=m,T=vQe(o)|0,o=n[T+4>>2]|0,n[k>>2]=n[T>>2],n[k+4>>2]=o,n[B>>2]=n[k>>2],n[B+4>>2]=n[k+4>>2],SQe(l,B,u,A,d),I=m}function vQe(o){return o=o|0,(n[(gM()|0)+24>>2]|0)+(o*12|0)|0}function SQe(o,l,u,A,d){o=o|0,l=l|0,u=+u,A=+A,d=d|0;var m=0,B=0,k=0,T=0,M=0;M=I,I=I+16|0,B=M+2|0,k=M+1|0,T=M,m=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(m=n[(n[o>>2]|0)+m>>2]|0),Qf(B,u),u=+Tf(B,u),Qf(k,A),A=+Tf(k,A),tp(T,d),T=rp(T,d)|0,MZ[m&1](o,u,A,T),I=M}function Qf(o,l){o=o|0,l=+l}function Tf(o,l){return o=o|0,l=+l,+ +bQe(l)}function tp(o,l){o=o|0,l=l|0}function rp(o,l){return o=o|0,l=l|0,DQe(l)|0}function DQe(o){return o=o|0,o|0}function bQe(o){return o=+o,+o}function PQe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],xQe(o,u,d,1),I=A}function xQe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,T=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,T=n[u+4>>2]|0,B=n[o>>2]|0,o=dM()|0,n[L>>2]=M,n[L+4>>2]=T,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=kQe(m)|0,n[k>>2]=M,n[k+4>>2]=T,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,QQe(m,A)|0,A),I=d}function dM(){var o=0,l=0;if(s[7648]|0||(Sz(9268),gr(27,9268,U|0)|0,l=7648,n[l>>2]=1,n[l+4>>2]=0),!(_r(9268)|0)){o=9268,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));Sz(9268)}return 9268}function kQe(o){return o=o|0,0}function QQe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,T=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=dM()|0,M=q+24|0,o=yr(l,4)|0,n[T>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],vz(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(TQe(M,k,T),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function vz(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function TQe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,T=o+4|0,d=(((n[T>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=RQe(o)|0,m>>>0>>0)an(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,FQe(k,ae>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[T>>2]|0)-L|0)/12|0,o+8|0),T=k+8|0,m=n[T>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],vz(m,A,u),n[T>>2]=(n[T>>2]|0)+12,NQe(o,k),OQe(k),I=M;return}}function RQe(o){return o=o|0,357913941}function FQe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function NQe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function OQe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function Sz(o){o=o|0,UQe(o)}function LQe(o){o=o|0,MQe(o+24|0)}function MQe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function UQe(o){o=o|0;var l=0;l=tn()|0,rn(o,2,4,l,_Qe()|0,0),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function _Qe(){return 1160}function HQe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0;return u=I,I=I+16|0,A=u+8|0,d=u,m=jQe(o)|0,o=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=o,n[A>>2]=n[d>>2],n[A+4>>2]=n[d+4>>2],l=GQe(l,A)|0,I=u,l|0}function jQe(o){return o=o|0,(n[(dM()|0)+24>>2]|0)+(o*12|0)|0}function GQe(o,l){o=o|0,l=l|0;var u=0;return u=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(u=n[(n[o>>2]|0)+u>>2]|0),Dz(gd[u&31](o)|0)|0}function Dz(o){return o=o|0,o&1|0}function qQe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],WQe(o,u,d,0),I=A}function WQe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,T=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,T=n[u+4>>2]|0,B=n[o>>2]|0,o=mM()|0,n[L>>2]=M,n[L+4>>2]=T,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=YQe(m)|0,n[k>>2]=M,n[k+4>>2]=T,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,VQe(m,A)|0,A),I=d}function mM(){var o=0,l=0;if(s[7656]|0||(Pz(9304),gr(28,9304,U|0)|0,l=7656,n[l>>2]=1,n[l+4>>2]=0),!(_r(9304)|0)){o=9304,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));Pz(9304)}return 9304}function YQe(o){return o=o|0,0}function VQe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,T=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=mM()|0,M=q+24|0,o=yr(l,4)|0,n[T>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],bz(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(JQe(M,k,T),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function bz(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function JQe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,T=o+4|0,d=(((n[T>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=KQe(o)|0,m>>>0>>0)an(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,zQe(k,ae>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[T>>2]|0)-L|0)/12|0,o+8|0),T=k+8|0,m=n[T>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],bz(m,A,u),n[T>>2]=(n[T>>2]|0)+12,XQe(o,k),ZQe(k),I=M;return}}function KQe(o){return o=o|0,357913941}function zQe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function XQe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function ZQe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function Pz(o){o=o|0,tTe(o)}function $Qe(o){o=o|0,eTe(o+24|0)}function eTe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function tTe(o){o=o|0;var l=0;l=tn()|0,rn(o,2,5,l,rTe()|0,1),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function rTe(){return 1164}function nTe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;A=I,I=I+16|0,d=A+8|0,m=A,B=iTe(o)|0,o=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=o,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],sTe(l,d,u),I=A}function iTe(o){return o=o|0,(n[(mM()|0)+24>>2]|0)+(o*12|0)|0}function sTe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0;m=I,I=I+16|0,d=m,A=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(A=n[(n[o>>2]|0)+A>>2]|0),Mh(d,u),u=Uh(d,u)|0,sp[A&31](o,u),_h(d),I=m}function Mh(o,l){o=o|0,l=l|0,oTe(o,l)}function Uh(o,l){return o=o|0,l=l|0,o|0}function _h(o){o=o|0,Sf(o)}function oTe(o,l){o=o|0,l=l|0,yM(o,l)}function yM(o,l){o=o|0,l=l|0,n[o>>2]=l}function aTe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],lTe(o,u,d,0),I=A}function lTe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,T=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,T=n[u+4>>2]|0,B=n[o>>2]|0,o=EM()|0,n[L>>2]=M,n[L+4>>2]=T,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=cTe(m)|0,n[k>>2]=M,n[k+4>>2]=T,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,uTe(m,A)|0,A),I=d}function EM(){var o=0,l=0;if(s[7664]|0||(kz(9340),gr(29,9340,U|0)|0,l=7664,n[l>>2]=1,n[l+4>>2]=0),!(_r(9340)|0)){o=9340,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));kz(9340)}return 9340}function cTe(o){return o=o|0,0}function uTe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,T=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=EM()|0,M=q+24|0,o=yr(l,4)|0,n[T>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],xz(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(fTe(M,k,T),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function xz(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function fTe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,T=o+4|0,d=(((n[T>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=ATe(o)|0,m>>>0>>0)an(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,pTe(k,ae>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[T>>2]|0)-L|0)/12|0,o+8|0),T=k+8|0,m=n[T>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],xz(m,A,u),n[T>>2]=(n[T>>2]|0)+12,hTe(o,k),gTe(k),I=M;return}}function ATe(o){return o=o|0,357913941}function pTe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function hTe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function gTe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function kz(o){o=o|0,yTe(o)}function dTe(o){o=o|0,mTe(o+24|0)}function mTe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function yTe(o){o=o|0;var l=0;l=tn()|0,rn(o,2,4,l,ETe()|0,1),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function ETe(){return 1180}function ITe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=CTe(o)|0,o=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=o,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],u=wTe(l,d,u)|0,I=A,u|0}function CTe(o){return o=o|0,(n[(EM()|0)+24>>2]|0)+(o*12|0)|0}function wTe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0;return m=I,I=I+16|0,d=m,A=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(A=n[(n[o>>2]|0)+A>>2]|0),ad(d,u),d=ld(d,u)|0,d=TP(gU[A&15](o,d)|0)|0,I=m,d|0}function ad(o,l){o=o|0,l=l|0}function ld(o,l){return o=o|0,l=l|0,BTe(l)|0}function TP(o){return o=o|0,o|0}function BTe(o){return o=o|0,o|0}function vTe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],STe(o,u,d,0),I=A}function STe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,T=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,T=n[u+4>>2]|0,B=n[o>>2]|0,o=IM()|0,n[L>>2]=M,n[L+4>>2]=T,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=DTe(m)|0,n[k>>2]=M,n[k+4>>2]=T,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,bTe(m,A)|0,A),I=d}function IM(){var o=0,l=0;if(s[7672]|0||(Tz(9376),gr(30,9376,U|0)|0,l=7672,n[l>>2]=1,n[l+4>>2]=0),!(_r(9376)|0)){o=9376,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));Tz(9376)}return 9376}function DTe(o){return o=o|0,0}function bTe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,T=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=IM()|0,M=q+24|0,o=yr(l,4)|0,n[T>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],Qz(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(PTe(M,k,T),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function Qz(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function PTe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,T=o+4|0,d=(((n[T>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=xTe(o)|0,m>>>0>>0)an(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,kTe(k,ae>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[T>>2]|0)-L|0)/12|0,o+8|0),T=k+8|0,m=n[T>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],Qz(m,A,u),n[T>>2]=(n[T>>2]|0)+12,QTe(o,k),TTe(k),I=M;return}}function xTe(o){return o=o|0,357913941}function kTe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function QTe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function TTe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function Tz(o){o=o|0,NTe(o)}function RTe(o){o=o|0,FTe(o+24|0)}function FTe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function NTe(o){o=o|0;var l=0;l=tn()|0,rn(o,2,5,l,Rz()|0,0),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function Rz(){return 1196}function OTe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0;return u=I,I=I+16|0,A=u+8|0,d=u,m=LTe(o)|0,o=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=o,n[A>>2]=n[d>>2],n[A+4>>2]=n[d+4>>2],l=MTe(l,A)|0,I=u,l|0}function LTe(o){return o=o|0,(n[(IM()|0)+24>>2]|0)+(o*12|0)|0}function MTe(o,l){o=o|0,l=l|0;var u=0;return u=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(u=n[(n[o>>2]|0)+u>>2]|0),TP(gd[u&31](o)|0)|0}function UTe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],_Te(o,u,d,1),I=A}function _Te(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,T=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,T=n[u+4>>2]|0,B=n[o>>2]|0,o=CM()|0,n[L>>2]=M,n[L+4>>2]=T,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=HTe(m)|0,n[k>>2]=M,n[k+4>>2]=T,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,jTe(m,A)|0,A),I=d}function CM(){var o=0,l=0;if(s[7680]|0||(Nz(9412),gr(31,9412,U|0)|0,l=7680,n[l>>2]=1,n[l+4>>2]=0),!(_r(9412)|0)){o=9412,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));Nz(9412)}return 9412}function HTe(o){return o=o|0,0}function jTe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,T=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=CM()|0,M=q+24|0,o=yr(l,4)|0,n[T>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],Fz(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(GTe(M,k,T),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function Fz(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function GTe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,T=o+4|0,d=(((n[T>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=qTe(o)|0,m>>>0>>0)an(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,WTe(k,ae>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[T>>2]|0)-L|0)/12|0,o+8|0),T=k+8|0,m=n[T>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],Fz(m,A,u),n[T>>2]=(n[T>>2]|0)+12,YTe(o,k),VTe(k),I=M;return}}function qTe(o){return o=o|0,357913941}function WTe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function YTe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function VTe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function Nz(o){o=o|0,zTe(o)}function JTe(o){o=o|0,KTe(o+24|0)}function KTe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function zTe(o){o=o|0;var l=0;l=tn()|0,rn(o,2,6,l,Oz()|0,0),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function Oz(){return 1200}function XTe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0;return u=I,I=I+16|0,A=u+8|0,d=u,m=ZTe(o)|0,o=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=o,n[A>>2]=n[d>>2],n[A+4>>2]=n[d+4>>2],l=$Te(l,A)|0,I=u,l|0}function ZTe(o){return o=o|0,(n[(CM()|0)+24>>2]|0)+(o*12|0)|0}function $Te(o,l){o=o|0,l=l|0;var u=0;return u=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(u=n[(n[o>>2]|0)+u>>2]|0),RP(gd[u&31](o)|0)|0}function RP(o){return o=o|0,o|0}function eRe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],tRe(o,u,d,0),I=A}function tRe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,T=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,T=n[u+4>>2]|0,B=n[o>>2]|0,o=wM()|0,n[L>>2]=M,n[L+4>>2]=T,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=rRe(m)|0,n[k>>2]=M,n[k+4>>2]=T,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,nRe(m,A)|0,A),I=d}function wM(){var o=0,l=0;if(s[7688]|0||(Mz(9448),gr(32,9448,U|0)|0,l=7688,n[l>>2]=1,n[l+4>>2]=0),!(_r(9448)|0)){o=9448,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));Mz(9448)}return 9448}function rRe(o){return o=o|0,0}function nRe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,T=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=wM()|0,M=q+24|0,o=yr(l,4)|0,n[T>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],Lz(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(iRe(M,k,T),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function Lz(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function iRe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,T=o+4|0,d=(((n[T>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=sRe(o)|0,m>>>0>>0)an(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,oRe(k,ae>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[T>>2]|0)-L|0)/12|0,o+8|0),T=k+8|0,m=n[T>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],Lz(m,A,u),n[T>>2]=(n[T>>2]|0)+12,aRe(o,k),lRe(k),I=M;return}}function sRe(o){return o=o|0,357913941}function oRe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function aRe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function lRe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function Mz(o){o=o|0,fRe(o)}function cRe(o){o=o|0,uRe(o+24|0)}function uRe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function fRe(o){o=o|0;var l=0;l=tn()|0,rn(o,2,6,l,Uz()|0,1),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function Uz(){return 1204}function ARe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;A=I,I=I+16|0,d=A+8|0,m=A,B=pRe(o)|0,o=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=o,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],hRe(l,d,u),I=A}function pRe(o){return o=o|0,(n[(wM()|0)+24>>2]|0)+(o*12|0)|0}function hRe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0;m=I,I=I+16|0,d=m,A=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(A=n[(n[o>>2]|0)+A>>2]|0),BM(d,u),d=vM(d,u)|0,sp[A&31](o,d),I=m}function BM(o,l){o=o|0,l=l|0}function vM(o,l){return o=o|0,l=l|0,gRe(l)|0}function gRe(o){return o=o|0,o|0}function dRe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],mRe(o,u,d,0),I=A}function mRe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,T=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,T=n[u+4>>2]|0,B=n[o>>2]|0,o=SM()|0,n[L>>2]=M,n[L+4>>2]=T,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=yRe(m)|0,n[k>>2]=M,n[k+4>>2]=T,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,ERe(m,A)|0,A),I=d}function SM(){var o=0,l=0;if(s[7696]|0||(Hz(9484),gr(33,9484,U|0)|0,l=7696,n[l>>2]=1,n[l+4>>2]=0),!(_r(9484)|0)){o=9484,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));Hz(9484)}return 9484}function yRe(o){return o=o|0,0}function ERe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,T=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=SM()|0,M=q+24|0,o=yr(l,4)|0,n[T>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],_z(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(IRe(M,k,T),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function _z(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function IRe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,T=o+4|0,d=(((n[T>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=CRe(o)|0,m>>>0>>0)an(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,wRe(k,ae>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[T>>2]|0)-L|0)/12|0,o+8|0),T=k+8|0,m=n[T>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],_z(m,A,u),n[T>>2]=(n[T>>2]|0)+12,BRe(o,k),vRe(k),I=M;return}}function CRe(o){return o=o|0,357913941}function wRe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function BRe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function vRe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function Hz(o){o=o|0,bRe(o)}function SRe(o){o=o|0,DRe(o+24|0)}function DRe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function bRe(o){o=o|0;var l=0;l=tn()|0,rn(o,2,1,l,PRe()|0,2),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function PRe(){return 1212}function xRe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0;d=I,I=I+16|0,m=d+8|0,B=d,k=kRe(o)|0,o=n[k+4>>2]|0,n[B>>2]=n[k>>2],n[B+4>>2]=o,n[m>>2]=n[B>>2],n[m+4>>2]=n[B+4>>2],QRe(l,m,u,A),I=d}function kRe(o){return o=o|0,(n[(SM()|0)+24>>2]|0)+(o*12|0)|0}function QRe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0;k=I,I=I+16|0,m=k+1|0,B=k,d=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(d=n[(n[o>>2]|0)+d>>2]|0),BM(m,u),m=vM(m,u)|0,ad(B,A),B=ld(B,A)|0,F2[d&15](o,m,B),I=k}function TRe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],RRe(o,u,d,1),I=A}function RRe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,T=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,T=n[u+4>>2]|0,B=n[o>>2]|0,o=DM()|0,n[L>>2]=M,n[L+4>>2]=T,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=FRe(m)|0,n[k>>2]=M,n[k+4>>2]=T,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,NRe(m,A)|0,A),I=d}function DM(){var o=0,l=0;if(s[7704]|0||(Gz(9520),gr(34,9520,U|0)|0,l=7704,n[l>>2]=1,n[l+4>>2]=0),!(_r(9520)|0)){o=9520,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));Gz(9520)}return 9520}function FRe(o){return o=o|0,0}function NRe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,T=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=DM()|0,M=q+24|0,o=yr(l,4)|0,n[T>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],jz(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(ORe(M,k,T),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function jz(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function ORe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,T=o+4|0,d=(((n[T>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=LRe(o)|0,m>>>0>>0)an(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,MRe(k,ae>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[T>>2]|0)-L|0)/12|0,o+8|0),T=k+8|0,m=n[T>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],jz(m,A,u),n[T>>2]=(n[T>>2]|0)+12,URe(o,k),_Re(k),I=M;return}}function LRe(o){return o=o|0,357913941}function MRe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function URe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function _Re(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function Gz(o){o=o|0,GRe(o)}function HRe(o){o=o|0,jRe(o+24|0)}function jRe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function GRe(o){o=o|0;var l=0;l=tn()|0,rn(o,2,1,l,qRe()|0,1),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function qRe(){return 1224}function WRe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;return d=I,I=I+16|0,m=d+8|0,B=d,k=YRe(o)|0,o=n[k+4>>2]|0,n[B>>2]=n[k>>2],n[B+4>>2]=o,n[m>>2]=n[B>>2],n[m+4>>2]=n[B+4>>2],A=+VRe(l,m,u),I=d,+A}function YRe(o){return o=o|0,(n[(DM()|0)+24>>2]|0)+(o*12|0)|0}function VRe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return m=I,I=I+16|0,d=m,A=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(A=n[(n[o>>2]|0)+A>>2]|0),tp(d,u),d=rp(d,u)|0,B=+kf(+_Z[A&7](o,d)),I=m,+B}function JRe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],KRe(o,u,d,1),I=A}function KRe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,T=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,T=n[u+4>>2]|0,B=n[o>>2]|0,o=bM()|0,n[L>>2]=M,n[L+4>>2]=T,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=zRe(m)|0,n[k>>2]=M,n[k+4>>2]=T,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,XRe(m,A)|0,A),I=d}function bM(){var o=0,l=0;if(s[7712]|0||(Wz(9556),gr(35,9556,U|0)|0,l=7712,n[l>>2]=1,n[l+4>>2]=0),!(_r(9556)|0)){o=9556,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));Wz(9556)}return 9556}function zRe(o){return o=o|0,0}function XRe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,T=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=bM()|0,M=q+24|0,o=yr(l,4)|0,n[T>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],qz(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(ZRe(M,k,T),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function qz(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function ZRe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,T=o+4|0,d=(((n[T>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=$Re(o)|0,m>>>0>>0)an(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,eFe(k,ae>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[T>>2]|0)-L|0)/12|0,o+8|0),T=k+8|0,m=n[T>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],qz(m,A,u),n[T>>2]=(n[T>>2]|0)+12,tFe(o,k),rFe(k),I=M;return}}function $Re(o){return o=o|0,357913941}function eFe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function tFe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function rFe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function Wz(o){o=o|0,sFe(o)}function nFe(o){o=o|0,iFe(o+24|0)}function iFe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function sFe(o){o=o|0;var l=0;l=tn()|0,rn(o,2,5,l,oFe()|0,0),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function oFe(){return 1232}function aFe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=lFe(o)|0,o=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=o,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],u=+cFe(l,d),I=A,+u}function lFe(o){return o=o|0,(n[(bM()|0)+24>>2]|0)+(o*12|0)|0}function cFe(o,l){o=o|0,l=l|0;var u=0;return u=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(u=n[(n[o>>2]|0)+u>>2]|0),+ +kf(+UZ[u&15](o))}function uFe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],fFe(o,u,d,1),I=A}function fFe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,T=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,T=n[u+4>>2]|0,B=n[o>>2]|0,o=PM()|0,n[L>>2]=M,n[L+4>>2]=T,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=AFe(m)|0,n[k>>2]=M,n[k+4>>2]=T,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,pFe(m,A)|0,A),I=d}function PM(){var o=0,l=0;if(s[7720]|0||(Vz(9592),gr(36,9592,U|0)|0,l=7720,n[l>>2]=1,n[l+4>>2]=0),!(_r(9592)|0)){o=9592,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));Vz(9592)}return 9592}function AFe(o){return o=o|0,0}function pFe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,T=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=PM()|0,M=q+24|0,o=yr(l,4)|0,n[T>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],Yz(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(hFe(M,k,T),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function Yz(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function hFe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,T=o+4|0,d=(((n[T>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=gFe(o)|0,m>>>0>>0)an(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,dFe(k,ae>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[T>>2]|0)-L|0)/12|0,o+8|0),T=k+8|0,m=n[T>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],Yz(m,A,u),n[T>>2]=(n[T>>2]|0)+12,mFe(o,k),yFe(k),I=M;return}}function gFe(o){return o=o|0,357913941}function dFe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function mFe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function yFe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function Vz(o){o=o|0,CFe(o)}function EFe(o){o=o|0,IFe(o+24|0)}function IFe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function CFe(o){o=o|0;var l=0;l=tn()|0,rn(o,2,7,l,wFe()|0,0),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function wFe(){return 1276}function BFe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0;return u=I,I=I+16|0,A=u+8|0,d=u,m=vFe(o)|0,o=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=o,n[A>>2]=n[d>>2],n[A+4>>2]=n[d+4>>2],l=SFe(l,A)|0,I=u,l|0}function vFe(o){return o=o|0,(n[(PM()|0)+24>>2]|0)+(o*12|0)|0}function SFe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0;return d=I,I=I+16|0,A=d,u=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(u=n[(n[o>>2]|0)+u>>2]|0),sp[u&31](A,o),A=Jz(A)|0,I=d,A|0}function Jz(o){o=o|0;var l=0,u=0,A=0,d=0;return d=I,I=I+32|0,l=d+12|0,u=d,A=fM(Kz()|0)|0,A?(AM(l,A),pM(u,l),DFe(o,u),o=hM(l)|0):o=bFe(o)|0,I=d,o|0}function Kz(){var o=0;return s[7736]|0||(LFe(9640),gr(25,9640,U|0)|0,o=7736,n[o>>2]=1,n[o+4>>2]=0),9640}function DFe(o,l){o=o|0,l=l|0,QFe(l,o,o+8|0)|0}function bFe(o){o=o|0;var l=0,u=0,A=0,d=0,m=0,B=0,k=0;return u=I,I=I+16|0,d=u+4|0,B=u,A=Rl(8)|0,l=A,k=Kt(16)|0,n[k>>2]=n[o>>2],n[k+4>>2]=n[o+4>>2],n[k+8>>2]=n[o+8>>2],n[k+12>>2]=n[o+12>>2],m=l+4|0,n[m>>2]=k,o=Kt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],xM(o,m,d),n[A>>2]=o,I=u,l|0}function xM(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,u=Kt(16)|0,n[u+4>>2]=0,n[u+8>>2]=0,n[u>>2]=1244,n[u+12>>2]=l,n[o+4>>2]=u}function PFe(o){o=o|0,$y(o),It(o)}function xFe(o){o=o|0,o=n[o+12>>2]|0,o|0&&It(o)}function kFe(o){o=o|0,It(o)}function QFe(o,l,u){return o=o|0,l=l|0,u=u|0,l=TFe(n[o>>2]|0,l,u)|0,u=o+4|0,n[(n[u>>2]|0)+8>>2]=l,n[(n[u>>2]|0)+8>>2]|0}function TFe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0;return A=I,I=I+16|0,d=A,Fl(d),o=Os(o)|0,u=RFe(o,n[l>>2]|0,+E[u>>3])|0,Nl(d),I=A,u|0}function RFe(o,l,u){o=o|0,l=l|0,u=+u;var A=0;return A=da(FFe()|0)|0,l=Yy(l)|0,ou(0,A|0,o|0,l|0,+ +Ja(u))|0}function FFe(){var o=0;return s[7728]|0||(NFe(9628),o=7728,n[o>>2]=1,n[o+4>>2]=0),9628}function NFe(o){o=o|0,Qo(o,OFe()|0,2)}function OFe(){return 1264}function LFe(o){o=o|0,Lh(o)}function MFe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],UFe(o,u,d,1),I=A}function UFe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,T=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,T=n[u+4>>2]|0,B=n[o>>2]|0,o=kM()|0,n[L>>2]=M,n[L+4>>2]=T,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=_Fe(m)|0,n[k>>2]=M,n[k+4>>2]=T,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,HFe(m,A)|0,A),I=d}function kM(){var o=0,l=0;if(s[7744]|0||(Xz(9684),gr(37,9684,U|0)|0,l=7744,n[l>>2]=1,n[l+4>>2]=0),!(_r(9684)|0)){o=9684,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));Xz(9684)}return 9684}function _Fe(o){return o=o|0,0}function HFe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,T=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=kM()|0,M=q+24|0,o=yr(l,4)|0,n[T>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],zz(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(jFe(M,k,T),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function zz(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function jFe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,T=o+4|0,d=(((n[T>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=GFe(o)|0,m>>>0>>0)an(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,qFe(k,ae>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[T>>2]|0)-L|0)/12|0,o+8|0),T=k+8|0,m=n[T>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],zz(m,A,u),n[T>>2]=(n[T>>2]|0)+12,WFe(o,k),YFe(k),I=M;return}}function GFe(o){return o=o|0,357913941}function qFe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function WFe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function YFe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function Xz(o){o=o|0,KFe(o)}function VFe(o){o=o|0,JFe(o+24|0)}function JFe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function KFe(o){o=o|0;var l=0;l=tn()|0,rn(o,2,5,l,zFe()|0,1),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function zFe(){return 1280}function XFe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=ZFe(o)|0,o=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=o,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],u=$Fe(l,d,u)|0,I=A,u|0}function ZFe(o){return o=o|0,(n[(kM()|0)+24>>2]|0)+(o*12|0)|0}function $Fe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return B=I,I=I+32|0,d=B,m=B+16|0,A=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(A=n[(n[o>>2]|0)+A>>2]|0),tp(m,u),m=rp(m,u)|0,F2[A&15](d,o,m),m=Jz(d)|0,I=B,m|0}function eNe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],tNe(o,u,d,1),I=A}function tNe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,T=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,T=n[u+4>>2]|0,B=n[o>>2]|0,o=QM()|0,n[L>>2]=M,n[L+4>>2]=T,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=rNe(m)|0,n[k>>2]=M,n[k+4>>2]=T,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,nNe(m,A)|0,A),I=d}function QM(){var o=0,l=0;if(s[7752]|0||($z(9720),gr(38,9720,U|0)|0,l=7752,n[l>>2]=1,n[l+4>>2]=0),!(_r(9720)|0)){o=9720,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));$z(9720)}return 9720}function rNe(o){return o=o|0,0}function nNe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,T=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=QM()|0,M=q+24|0,o=yr(l,4)|0,n[T>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],Zz(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(iNe(M,k,T),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function Zz(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function iNe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,T=o+4|0,d=(((n[T>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=sNe(o)|0,m>>>0>>0)an(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,oNe(k,ae>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[T>>2]|0)-L|0)/12|0,o+8|0),T=k+8|0,m=n[T>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],Zz(m,A,u),n[T>>2]=(n[T>>2]|0)+12,aNe(o,k),lNe(k),I=M;return}}function sNe(o){return o=o|0,357913941}function oNe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function aNe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function lNe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function $z(o){o=o|0,fNe(o)}function cNe(o){o=o|0,uNe(o+24|0)}function uNe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function fNe(o){o=o|0;var l=0;l=tn()|0,rn(o,2,8,l,ANe()|0,0),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function ANe(){return 1288}function pNe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0;return u=I,I=I+16|0,A=u+8|0,d=u,m=hNe(o)|0,o=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=o,n[A>>2]=n[d>>2],n[A+4>>2]=n[d+4>>2],l=gNe(l,A)|0,I=u,l|0}function hNe(o){return o=o|0,(n[(QM()|0)+24>>2]|0)+(o*12|0)|0}function gNe(o,l){o=o|0,l=l|0;var u=0;return u=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(u=n[(n[o>>2]|0)+u>>2]|0),sd(gd[u&31](o)|0)|0}function dNe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],mNe(o,u,d,0),I=A}function mNe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,T=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,T=n[u+4>>2]|0,B=n[o>>2]|0,o=TM()|0,n[L>>2]=M,n[L+4>>2]=T,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=yNe(m)|0,n[k>>2]=M,n[k+4>>2]=T,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,ENe(m,A)|0,A),I=d}function TM(){var o=0,l=0;if(s[7760]|0||(tX(9756),gr(39,9756,U|0)|0,l=7760,n[l>>2]=1,n[l+4>>2]=0),!(_r(9756)|0)){o=9756,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));tX(9756)}return 9756}function yNe(o){return o=o|0,0}function ENe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,T=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=TM()|0,M=q+24|0,o=yr(l,4)|0,n[T>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],eX(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(INe(M,k,T),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function eX(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function INe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,T=o+4|0,d=(((n[T>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=CNe(o)|0,m>>>0>>0)an(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,wNe(k,ae>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[T>>2]|0)-L|0)/12|0,o+8|0),T=k+8|0,m=n[T>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],eX(m,A,u),n[T>>2]=(n[T>>2]|0)+12,BNe(o,k),vNe(k),I=M;return}}function CNe(o){return o=o|0,357913941}function wNe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function BNe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function vNe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function tX(o){o=o|0,bNe(o)}function SNe(o){o=o|0,DNe(o+24|0)}function DNe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function bNe(o){o=o|0;var l=0;l=tn()|0,rn(o,2,8,l,PNe()|0,1),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function PNe(){return 1292}function xNe(o,l,u){o=o|0,l=l|0,u=+u;var A=0,d=0,m=0,B=0;A=I,I=I+16|0,d=A+8|0,m=A,B=kNe(o)|0,o=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=o,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],QNe(l,d,u),I=A}function kNe(o){return o=o|0,(n[(TM()|0)+24>>2]|0)+(o*12|0)|0}function QNe(o,l,u){o=o|0,l=l|0,u=+u;var A=0,d=0,m=0;m=I,I=I+16|0,d=m,A=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(A=n[(n[o>>2]|0)+A>>2]|0),Qf(d,u),u=+Tf(d,u),OZ[A&31](o,u),I=m}function TNe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],RNe(o,u,d,0),I=A}function RNe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,T=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,T=n[u+4>>2]|0,B=n[o>>2]|0,o=RM()|0,n[L>>2]=M,n[L+4>>2]=T,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=FNe(m)|0,n[k>>2]=M,n[k+4>>2]=T,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,NNe(m,A)|0,A),I=d}function RM(){var o=0,l=0;if(s[7768]|0||(nX(9792),gr(40,9792,U|0)|0,l=7768,n[l>>2]=1,n[l+4>>2]=0),!(_r(9792)|0)){o=9792,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));nX(9792)}return 9792}function FNe(o){return o=o|0,0}function NNe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,T=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=RM()|0,M=q+24|0,o=yr(l,4)|0,n[T>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],rX(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(ONe(M,k,T),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function rX(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function ONe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,T=o+4|0,d=(((n[T>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=LNe(o)|0,m>>>0>>0)an(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,MNe(k,ae>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[T>>2]|0)-L|0)/12|0,o+8|0),T=k+8|0,m=n[T>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],rX(m,A,u),n[T>>2]=(n[T>>2]|0)+12,UNe(o,k),_Ne(k),I=M;return}}function LNe(o){return o=o|0,357913941}function MNe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function UNe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function _Ne(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function nX(o){o=o|0,GNe(o)}function HNe(o){o=o|0,jNe(o+24|0)}function jNe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function GNe(o){o=o|0;var l=0;l=tn()|0,rn(o,2,1,l,qNe()|0,2),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function qNe(){return 1300}function WNe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=+A;var d=0,m=0,B=0,k=0;d=I,I=I+16|0,m=d+8|0,B=d,k=YNe(o)|0,o=n[k+4>>2]|0,n[B>>2]=n[k>>2],n[B+4>>2]=o,n[m>>2]=n[B>>2],n[m+4>>2]=n[B+4>>2],VNe(l,m,u,A),I=d}function YNe(o){return o=o|0,(n[(RM()|0)+24>>2]|0)+(o*12|0)|0}function VNe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=+A;var d=0,m=0,B=0,k=0;k=I,I=I+16|0,m=k+1|0,B=k,d=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(d=n[(n[o>>2]|0)+d>>2]|0),tp(m,u),m=rp(m,u)|0,Qf(B,A),A=+Tf(B,A),qZ[d&15](o,m,A),I=k}function JNe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],KNe(o,u,d,0),I=A}function KNe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,T=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,T=n[u+4>>2]|0,B=n[o>>2]|0,o=FM()|0,n[L>>2]=M,n[L+4>>2]=T,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=zNe(m)|0,n[k>>2]=M,n[k+4>>2]=T,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,XNe(m,A)|0,A),I=d}function FM(){var o=0,l=0;if(s[7776]|0||(sX(9828),gr(41,9828,U|0)|0,l=7776,n[l>>2]=1,n[l+4>>2]=0),!(_r(9828)|0)){o=9828,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));sX(9828)}return 9828}function zNe(o){return o=o|0,0}function XNe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,T=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=FM()|0,M=q+24|0,o=yr(l,4)|0,n[T>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],iX(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(ZNe(M,k,T),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function iX(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function ZNe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,T=o+4|0,d=(((n[T>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=$Ne(o)|0,m>>>0>>0)an(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,eOe(k,ae>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[T>>2]|0)-L|0)/12|0,o+8|0),T=k+8|0,m=n[T>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],iX(m,A,u),n[T>>2]=(n[T>>2]|0)+12,tOe(o,k),rOe(k),I=M;return}}function $Ne(o){return o=o|0,357913941}function eOe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function tOe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function rOe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function sX(o){o=o|0,sOe(o)}function nOe(o){o=o|0,iOe(o+24|0)}function iOe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function sOe(o){o=o|0;var l=0;l=tn()|0,rn(o,2,7,l,oOe()|0,1),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function oOe(){return 1312}function aOe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;A=I,I=I+16|0,d=A+8|0,m=A,B=lOe(o)|0,o=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=o,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],cOe(l,d,u),I=A}function lOe(o){return o=o|0,(n[(FM()|0)+24>>2]|0)+(o*12|0)|0}function cOe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0;m=I,I=I+16|0,d=m,A=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(A=n[(n[o>>2]|0)+A>>2]|0),tp(d,u),d=rp(d,u)|0,sp[A&31](o,d),I=m}function uOe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],fOe(o,u,d,0),I=A}function fOe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,T=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,T=n[u+4>>2]|0,B=n[o>>2]|0,o=NM()|0,n[L>>2]=M,n[L+4>>2]=T,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=AOe(m)|0,n[k>>2]=M,n[k+4>>2]=T,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,pOe(m,A)|0,A),I=d}function NM(){var o=0,l=0;if(s[7784]|0||(aX(9864),gr(42,9864,U|0)|0,l=7784,n[l>>2]=1,n[l+4>>2]=0),!(_r(9864)|0)){o=9864,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));aX(9864)}return 9864}function AOe(o){return o=o|0,0}function pOe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,T=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=NM()|0,M=q+24|0,o=yr(l,4)|0,n[T>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],oX(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(hOe(M,k,T),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function oX(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function hOe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,T=o+4|0,d=(((n[T>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=gOe(o)|0,m>>>0>>0)an(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,dOe(k,ae>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[T>>2]|0)-L|0)/12|0,o+8|0),T=k+8|0,m=n[T>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],oX(m,A,u),n[T>>2]=(n[T>>2]|0)+12,mOe(o,k),yOe(k),I=M;return}}function gOe(o){return o=o|0,357913941}function dOe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function mOe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function yOe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function aX(o){o=o|0,COe(o)}function EOe(o){o=o|0,IOe(o+24|0)}function IOe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function COe(o){o=o|0;var l=0;l=tn()|0,rn(o,2,8,l,wOe()|0,1),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function wOe(){return 1320}function BOe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;A=I,I=I+16|0,d=A+8|0,m=A,B=vOe(o)|0,o=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=o,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],SOe(l,d,u),I=A}function vOe(o){return o=o|0,(n[(NM()|0)+24>>2]|0)+(o*12|0)|0}function SOe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0;m=I,I=I+16|0,d=m,A=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(A=n[(n[o>>2]|0)+A>>2]|0),DOe(d,u),d=bOe(d,u)|0,sp[A&31](o,d),I=m}function DOe(o,l){o=o|0,l=l|0}function bOe(o,l){return o=o|0,l=l|0,POe(l)|0}function POe(o){return o=o|0,o|0}function xOe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],kOe(o,u,d,0),I=A}function kOe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,T=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,T=n[u+4>>2]|0,B=n[o>>2]|0,o=OM()|0,n[L>>2]=M,n[L+4>>2]=T,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=QOe(m)|0,n[k>>2]=M,n[k+4>>2]=T,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,TOe(m,A)|0,A),I=d}function OM(){var o=0,l=0;if(s[7792]|0||(cX(9900),gr(43,9900,U|0)|0,l=7792,n[l>>2]=1,n[l+4>>2]=0),!(_r(9900)|0)){o=9900,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));cX(9900)}return 9900}function QOe(o){return o=o|0,0}function TOe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,T=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=OM()|0,M=q+24|0,o=yr(l,4)|0,n[T>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],lX(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(ROe(M,k,T),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function lX(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function ROe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,T=o+4|0,d=(((n[T>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=FOe(o)|0,m>>>0>>0)an(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,NOe(k,ae>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[T>>2]|0)-L|0)/12|0,o+8|0),T=k+8|0,m=n[T>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],lX(m,A,u),n[T>>2]=(n[T>>2]|0)+12,OOe(o,k),LOe(k),I=M;return}}function FOe(o){return o=o|0,357913941}function NOe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function OOe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function LOe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function cX(o){o=o|0,_Oe(o)}function MOe(o){o=o|0,UOe(o+24|0)}function UOe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function _Oe(o){o=o|0;var l=0;l=tn()|0,rn(o,2,22,l,HOe()|0,0),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function HOe(){return 1344}function jOe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0;u=I,I=I+16|0,A=u+8|0,d=u,m=GOe(o)|0,o=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=o,n[A>>2]=n[d>>2],n[A+4>>2]=n[d+4>>2],qOe(l,A),I=u}function GOe(o){return o=o|0,(n[(OM()|0)+24>>2]|0)+(o*12|0)|0}function qOe(o,l){o=o|0,l=l|0;var u=0;u=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(u=n[(n[o>>2]|0)+u>>2]|0),ip[u&127](o)}function WOe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0;m=n[o>>2]|0,d=LM()|0,o=YOe(u)|0,vn(m,l,d,o,VOe(u,A)|0,A)}function LM(){var o=0,l=0;if(s[7800]|0||(fX(9936),gr(44,9936,U|0)|0,l=7800,n[l>>2]=1,n[l+4>>2]=0),!(_r(9936)|0)){o=9936,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));fX(9936)}return 9936}function YOe(o){return o=o|0,o|0}function VOe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0;return k=I,I=I+16|0,d=k,m=k+4|0,n[d>>2]=o,T=LM()|0,B=T+24|0,l=yr(l,4)|0,n[m>>2]=l,u=T+28|0,A=n[u>>2]|0,A>>>0<(n[T+32>>2]|0)>>>0?(uX(A,o,l),l=(n[u>>2]|0)+8|0,n[u>>2]=l):(JOe(B,d,m),l=n[u>>2]|0),I=k,(l-(n[B>>2]|0)>>3)+-1|0}function uX(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,n[o+4>>2]=u}function JOe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0;if(k=I,I=I+32|0,d=k,m=o+4|0,B=((n[m>>2]|0)-(n[o>>2]|0)>>3)+1|0,A=KOe(o)|0,A>>>0>>0)an(o);else{T=n[o>>2]|0,L=(n[o+8>>2]|0)-T|0,M=L>>2,zOe(d,L>>3>>>0>>1>>>0?M>>>0>>0?B:M:A,(n[m>>2]|0)-T>>3,o+8|0),B=d+8|0,uX(n[B>>2]|0,n[l>>2]|0,n[u>>2]|0),n[B>>2]=(n[B>>2]|0)+8,XOe(o,d),ZOe(d),I=k;return}}function KOe(o){return o=o|0,536870911}function zOe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>536870911)Nt();else{d=Kt(l<<3)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u<<3)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l<<3)}function XOe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function ZOe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~((A+-8-l|0)>>>3)<<3)),o=n[o>>2]|0,o|0&&It(o)}function fX(o){o=o|0,tLe(o)}function $Oe(o){o=o|0,eLe(o+24|0)}function eLe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function tLe(o){o=o|0;var l=0;l=tn()|0,rn(o,1,23,l,Uz()|0,1),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function rLe(o,l){o=o|0,l=l|0,iLe(n[(nLe(o)|0)>>2]|0,l)}function nLe(o){return o=o|0,(n[(LM()|0)+24>>2]|0)+(o<<3)|0}function iLe(o,l){o=o|0,l=l|0;var u=0,A=0;u=I,I=I+16|0,A=u,BM(A,l),l=vM(A,l)|0,ip[o&127](l),I=u}function sLe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0;m=n[o>>2]|0,d=MM()|0,o=oLe(u)|0,vn(m,l,d,o,aLe(u,A)|0,A)}function MM(){var o=0,l=0;if(s[7808]|0||(pX(9972),gr(45,9972,U|0)|0,l=7808,n[l>>2]=1,n[l+4>>2]=0),!(_r(9972)|0)){o=9972,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));pX(9972)}return 9972}function oLe(o){return o=o|0,o|0}function aLe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0;return k=I,I=I+16|0,d=k,m=k+4|0,n[d>>2]=o,T=MM()|0,B=T+24|0,l=yr(l,4)|0,n[m>>2]=l,u=T+28|0,A=n[u>>2]|0,A>>>0<(n[T+32>>2]|0)>>>0?(AX(A,o,l),l=(n[u>>2]|0)+8|0,n[u>>2]=l):(lLe(B,d,m),l=n[u>>2]|0),I=k,(l-(n[B>>2]|0)>>3)+-1|0}function AX(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,n[o+4>>2]=u}function lLe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0;if(k=I,I=I+32|0,d=k,m=o+4|0,B=((n[m>>2]|0)-(n[o>>2]|0)>>3)+1|0,A=cLe(o)|0,A>>>0>>0)an(o);else{T=n[o>>2]|0,L=(n[o+8>>2]|0)-T|0,M=L>>2,uLe(d,L>>3>>>0>>1>>>0?M>>>0>>0?B:M:A,(n[m>>2]|0)-T>>3,o+8|0),B=d+8|0,AX(n[B>>2]|0,n[l>>2]|0,n[u>>2]|0),n[B>>2]=(n[B>>2]|0)+8,fLe(o,d),ALe(d),I=k;return}}function cLe(o){return o=o|0,536870911}function uLe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>536870911)Nt();else{d=Kt(l<<3)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u<<3)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l<<3)}function fLe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function ALe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~((A+-8-l|0)>>>3)<<3)),o=n[o>>2]|0,o|0&&It(o)}function pX(o){o=o|0,gLe(o)}function pLe(o){o=o|0,hLe(o+24|0)}function hLe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function gLe(o){o=o|0;var l=0;l=tn()|0,rn(o,1,9,l,dLe()|0,1),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function dLe(){return 1348}function mLe(o,l){return o=o|0,l=l|0,ELe(n[(yLe(o)|0)>>2]|0,l)|0}function yLe(o){return o=o|0,(n[(MM()|0)+24>>2]|0)+(o<<3)|0}function ELe(o,l){o=o|0,l=l|0;var u=0,A=0;return u=I,I=I+16|0,A=u,hX(A,l),l=gX(A,l)|0,l=TP(gd[o&31](l)|0)|0,I=u,l|0}function hX(o,l){o=o|0,l=l|0}function gX(o,l){return o=o|0,l=l|0,ILe(l)|0}function ILe(o){return o=o|0,o|0}function CLe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0;m=n[o>>2]|0,d=UM()|0,o=wLe(u)|0,vn(m,l,d,o,BLe(u,A)|0,A)}function UM(){var o=0,l=0;if(s[7816]|0||(mX(10008),gr(46,10008,U|0)|0,l=7816,n[l>>2]=1,n[l+4>>2]=0),!(_r(10008)|0)){o=10008,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));mX(10008)}return 10008}function wLe(o){return o=o|0,o|0}function BLe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0;return k=I,I=I+16|0,d=k,m=k+4|0,n[d>>2]=o,T=UM()|0,B=T+24|0,l=yr(l,4)|0,n[m>>2]=l,u=T+28|0,A=n[u>>2]|0,A>>>0<(n[T+32>>2]|0)>>>0?(dX(A,o,l),l=(n[u>>2]|0)+8|0,n[u>>2]=l):(vLe(B,d,m),l=n[u>>2]|0),I=k,(l-(n[B>>2]|0)>>3)+-1|0}function dX(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,n[o+4>>2]=u}function vLe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0;if(k=I,I=I+32|0,d=k,m=o+4|0,B=((n[m>>2]|0)-(n[o>>2]|0)>>3)+1|0,A=SLe(o)|0,A>>>0>>0)an(o);else{T=n[o>>2]|0,L=(n[o+8>>2]|0)-T|0,M=L>>2,DLe(d,L>>3>>>0>>1>>>0?M>>>0>>0?B:M:A,(n[m>>2]|0)-T>>3,o+8|0),B=d+8|0,dX(n[B>>2]|0,n[l>>2]|0,n[u>>2]|0),n[B>>2]=(n[B>>2]|0)+8,bLe(o,d),PLe(d),I=k;return}}function SLe(o){return o=o|0,536870911}function DLe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>536870911)Nt();else{d=Kt(l<<3)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u<<3)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l<<3)}function bLe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function PLe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~((A+-8-l|0)>>>3)<<3)),o=n[o>>2]|0,o|0&&It(o)}function mX(o){o=o|0,QLe(o)}function xLe(o){o=o|0,kLe(o+24|0)}function kLe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function QLe(o){o=o|0;var l=0;l=tn()|0,rn(o,1,15,l,Rz()|0,0),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function TLe(o){return o=o|0,FLe(n[(RLe(o)|0)>>2]|0)|0}function RLe(o){return o=o|0,(n[(UM()|0)+24>>2]|0)+(o<<3)|0}function FLe(o){return o=o|0,TP(VP[o&7]()|0)|0}function NLe(){var o=0;return s[7832]|0||(GLe(10052),gr(25,10052,U|0)|0,o=7832,n[o>>2]=1,n[o+4>>2]=0),10052}function OLe(o,l){o=o|0,l=l|0,n[o>>2]=LLe()|0,n[o+4>>2]=MLe()|0,n[o+12>>2]=l,n[o+8>>2]=ULe()|0,n[o+32>>2]=2}function LLe(){return 11709}function MLe(){return 1188}function ULe(){return FP()|0}function _Le(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0,(Hh(A,896)|0)==512?u|0&&(HLe(u),It(u)):l|0&&(Oy(l),It(l))}function Hh(o,l){return o=o|0,l=l|0,l&o|0}function HLe(o){o=o|0,o=n[o+4>>2]|0,o|0&&Gh(o)}function FP(){var o=0;return s[7824]|0||(n[2511]=jLe()|0,n[2512]=0,o=7824,n[o>>2]=1,n[o+4>>2]=0),10044}function jLe(){return 0}function GLe(o){o=o|0,Lh(o)}function qLe(o){o=o|0;var l=0,u=0,A=0,d=0,m=0;l=I,I=I+32|0,u=l+24|0,m=l+16|0,d=l+8|0,A=l,WLe(o,4827),YLe(o,4834,3)|0,VLe(o,3682,47)|0,n[m>>2]=9,n[m+4>>2]=0,n[u>>2]=n[m>>2],n[u+4>>2]=n[m+4>>2],JLe(o,4841,u)|0,n[d>>2]=1,n[d+4>>2]=0,n[u>>2]=n[d>>2],n[u+4>>2]=n[d+4>>2],KLe(o,4871,u)|0,n[A>>2]=10,n[A+4>>2]=0,n[u>>2]=n[A>>2],n[u+4>>2]=n[A+4>>2],zLe(o,4891,u)|0,I=l}function WLe(o,l){o=o|0,l=l|0;var u=0;u=PUe()|0,n[o>>2]=u,xUe(u,l),jh(n[o>>2]|0)}function YLe(o,l,u){return o=o|0,l=l|0,u=u|0,AUe(o,Bn(l)|0,u,0),o|0}function VLe(o,l,u){return o=o|0,l=l|0,u=u|0,XMe(o,Bn(l)|0,u,0),o|0}function JLe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],TMe(o,l,d),I=A,o|0}function KLe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],pMe(o,l,d),I=A,o|0}function zLe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],XLe(o,l,d),I=A,o|0}function XLe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],ZLe(o,u,d,1),I=A}function ZLe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,T=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,T=n[u+4>>2]|0,B=n[o>>2]|0,o=_M()|0,n[L>>2]=M,n[L+4>>2]=T,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=$Le(m)|0,n[k>>2]=M,n[k+4>>2]=T,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,eMe(m,A)|0,A),I=d}function _M(){var o=0,l=0;if(s[7840]|0||(EX(10100),gr(48,10100,U|0)|0,l=7840,n[l>>2]=1,n[l+4>>2]=0),!(_r(10100)|0)){o=10100,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));EX(10100)}return 10100}function $Le(o){return o=o|0,0}function eMe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,T=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=_M()|0,M=q+24|0,o=yr(l,4)|0,n[T>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],yX(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(tMe(M,k,T),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function yX(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function tMe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,T=o+4|0,d=(((n[T>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=rMe(o)|0,m>>>0>>0)an(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,nMe(k,ae>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[T>>2]|0)-L|0)/12|0,o+8|0),T=k+8|0,m=n[T>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],yX(m,A,u),n[T>>2]=(n[T>>2]|0)+12,iMe(o,k),sMe(k),I=M;return}}function rMe(o){return o=o|0,357913941}function nMe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function iMe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function sMe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function EX(o){o=o|0,lMe(o)}function oMe(o){o=o|0,aMe(o+24|0)}function aMe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function lMe(o){o=o|0;var l=0;l=tn()|0,rn(o,2,6,l,cMe()|0,1),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function cMe(){return 1364}function uMe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=fMe(o)|0,o=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=o,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],u=AMe(l,d,u)|0,I=A,u|0}function fMe(o){return o=o|0,(n[(_M()|0)+24>>2]|0)+(o*12|0)|0}function AMe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0;return m=I,I=I+16|0,d=m,A=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(A=n[(n[o>>2]|0)+A>>2]|0),tp(d,u),d=rp(d,u)|0,d=Dz(gU[A&15](o,d)|0)|0,I=m,d|0}function pMe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],hMe(o,u,d,0),I=A}function hMe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,T=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,T=n[u+4>>2]|0,B=n[o>>2]|0,o=HM()|0,n[L>>2]=M,n[L+4>>2]=T,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=gMe(m)|0,n[k>>2]=M,n[k+4>>2]=T,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,dMe(m,A)|0,A),I=d}function HM(){var o=0,l=0;if(s[7848]|0||(CX(10136),gr(49,10136,U|0)|0,l=7848,n[l>>2]=1,n[l+4>>2]=0),!(_r(10136)|0)){o=10136,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));CX(10136)}return 10136}function gMe(o){return o=o|0,0}function dMe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,T=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=HM()|0,M=q+24|0,o=yr(l,4)|0,n[T>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],IX(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(mMe(M,k,T),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function IX(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function mMe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,T=o+4|0,d=(((n[T>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=yMe(o)|0,m>>>0>>0)an(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,EMe(k,ae>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[T>>2]|0)-L|0)/12|0,o+8|0),T=k+8|0,m=n[T>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],IX(m,A,u),n[T>>2]=(n[T>>2]|0)+12,IMe(o,k),CMe(k),I=M;return}}function yMe(o){return o=o|0,357913941}function EMe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function IMe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function CMe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function CX(o){o=o|0,vMe(o)}function wMe(o){o=o|0,BMe(o+24|0)}function BMe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function vMe(o){o=o|0;var l=0;l=tn()|0,rn(o,2,9,l,SMe()|0,1),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function SMe(){return 1372}function DMe(o,l,u){o=o|0,l=l|0,u=+u;var A=0,d=0,m=0,B=0;A=I,I=I+16|0,d=A+8|0,m=A,B=bMe(o)|0,o=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=o,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],PMe(l,d,u),I=A}function bMe(o){return o=o|0,(n[(HM()|0)+24>>2]|0)+(o*12|0)|0}function PMe(o,l,u){o=o|0,l=l|0,u=+u;var A=0,d=0,m=0,B=$e;m=I,I=I+16|0,d=m,A=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(A=n[(n[o>>2]|0)+A>>2]|0),xMe(d,u),B=y(kMe(d,u)),NZ[A&1](o,B),I=m}function xMe(o,l){o=o|0,l=+l}function kMe(o,l){return o=o|0,l=+l,y(QMe(l))}function QMe(o){return o=+o,y(o)}function TMe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],RMe(o,u,d,0),I=A}function RMe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,T=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,T=n[u+4>>2]|0,B=n[o>>2]|0,o=jM()|0,n[L>>2]=M,n[L+4>>2]=T,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=FMe(m)|0,n[k>>2]=M,n[k+4>>2]=T,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,NMe(m,A)|0,A),I=d}function jM(){var o=0,l=0;if(s[7856]|0||(BX(10172),gr(50,10172,U|0)|0,l=7856,n[l>>2]=1,n[l+4>>2]=0),!(_r(10172)|0)){o=10172,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));BX(10172)}return 10172}function FMe(o){return o=o|0,0}function NMe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,T=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=jM()|0,M=q+24|0,o=yr(l,4)|0,n[T>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],wX(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(OMe(M,k,T),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function wX(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function OMe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,T=o+4|0,d=(((n[T>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=LMe(o)|0,m>>>0>>0)an(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,MMe(k,ae>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[T>>2]|0)-L|0)/12|0,o+8|0),T=k+8|0,m=n[T>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],wX(m,A,u),n[T>>2]=(n[T>>2]|0)+12,UMe(o,k),_Me(k),I=M;return}}function LMe(o){return o=o|0,357913941}function MMe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function UMe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function _Me(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function BX(o){o=o|0,GMe(o)}function HMe(o){o=o|0,jMe(o+24|0)}function jMe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function GMe(o){o=o|0;var l=0;l=tn()|0,rn(o,2,3,l,qMe()|0,2),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function qMe(){return 1380}function WMe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0;d=I,I=I+16|0,m=d+8|0,B=d,k=YMe(o)|0,o=n[k+4>>2]|0,n[B>>2]=n[k>>2],n[B+4>>2]=o,n[m>>2]=n[B>>2],n[m+4>>2]=n[B+4>>2],VMe(l,m,u,A),I=d}function YMe(o){return o=o|0,(n[(jM()|0)+24>>2]|0)+(o*12|0)|0}function VMe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0;k=I,I=I+16|0,m=k+1|0,B=k,d=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(d=n[(n[o>>2]|0)+d>>2]|0),tp(m,u),m=rp(m,u)|0,JMe(B,A),B=KMe(B,A)|0,F2[d&15](o,m,B),I=k}function JMe(o,l){o=o|0,l=l|0}function KMe(o,l){return o=o|0,l=l|0,zMe(l)|0}function zMe(o){return o=o|0,(o|0)!=0|0}function XMe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0;m=n[o>>2]|0,d=GM()|0,o=ZMe(u)|0,vn(m,l,d,o,$Me(u,A)|0,A)}function GM(){var o=0,l=0;if(s[7864]|0||(SX(10208),gr(51,10208,U|0)|0,l=7864,n[l>>2]=1,n[l+4>>2]=0),!(_r(10208)|0)){o=10208,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));SX(10208)}return 10208}function ZMe(o){return o=o|0,o|0}function $Me(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0;return k=I,I=I+16|0,d=k,m=k+4|0,n[d>>2]=o,T=GM()|0,B=T+24|0,l=yr(l,4)|0,n[m>>2]=l,u=T+28|0,A=n[u>>2]|0,A>>>0<(n[T+32>>2]|0)>>>0?(vX(A,o,l),l=(n[u>>2]|0)+8|0,n[u>>2]=l):(eUe(B,d,m),l=n[u>>2]|0),I=k,(l-(n[B>>2]|0)>>3)+-1|0}function vX(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,n[o+4>>2]=u}function eUe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0;if(k=I,I=I+32|0,d=k,m=o+4|0,B=((n[m>>2]|0)-(n[o>>2]|0)>>3)+1|0,A=tUe(o)|0,A>>>0>>0)an(o);else{T=n[o>>2]|0,L=(n[o+8>>2]|0)-T|0,M=L>>2,rUe(d,L>>3>>>0>>1>>>0?M>>>0>>0?B:M:A,(n[m>>2]|0)-T>>3,o+8|0),B=d+8|0,vX(n[B>>2]|0,n[l>>2]|0,n[u>>2]|0),n[B>>2]=(n[B>>2]|0)+8,nUe(o,d),iUe(d),I=k;return}}function tUe(o){return o=o|0,536870911}function rUe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>536870911)Nt();else{d=Kt(l<<3)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u<<3)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l<<3)}function nUe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function iUe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~((A+-8-l|0)>>>3)<<3)),o=n[o>>2]|0,o|0&&It(o)}function SX(o){o=o|0,aUe(o)}function sUe(o){o=o|0,oUe(o+24|0)}function oUe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function aUe(o){o=o|0;var l=0;l=tn()|0,rn(o,1,24,l,lUe()|0,1),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function lUe(){return 1392}function cUe(o,l){o=o|0,l=l|0,fUe(n[(uUe(o)|0)>>2]|0,l)}function uUe(o){return o=o|0,(n[(GM()|0)+24>>2]|0)+(o<<3)|0}function fUe(o,l){o=o|0,l=l|0;var u=0,A=0;u=I,I=I+16|0,A=u,hX(A,l),l=gX(A,l)|0,ip[o&127](l),I=u}function AUe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0;m=n[o>>2]|0,d=qM()|0,o=pUe(u)|0,vn(m,l,d,o,hUe(u,A)|0,A)}function qM(){var o=0,l=0;if(s[7872]|0||(bX(10244),gr(52,10244,U|0)|0,l=7872,n[l>>2]=1,n[l+4>>2]=0),!(_r(10244)|0)){o=10244,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));bX(10244)}return 10244}function pUe(o){return o=o|0,o|0}function hUe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0;return k=I,I=I+16|0,d=k,m=k+4|0,n[d>>2]=o,T=qM()|0,B=T+24|0,l=yr(l,4)|0,n[m>>2]=l,u=T+28|0,A=n[u>>2]|0,A>>>0<(n[T+32>>2]|0)>>>0?(DX(A,o,l),l=(n[u>>2]|0)+8|0,n[u>>2]=l):(gUe(B,d,m),l=n[u>>2]|0),I=k,(l-(n[B>>2]|0)>>3)+-1|0}function DX(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,n[o+4>>2]=u}function gUe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0;if(k=I,I=I+32|0,d=k,m=o+4|0,B=((n[m>>2]|0)-(n[o>>2]|0)>>3)+1|0,A=dUe(o)|0,A>>>0>>0)an(o);else{T=n[o>>2]|0,L=(n[o+8>>2]|0)-T|0,M=L>>2,mUe(d,L>>3>>>0>>1>>>0?M>>>0>>0?B:M:A,(n[m>>2]|0)-T>>3,o+8|0),B=d+8|0,DX(n[B>>2]|0,n[l>>2]|0,n[u>>2]|0),n[B>>2]=(n[B>>2]|0)+8,yUe(o,d),EUe(d),I=k;return}}function dUe(o){return o=o|0,536870911}function mUe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>536870911)Nt();else{d=Kt(l<<3)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u<<3)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l<<3)}function yUe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function EUe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~((A+-8-l|0)>>>3)<<3)),o=n[o>>2]|0,o|0&&It(o)}function bX(o){o=o|0,wUe(o)}function IUe(o){o=o|0,CUe(o+24|0)}function CUe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function wUe(o){o=o|0;var l=0;l=tn()|0,rn(o,1,16,l,BUe()|0,0),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function BUe(){return 1400}function vUe(o){return o=o|0,DUe(n[(SUe(o)|0)>>2]|0)|0}function SUe(o){return o=o|0,(n[(qM()|0)+24>>2]|0)+(o<<3)|0}function DUe(o){return o=o|0,bUe(VP[o&7]()|0)|0}function bUe(o){return o=o|0,o|0}function PUe(){var o=0;return s[7880]|0||(NUe(10280),gr(25,10280,U|0)|0,o=7880,n[o>>2]=1,n[o+4>>2]=0),10280}function xUe(o,l){o=o|0,l=l|0,n[o>>2]=kUe()|0,n[o+4>>2]=QUe()|0,n[o+12>>2]=l,n[o+8>>2]=TUe()|0,n[o+32>>2]=4}function kUe(){return 11711}function QUe(){return 1356}function TUe(){return FP()|0}function RUe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0,(Hh(A,896)|0)==512?u|0&&(FUe(u),It(u)):l|0&&(Kg(l),It(l))}function FUe(o){o=o|0,o=n[o+4>>2]|0,o|0&&Gh(o)}function NUe(o){o=o|0,Lh(o)}function OUe(o){o=o|0,LUe(o,4920),MUe(o)|0,UUe(o)|0}function LUe(o,l){o=o|0,l=l|0;var u=0;u=Kz()|0,n[o>>2]=u,o_e(u,l),jh(n[o>>2]|0)}function MUe(o){o=o|0;var l=0;return l=n[o>>2]|0,cd(l,zUe()|0),o|0}function UUe(o){o=o|0;var l=0;return l=n[o>>2]|0,cd(l,_Ue()|0),o|0}function _Ue(){var o=0;return s[7888]|0||(PX(10328),gr(53,10328,U|0)|0,o=7888,n[o>>2]=1,n[o+4>>2]=0),_r(10328)|0||PX(10328),10328}function cd(o,l){o=o|0,l=l|0,vn(o,0,l,0,0,0)}function PX(o){o=o|0,GUe(o),ud(o,10)}function HUe(o){o=o|0,jUe(o+24|0)}function jUe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function GUe(o){o=o|0;var l=0;l=tn()|0,rn(o,5,1,l,VUe()|0,2),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function qUe(o,l,u){o=o|0,l=l|0,u=+u,WUe(o,l,u)}function ud(o,l){o=o|0,l=l|0,n[o+20>>2]=l}function WUe(o,l,u){o=o|0,l=l|0,u=+u;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,m=A+8|0,k=A+13|0,d=A,B=A+12|0,tp(k,l),n[m>>2]=rp(k,l)|0,Qf(B,u),E[d>>3]=+Tf(B,u),YUe(o,m,d),I=A}function YUe(o,l,u){o=o|0,l=l|0,u=u|0,Tl(o+8|0,n[l>>2]|0,+E[u>>3]),s[o+24>>0]=1}function VUe(){return 1404}function JUe(o,l){return o=o|0,l=+l,KUe(o,l)|0}function KUe(o,l){o=o|0,l=+l;var u=0,A=0,d=0,m=0,B=0,k=0,T=0;return A=I,I=I+16|0,m=A+4|0,B=A+8|0,k=A,d=Rl(8)|0,u=d,T=Kt(16)|0,tp(m,o),o=rp(m,o)|0,Qf(B,l),Tl(T,o,+Tf(B,l)),B=u+4|0,n[B>>2]=T,o=Kt(8)|0,B=n[B>>2]|0,n[k>>2]=0,n[m>>2]=n[k>>2],xM(o,B,m),n[d>>2]=o,I=A,u|0}function zUe(){var o=0;return s[7896]|0||(xX(10364),gr(54,10364,U|0)|0,o=7896,n[o>>2]=1,n[o+4>>2]=0),_r(10364)|0||xX(10364),10364}function xX(o){o=o|0,$Ue(o),ud(o,55)}function XUe(o){o=o|0,ZUe(o+24|0)}function ZUe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function $Ue(o){o=o|0;var l=0;l=tn()|0,rn(o,5,4,l,n_e()|0,0),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function e_e(o){o=o|0,t_e(o)}function t_e(o){o=o|0,r_e(o)}function r_e(o){o=o|0,kX(o+8|0),s[o+24>>0]=1}function kX(o){o=o|0,n[o>>2]=0,E[o+8>>3]=0}function n_e(){return 1424}function i_e(){return s_e()|0}function s_e(){var o=0,l=0,u=0,A=0,d=0,m=0,B=0;return l=I,I=I+16|0,d=l+4|0,B=l,u=Rl(8)|0,o=u,A=Kt(16)|0,kX(A),m=o+4|0,n[m>>2]=A,A=Kt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],xM(A,m,d),n[u>>2]=A,I=l,o|0}function o_e(o,l){o=o|0,l=l|0,n[o>>2]=a_e()|0,n[o+4>>2]=l_e()|0,n[o+12>>2]=l,n[o+8>>2]=c_e()|0,n[o+32>>2]=5}function a_e(){return 11710}function l_e(){return 1416}function c_e(){return NP()|0}function u_e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0,(Hh(A,896)|0)==512?u|0&&(f_e(u),It(u)):l|0&&It(l)}function f_e(o){o=o|0,o=n[o+4>>2]|0,o|0&&Gh(o)}function NP(){var o=0;return s[7904]|0||(n[2600]=A_e()|0,n[2601]=0,o=7904,n[o>>2]=1,n[o+4>>2]=0),10400}function A_e(){return n[357]|0}function p_e(o){o=o|0,h_e(o,4926),g_e(o)|0}function h_e(o,l){o=o|0,l=l|0;var u=0;u=yz()|0,n[o>>2]=u,D_e(u,l),jh(n[o>>2]|0)}function g_e(o){o=o|0;var l=0;return l=n[o>>2]|0,cd(l,d_e()|0),o|0}function d_e(){var o=0;return s[7912]|0||(QX(10412),gr(56,10412,U|0)|0,o=7912,n[o>>2]=1,n[o+4>>2]=0),_r(10412)|0||QX(10412),10412}function QX(o){o=o|0,E_e(o),ud(o,57)}function m_e(o){o=o|0,y_e(o+24|0)}function y_e(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function E_e(o){o=o|0;var l=0;l=tn()|0,rn(o,5,5,l,B_e()|0,0),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function I_e(o){o=o|0,C_e(o)}function C_e(o){o=o|0,w_e(o)}function w_e(o){o=o|0;var l=0,u=0;l=o+8|0,u=l+48|0;do n[l>>2]=0,l=l+4|0;while((l|0)<(u|0));s[o+56>>0]=1}function B_e(){return 1432}function v_e(){return S_e()|0}function S_e(){var o=0,l=0,u=0,A=0,d=0,m=0,B=0,k=0;B=I,I=I+16|0,o=B+4|0,l=B,u=Rl(8)|0,A=u,d=Kt(48)|0,m=d,k=m+48|0;do n[m>>2]=0,m=m+4|0;while((m|0)<(k|0));return m=A+4|0,n[m>>2]=d,k=Kt(8)|0,m=n[m>>2]|0,n[l>>2]=0,n[o>>2]=n[l>>2],Ez(k,m,o),n[u>>2]=k,I=B,A|0}function D_e(o,l){o=o|0,l=l|0,n[o>>2]=b_e()|0,n[o+4>>2]=P_e()|0,n[o+12>>2]=l,n[o+8>>2]=x_e()|0,n[o+32>>2]=6}function b_e(){return 11704}function P_e(){return 1436}function x_e(){return NP()|0}function k_e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0,(Hh(A,896)|0)==512?u|0&&(Q_e(u),It(u)):l|0&&It(l)}function Q_e(o){o=o|0,o=n[o+4>>2]|0,o|0&&Gh(o)}function T_e(o){o=o|0,R_e(o,4933),F_e(o)|0,N_e(o)|0}function R_e(o,l){o=o|0,l=l|0;var u=0;u=s4e()|0,n[o>>2]=u,o4e(u,l),jh(n[o>>2]|0)}function F_e(o){o=o|0;var l=0;return l=n[o>>2]|0,cd(l,K_e()|0),o|0}function N_e(o){o=o|0;var l=0;return l=n[o>>2]|0,cd(l,O_e()|0),o|0}function O_e(){var o=0;return s[7920]|0||(TX(10452),gr(58,10452,U|0)|0,o=7920,n[o>>2]=1,n[o+4>>2]=0),_r(10452)|0||TX(10452),10452}function TX(o){o=o|0,U_e(o),ud(o,1)}function L_e(o){o=o|0,M_e(o+24|0)}function M_e(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function U_e(o){o=o|0;var l=0;l=tn()|0,rn(o,5,1,l,G_e()|0,2),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function __e(o,l,u){o=o|0,l=+l,u=+u,H_e(o,l,u)}function H_e(o,l,u){o=o|0,l=+l,u=+u;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+32|0,m=A+8|0,k=A+17|0,d=A,B=A+16|0,Qf(k,l),E[m>>3]=+Tf(k,l),Qf(B,u),E[d>>3]=+Tf(B,u),j_e(o,m,d),I=A}function j_e(o,l,u){o=o|0,l=l|0,u=u|0,RX(o+8|0,+E[l>>3],+E[u>>3]),s[o+24>>0]=1}function RX(o,l,u){o=o|0,l=+l,u=+u,E[o>>3]=l,E[o+8>>3]=u}function G_e(){return 1472}function q_e(o,l){return o=+o,l=+l,W_e(o,l)|0}function W_e(o,l){o=+o,l=+l;var u=0,A=0,d=0,m=0,B=0,k=0,T=0;return A=I,I=I+16|0,B=A+4|0,k=A+8|0,T=A,d=Rl(8)|0,u=d,m=Kt(16)|0,Qf(B,o),o=+Tf(B,o),Qf(k,l),RX(m,o,+Tf(k,l)),k=u+4|0,n[k>>2]=m,m=Kt(8)|0,k=n[k>>2]|0,n[T>>2]=0,n[B>>2]=n[T>>2],FX(m,k,B),n[d>>2]=m,I=A,u|0}function FX(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,u=Kt(16)|0,n[u+4>>2]=0,n[u+8>>2]=0,n[u>>2]=1452,n[u+12>>2]=l,n[o+4>>2]=u}function Y_e(o){o=o|0,$y(o),It(o)}function V_e(o){o=o|0,o=n[o+12>>2]|0,o|0&&It(o)}function J_e(o){o=o|0,It(o)}function K_e(){var o=0;return s[7928]|0||(NX(10488),gr(59,10488,U|0)|0,o=7928,n[o>>2]=1,n[o+4>>2]=0),_r(10488)|0||NX(10488),10488}function NX(o){o=o|0,Z_e(o),ud(o,60)}function z_e(o){o=o|0,X_e(o+24|0)}function X_e(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function Z_e(o){o=o|0;var l=0;l=tn()|0,rn(o,5,6,l,r4e()|0,0),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function $_e(o){o=o|0,e4e(o)}function e4e(o){o=o|0,t4e(o)}function t4e(o){o=o|0,OX(o+8|0),s[o+24>>0]=1}function OX(o){o=o|0,n[o>>2]=0,n[o+4>>2]=0,n[o+8>>2]=0,n[o+12>>2]=0}function r4e(){return 1492}function n4e(){return i4e()|0}function i4e(){var o=0,l=0,u=0,A=0,d=0,m=0,B=0;return l=I,I=I+16|0,d=l+4|0,B=l,u=Rl(8)|0,o=u,A=Kt(16)|0,OX(A),m=o+4|0,n[m>>2]=A,A=Kt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],FX(A,m,d),n[u>>2]=A,I=l,o|0}function s4e(){var o=0;return s[7936]|0||(A4e(10524),gr(25,10524,U|0)|0,o=7936,n[o>>2]=1,n[o+4>>2]=0),10524}function o4e(o,l){o=o|0,l=l|0,n[o>>2]=a4e()|0,n[o+4>>2]=l4e()|0,n[o+12>>2]=l,n[o+8>>2]=c4e()|0,n[o+32>>2]=7}function a4e(){return 11700}function l4e(){return 1484}function c4e(){return NP()|0}function u4e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0,(Hh(A,896)|0)==512?u|0&&(f4e(u),It(u)):l|0&&It(l)}function f4e(o){o=o|0,o=n[o+4>>2]|0,o|0&&Gh(o)}function A4e(o){o=o|0,Lh(o)}function p4e(o,l,u){o=o|0,l=l|0,u=u|0,o=Bn(l)|0,l=h4e(u)|0,u=g4e(u,0)|0,W4e(o,l,u,WM()|0,0)}function h4e(o){return o=o|0,o|0}function g4e(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0;return k=I,I=I+16|0,d=k,m=k+4|0,n[d>>2]=o,T=WM()|0,B=T+24|0,l=yr(l,4)|0,n[m>>2]=l,u=T+28|0,A=n[u>>2]|0,A>>>0<(n[T+32>>2]|0)>>>0?(MX(A,o,l),l=(n[u>>2]|0)+8|0,n[u>>2]=l):(w4e(B,d,m),l=n[u>>2]|0),I=k,(l-(n[B>>2]|0)>>3)+-1|0}function WM(){var o=0,l=0;if(s[7944]|0||(LX(10568),gr(61,10568,U|0)|0,l=7944,n[l>>2]=1,n[l+4>>2]=0),!(_r(10568)|0)){o=10568,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));LX(10568)}return 10568}function LX(o){o=o|0,y4e(o)}function d4e(o){o=o|0,m4e(o+24|0)}function m4e(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function y4e(o){o=o|0;var l=0;l=tn()|0,rn(o,1,17,l,Oz()|0,0),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function E4e(o){return o=o|0,C4e(n[(I4e(o)|0)>>2]|0)|0}function I4e(o){return o=o|0,(n[(WM()|0)+24>>2]|0)+(o<<3)|0}function C4e(o){return o=o|0,RP(VP[o&7]()|0)|0}function MX(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,n[o+4>>2]=u}function w4e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0;if(k=I,I=I+32|0,d=k,m=o+4|0,B=((n[m>>2]|0)-(n[o>>2]|0)>>3)+1|0,A=B4e(o)|0,A>>>0>>0)an(o);else{T=n[o>>2]|0,L=(n[o+8>>2]|0)-T|0,M=L>>2,v4e(d,L>>3>>>0>>1>>>0?M>>>0>>0?B:M:A,(n[m>>2]|0)-T>>3,o+8|0),B=d+8|0,MX(n[B>>2]|0,n[l>>2]|0,n[u>>2]|0),n[B>>2]=(n[B>>2]|0)+8,S4e(o,d),D4e(d),I=k;return}}function B4e(o){return o=o|0,536870911}function v4e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>536870911)Nt();else{d=Kt(l<<3)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u<<3)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l<<3)}function S4e(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function D4e(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~((A+-8-l|0)>>>3)<<3)),o=n[o>>2]|0,o|0&&It(o)}function b4e(){P4e()}function P4e(){x4e(10604)}function x4e(o){o=o|0,k4e(o,4955)}function k4e(o,l){o=o|0,l=l|0;var u=0;u=Q4e()|0,n[o>>2]=u,T4e(u,l),jh(n[o>>2]|0)}function Q4e(){var o=0;return s[7952]|0||(H4e(10612),gr(25,10612,U|0)|0,o=7952,n[o>>2]=1,n[o+4>>2]=0),10612}function T4e(o,l){o=o|0,l=l|0,n[o>>2]=O4e()|0,n[o+4>>2]=L4e()|0,n[o+12>>2]=l,n[o+8>>2]=M4e()|0,n[o+32>>2]=8}function jh(o){o=o|0;var l=0,u=0;l=I,I=I+16|0,u=l,Jy()|0,n[u>>2]=o,R4e(10608,u),I=l}function Jy(){return s[11714]|0||(n[2652]=0,gr(62,10608,U|0)|0,s[11714]=1),10608}function R4e(o,l){o=o|0,l=l|0;var u=0;u=Kt(8)|0,n[u+4>>2]=n[l>>2],n[u>>2]=n[o>>2],n[o>>2]=u}function F4e(o){o=o|0,N4e(o)}function N4e(o){o=o|0;var l=0,u=0;if(l=n[o>>2]|0,l|0)do u=l,l=n[l>>2]|0,It(u);while(l|0);n[o>>2]=0}function O4e(){return 11715}function L4e(){return 1496}function M4e(){return FP()|0}function U4e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0,(Hh(A,896)|0)==512?u|0&&(_4e(u),It(u)):l|0&&It(l)}function _4e(o){o=o|0,o=n[o+4>>2]|0,o|0&&Gh(o)}function H4e(o){o=o|0,Lh(o)}function j4e(o,l){o=o|0,l=l|0;var u=0,A=0;Jy()|0,u=n[2652]|0;e:do if(u|0){for(;A=n[u+4>>2]|0,!(A|0&&!(EZ(YM(A)|0,o)|0));)if(u=n[u>>2]|0,!u)break e;G4e(A,l)}while(!1)}function YM(o){return o=o|0,n[o+12>>2]|0}function G4e(o,l){o=o|0,l=l|0;var u=0;o=o+36|0,u=n[o>>2]|0,u|0&&(Sf(u),It(u)),u=Kt(4)|0,DP(u,l),n[o>>2]=u}function VM(){return s[11716]|0||(n[2664]=0,gr(63,10656,U|0)|0,s[11716]=1),10656}function UX(){var o=0;return s[11717]|0?o=n[2665]|0:(q4e(),n[2665]=1504,s[11717]=1,o=1504),o|0}function q4e(){s[11740]|0||(s[11718]=yr(yr(8,0)|0,0)|0,s[11719]=yr(yr(0,0)|0,0)|0,s[11720]=yr(yr(0,16)|0,0)|0,s[11721]=yr(yr(8,0)|0,0)|0,s[11722]=yr(yr(0,0)|0,0)|0,s[11723]=yr(yr(8,0)|0,0)|0,s[11724]=yr(yr(0,0)|0,0)|0,s[11725]=yr(yr(8,0)|0,0)|0,s[11726]=yr(yr(0,0)|0,0)|0,s[11727]=yr(yr(8,0)|0,0)|0,s[11728]=yr(yr(0,0)|0,0)|0,s[11729]=yr(yr(0,0)|0,32)|0,s[11730]=yr(yr(0,0)|0,32)|0,s[11740]=1)}function _X(){return 1572}function W4e(o,l,u,A,d){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0;var m=0,B=0,k=0,T=0,M=0,L=0;m=I,I=I+32|0,L=m+16|0,M=m+12|0,T=m+8|0,k=m+4|0,B=m,n[L>>2]=o,n[M>>2]=l,n[T>>2]=u,n[k>>2]=A,n[B>>2]=d,VM()|0,Y4e(10656,L,M,T,k,B),I=m}function Y4e(o,l,u,A,d,m){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0;var B=0;B=Kt(24)|0,gz(B+4|0,n[l>>2]|0,n[u>>2]|0,n[A>>2]|0,n[d>>2]|0,n[m>>2]|0),n[B>>2]=n[o>>2],n[o>>2]=B}function HX(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0,Ye=0,Le=0,Qe=0,tt=0,Ze=0,ct=0;if(ct=I,I=I+32|0,Le=ct+20|0,Qe=ct+8|0,tt=ct+4|0,Ze=ct,l=n[l>>2]|0,l|0){Ye=Le+4|0,T=Le+8|0,M=Qe+4|0,L=Qe+8|0,q=Qe+8|0,ae=Le+8|0;do{if(B=l+4|0,k=JM(B)|0,k|0){if(d=P2(k)|0,n[Le>>2]=0,n[Ye>>2]=0,n[T>>2]=0,A=(x2(k)|0)+1|0,V4e(Le,A),A|0)for(;A=A+-1|0,bu(Qe,n[d>>2]|0),m=n[Ye>>2]|0,m>>>0<(n[ae>>2]|0)>>>0?(n[m>>2]=n[Qe>>2],n[Ye>>2]=(n[Ye>>2]|0)+4):KM(Le,Qe),A;)d=d+4|0;A=k2(k)|0,n[Qe>>2]=0,n[M>>2]=0,n[L>>2]=0;e:do if(n[A>>2]|0)for(d=0,m=0;;){if((d|0)==(m|0)?J4e(Qe,A):(n[d>>2]=n[A>>2],n[M>>2]=(n[M>>2]|0)+4),A=A+4|0,!(n[A>>2]|0))break e;d=n[M>>2]|0,m=n[q>>2]|0}while(!1);n[tt>>2]=OP(B)|0,n[Ze>>2]=_r(k)|0,K4e(u,o,tt,Ze,Le,Qe),zM(Qe),np(Le)}l=n[l>>2]|0}while(l|0)}I=ct}function JM(o){return o=o|0,n[o+12>>2]|0}function P2(o){return o=o|0,n[o+12>>2]|0}function x2(o){return o=o|0,n[o+16>>2]|0}function V4e(o,l){o=o|0,l=l|0;var u=0,A=0,d=0;d=I,I=I+32|0,u=d,A=n[o>>2]|0,(n[o+8>>2]|0)-A>>2>>>0>>0&&(KX(u,l,(n[o+4>>2]|0)-A>>2,o+8|0),zX(o,u),XX(u)),I=d}function KM(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0,M=0;if(B=I,I=I+32|0,u=B,A=o+4|0,d=((n[A>>2]|0)-(n[o>>2]|0)>>2)+1|0,m=JX(o)|0,m>>>0>>0)an(o);else{k=n[o>>2]|0,M=(n[o+8>>2]|0)-k|0,T=M>>1,KX(u,M>>2>>>0>>1>>>0?T>>>0>>0?d:T:m,(n[A>>2]|0)-k>>2,o+8|0),m=u+8|0,n[n[m>>2]>>2]=n[l>>2],n[m>>2]=(n[m>>2]|0)+4,zX(o,u),XX(u),I=B;return}}function k2(o){return o=o|0,n[o+8>>2]|0}function J4e(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0,M=0;if(B=I,I=I+32|0,u=B,A=o+4|0,d=((n[A>>2]|0)-(n[o>>2]|0)>>2)+1|0,m=VX(o)|0,m>>>0>>0)an(o);else{k=n[o>>2]|0,M=(n[o+8>>2]|0)-k|0,T=M>>1,h3e(u,M>>2>>>0>>1>>>0?T>>>0>>0?d:T:m,(n[A>>2]|0)-k>>2,o+8|0),m=u+8|0,n[n[m>>2]>>2]=n[l>>2],n[m>>2]=(n[m>>2]|0)+4,g3e(o,u),d3e(u),I=B;return}}function OP(o){return o=o|0,n[o>>2]|0}function K4e(o,l,u,A,d,m){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0,z4e(o,l,u,A,d,m)}function zM(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-4-A|0)>>>2)<<2)),It(u))}function np(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-4-A|0)>>>2)<<2)),It(u))}function z4e(o,l,u,A,d,m){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0;var B=0,k=0,T=0,M=0,L=0,q=0;B=I,I=I+48|0,L=B+40|0,k=B+32|0,q=B+24|0,T=B+12|0,M=B,Fl(k),o=Os(o)|0,n[q>>2]=n[l>>2],u=n[u>>2]|0,A=n[A>>2]|0,XM(T,d),X4e(M,m),n[L>>2]=n[q>>2],Z4e(o,L,u,A,T,M),zM(M),np(T),Nl(k),I=B}function XM(o,l){o=o|0,l=l|0;var u=0,A=0;n[o>>2]=0,n[o+4>>2]=0,n[o+8>>2]=0,u=l+4|0,A=(n[u>>2]|0)-(n[l>>2]|0)>>2,A|0&&(A3e(o,A),p3e(o,n[l>>2]|0,n[u>>2]|0,A))}function X4e(o,l){o=o|0,l=l|0;var u=0,A=0;n[o>>2]=0,n[o+4>>2]=0,n[o+8>>2]=0,u=l+4|0,A=(n[u>>2]|0)-(n[l>>2]|0)>>2,A|0&&(u3e(o,A),f3e(o,n[l>>2]|0,n[u>>2]|0,A))}function Z4e(o,l,u,A,d,m){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0;var B=0,k=0,T=0,M=0,L=0,q=0;B=I,I=I+32|0,L=B+28|0,q=B+24|0,k=B+12|0,T=B,M=da($4e()|0)|0,n[q>>2]=n[l>>2],n[L>>2]=n[q>>2],l=fd(L)|0,u=jX(u)|0,A=ZM(A)|0,n[k>>2]=n[d>>2],L=d+4|0,n[k+4>>2]=n[L>>2],q=d+8|0,n[k+8>>2]=n[q>>2],n[q>>2]=0,n[L>>2]=0,n[d>>2]=0,d=$M(k)|0,n[T>>2]=n[m>>2],L=m+4|0,n[T+4>>2]=n[L>>2],q=m+8|0,n[T+8>>2]=n[q>>2],n[q>>2]=0,n[L>>2]=0,n[m>>2]=0,lu(0,M|0,o|0,l|0,u|0,A|0,d|0,e3e(T)|0)|0,zM(T),np(k),I=B}function $4e(){var o=0;return s[7968]|0||(l3e(10708),o=7968,n[o>>2]=1,n[o+4>>2]=0),10708}function fd(o){return o=o|0,qX(o)|0}function jX(o){return o=o|0,GX(o)|0}function ZM(o){return o=o|0,RP(o)|0}function $M(o){return o=o|0,r3e(o)|0}function e3e(o){return o=o|0,t3e(o)|0}function t3e(o){o=o|0;var l=0,u=0,A=0;if(A=(n[o+4>>2]|0)-(n[o>>2]|0)|0,u=A>>2,A=Rl(A+4|0)|0,n[A>>2]=u,u|0){l=0;do n[A+4+(l<<2)>>2]=GX(n[(n[o>>2]|0)+(l<<2)>>2]|0)|0,l=l+1|0;while((l|0)!=(u|0))}return A|0}function GX(o){return o=o|0,o|0}function r3e(o){o=o|0;var l=0,u=0,A=0;if(A=(n[o+4>>2]|0)-(n[o>>2]|0)|0,u=A>>2,A=Rl(A+4|0)|0,n[A>>2]=u,u|0){l=0;do n[A+4+(l<<2)>>2]=qX((n[o>>2]|0)+(l<<2)|0)|0,l=l+1|0;while((l|0)!=(u|0))}return A|0}function qX(o){o=o|0;var l=0,u=0,A=0,d=0;return d=I,I=I+32|0,l=d+12|0,u=d,A=fM(WX()|0)|0,A?(AM(l,A),pM(u,l),Mje(o,u),o=hM(l)|0):o=n3e(o)|0,I=d,o|0}function WX(){var o=0;return s[7960]|0||(a3e(10664),gr(25,10664,U|0)|0,o=7960,n[o>>2]=1,n[o+4>>2]=0),10664}function n3e(o){o=o|0;var l=0,u=0,A=0,d=0,m=0,B=0,k=0;return u=I,I=I+16|0,d=u+4|0,B=u,A=Rl(8)|0,l=A,k=Kt(4)|0,n[k>>2]=n[o>>2],m=l+4|0,n[m>>2]=k,o=Kt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],YX(o,m,d),n[A>>2]=o,I=u,l|0}function YX(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,u=Kt(16)|0,n[u+4>>2]=0,n[u+8>>2]=0,n[u>>2]=1656,n[u+12>>2]=l,n[o+4>>2]=u}function i3e(o){o=o|0,$y(o),It(o)}function s3e(o){o=o|0,o=n[o+12>>2]|0,o|0&&It(o)}function o3e(o){o=o|0,It(o)}function a3e(o){o=o|0,Lh(o)}function l3e(o){o=o|0,Qo(o,c3e()|0,5)}function c3e(){return 1676}function u3e(o,l){o=o|0,l=l|0;var u=0;if((VX(o)|0)>>>0>>0&&an(o),l>>>0>1073741823)Nt();else{u=Kt(l<<2)|0,n[o+4>>2]=u,n[o>>2]=u,n[o+8>>2]=u+(l<<2);return}}function f3e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0,A=o+4|0,o=u-l|0,(o|0)>0&&(Qr(n[A>>2]|0,l|0,o|0)|0,n[A>>2]=(n[A>>2]|0)+(o>>>2<<2))}function VX(o){return o=o|0,1073741823}function A3e(o,l){o=o|0,l=l|0;var u=0;if((JX(o)|0)>>>0>>0&&an(o),l>>>0>1073741823)Nt();else{u=Kt(l<<2)|0,n[o+4>>2]=u,n[o>>2]=u,n[o+8>>2]=u+(l<<2);return}}function p3e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0,A=o+4|0,o=u-l|0,(o|0)>0&&(Qr(n[A>>2]|0,l|0,o|0)|0,n[A>>2]=(n[A>>2]|0)+(o>>>2<<2))}function JX(o){return o=o|0,1073741823}function h3e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>1073741823)Nt();else{d=Kt(l<<2)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u<<2)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l<<2)}function g3e(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(0-(d>>2)<<2)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function d3e(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~((A+-4-l|0)>>>2)<<2)),o=n[o>>2]|0,o|0&&It(o)}function KX(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>1073741823)Nt();else{d=Kt(l<<2)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u<<2)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l<<2)}function zX(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(0-(d>>2)<<2)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function XX(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~((A+-4-l|0)>>>2)<<2)),o=n[o>>2]|0,o|0&&It(o)}function m3e(o,l,u,A,d){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0;var m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0,Ye=0,Le=0,Qe=0;if(Qe=I,I=I+32|0,L=Qe+20|0,q=Qe+12|0,M=Qe+16|0,ae=Qe+4|0,Ye=Qe,Le=Qe+8|0,k=UX()|0,m=n[k>>2]|0,B=n[m>>2]|0,B|0)for(T=n[k+8>>2]|0,k=n[k+4>>2]|0;bu(L,B),y3e(o,L,k,T),m=m+4|0,B=n[m>>2]|0,B;)T=T+1|0,k=k+1|0;if(m=_X()|0,B=n[m>>2]|0,B|0)do bu(L,B),n[q>>2]=n[m+4>>2],E3e(l,L,q),m=m+8|0,B=n[m>>2]|0;while(B|0);if(m=n[(Jy()|0)>>2]|0,m|0)do l=n[m+4>>2]|0,bu(L,n[(Ky(l)|0)>>2]|0),n[q>>2]=YM(l)|0,I3e(u,L,q),m=n[m>>2]|0;while(m|0);if(bu(M,0),m=VM()|0,n[L>>2]=n[M>>2],HX(L,m,d),m=n[(Jy()|0)>>2]|0,m|0){o=L+4|0,l=L+8|0,u=L+8|0;do{if(T=n[m+4>>2]|0,bu(q,n[(Ky(T)|0)>>2]|0),C3e(ae,ZX(T)|0),B=n[ae>>2]|0,B|0){n[L>>2]=0,n[o>>2]=0,n[l>>2]=0;do bu(Ye,n[(Ky(n[B+4>>2]|0)|0)>>2]|0),k=n[o>>2]|0,k>>>0<(n[u>>2]|0)>>>0?(n[k>>2]=n[Ye>>2],n[o>>2]=(n[o>>2]|0)+4):KM(L,Ye),B=n[B>>2]|0;while(B|0);w3e(A,q,L),np(L)}n[Le>>2]=n[q>>2],M=$X(T)|0,n[L>>2]=n[Le>>2],HX(L,M,d),Cz(ae),m=n[m>>2]|0}while(m|0)}I=Qe}function y3e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0,F3e(o,l,u,A)}function E3e(o,l,u){o=o|0,l=l|0,u=u|0,R3e(o,l,u)}function Ky(o){return o=o|0,o|0}function I3e(o,l,u){o=o|0,l=l|0,u=u|0,x3e(o,l,u)}function ZX(o){return o=o|0,o+16|0}function C3e(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0;if(m=I,I=I+16|0,d=m+8|0,u=m,n[o>>2]=0,A=n[l>>2]|0,n[d>>2]=A,n[u>>2]=o,u=P3e(u)|0,A|0){if(A=Kt(12)|0,B=(eZ(d)|0)+4|0,o=n[B+4>>2]|0,l=A+4|0,n[l>>2]=n[B>>2],n[l+4>>2]=o,l=n[n[d>>2]>>2]|0,n[d>>2]=l,!l)o=A;else for(l=A;o=Kt(12)|0,T=(eZ(d)|0)+4|0,k=n[T+4>>2]|0,B=o+4|0,n[B>>2]=n[T>>2],n[B+4>>2]=k,n[l>>2]=o,B=n[n[d>>2]>>2]|0,n[d>>2]=B,B;)l=o;n[o>>2]=n[u>>2],n[u>>2]=A}I=m}function w3e(o,l,u){o=o|0,l=l|0,u=u|0,B3e(o,l,u)}function $X(o){return o=o|0,o+24|0}function B3e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+32|0,B=A+24|0,d=A+16|0,k=A+12|0,m=A,Fl(d),o=Os(o)|0,n[k>>2]=n[l>>2],XM(m,u),n[B>>2]=n[k>>2],v3e(o,B,m),np(m),Nl(d),I=A}function v3e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+32|0,B=A+16|0,k=A+12|0,d=A,m=da(S3e()|0)|0,n[k>>2]=n[l>>2],n[B>>2]=n[k>>2],l=fd(B)|0,n[d>>2]=n[u>>2],B=u+4|0,n[d+4>>2]=n[B>>2],k=u+8|0,n[d+8>>2]=n[k>>2],n[k>>2]=0,n[B>>2]=0,n[u>>2]=0,Ts(0,m|0,o|0,l|0,$M(d)|0)|0,np(d),I=A}function S3e(){var o=0;return s[7976]|0||(D3e(10720),o=7976,n[o>>2]=1,n[o+4>>2]=0),10720}function D3e(o){o=o|0,Qo(o,b3e()|0,2)}function b3e(){return 1732}function P3e(o){return o=o|0,n[o>>2]|0}function eZ(o){return o=o|0,n[o>>2]|0}function x3e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;A=I,I=I+32|0,m=A+16|0,d=A+8|0,B=A,Fl(d),o=Os(o)|0,n[B>>2]=n[l>>2],u=n[u>>2]|0,n[m>>2]=n[B>>2],tZ(o,m,u),Nl(d),I=A}function tZ(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;A=I,I=I+16|0,m=A+4|0,B=A,d=da(k3e()|0)|0,n[B>>2]=n[l>>2],n[m>>2]=n[B>>2],l=fd(m)|0,Ts(0,d|0,o|0,l|0,jX(u)|0)|0,I=A}function k3e(){var o=0;return s[7984]|0||(Q3e(10732),o=7984,n[o>>2]=1,n[o+4>>2]=0),10732}function Q3e(o){o=o|0,Qo(o,T3e()|0,2)}function T3e(){return 1744}function R3e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;A=I,I=I+32|0,m=A+16|0,d=A+8|0,B=A,Fl(d),o=Os(o)|0,n[B>>2]=n[l>>2],u=n[u>>2]|0,n[m>>2]=n[B>>2],tZ(o,m,u),Nl(d),I=A}function F3e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0;d=I,I=I+32|0,B=d+16|0,m=d+8|0,k=d,Fl(m),o=Os(o)|0,n[k>>2]=n[l>>2],u=s[u>>0]|0,A=s[A>>0]|0,n[B>>2]=n[k>>2],N3e(o,B,u,A),Nl(m),I=d}function N3e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0;d=I,I=I+16|0,B=d+4|0,k=d,m=da(O3e()|0)|0,n[k>>2]=n[l>>2],n[B>>2]=n[k>>2],l=fd(B)|0,u=zy(u)|0,Li(0,m|0,o|0,l|0,u|0,zy(A)|0)|0,I=d}function O3e(){var o=0;return s[7992]|0||(M3e(10744),o=7992,n[o>>2]=1,n[o+4>>2]=0),10744}function zy(o){return o=o|0,L3e(o)|0}function L3e(o){return o=o|0,o&255|0}function M3e(o){o=o|0,Qo(o,U3e()|0,3)}function U3e(){return 1756}function _3e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0;switch(ae=I,I=I+32|0,k=ae+8|0,T=ae+4|0,M=ae+20|0,L=ae,yM(o,0),A=Lje(l)|0,n[k>>2]=0,q=k+4|0,n[q>>2]=0,n[k+8>>2]=0,A<<24>>24){case 0:{s[M>>0]=0,H3e(T,u,M),LP(o,T)|0,Df(T);break}case 8:{q=sU(l)|0,s[M>>0]=8,bu(L,n[q+4>>2]|0),j3e(T,u,M,L,q+8|0),LP(o,T)|0,Df(T);break}case 9:{if(m=sU(l)|0,l=n[m+4>>2]|0,l|0)for(B=k+8|0,d=m+12|0;l=l+-1|0,bu(T,n[d>>2]|0),A=n[q>>2]|0,A>>>0<(n[B>>2]|0)>>>0?(n[A>>2]=n[T>>2],n[q>>2]=(n[q>>2]|0)+4):KM(k,T),l;)d=d+4|0;s[M>>0]=9,bu(L,n[m+8>>2]|0),G3e(T,u,M,L,k),LP(o,T)|0,Df(T);break}default:q=sU(l)|0,s[M>>0]=A,bu(L,n[q+4>>2]|0),q3e(T,u,M,L),LP(o,T)|0,Df(T)}np(k),I=ae}function H3e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0;A=I,I=I+16|0,d=A,Fl(d),l=Os(l)|0,n8e(o,l,s[u>>0]|0),Nl(d),I=A}function LP(o,l){o=o|0,l=l|0;var u=0;return u=n[o>>2]|0,u|0&&Na(u|0),n[o>>2]=n[l>>2],n[l>>2]=0,o|0}function j3e(o,l,u,A,d){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0;var m=0,B=0,k=0,T=0;m=I,I=I+32|0,k=m+16|0,B=m+8|0,T=m,Fl(B),l=Os(l)|0,u=s[u>>0]|0,n[T>>2]=n[A>>2],d=n[d>>2]|0,n[k>>2]=n[T>>2],$3e(o,l,u,k,d),Nl(B),I=m}function G3e(o,l,u,A,d){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0;var m=0,B=0,k=0,T=0,M=0;m=I,I=I+32|0,T=m+24|0,B=m+16|0,M=m+12|0,k=m,Fl(B),l=Os(l)|0,u=s[u>>0]|0,n[M>>2]=n[A>>2],XM(k,d),n[T>>2]=n[M>>2],K3e(o,l,u,T,k),np(k),Nl(B),I=m}function q3e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0;d=I,I=I+32|0,B=d+16|0,m=d+8|0,k=d,Fl(m),l=Os(l)|0,u=s[u>>0]|0,n[k>>2]=n[A>>2],n[B>>2]=n[k>>2],W3e(o,l,u,B),Nl(m),I=d}function W3e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0;d=I,I=I+16|0,m=d+4|0,k=d,B=da(Y3e()|0)|0,u=zy(u)|0,n[k>>2]=n[A>>2],n[m>>2]=n[k>>2],MP(o,Ts(0,B|0,l|0,u|0,fd(m)|0)|0),I=d}function Y3e(){var o=0;return s[8e3]|0||(V3e(10756),o=8e3,n[o>>2]=1,n[o+4>>2]=0),10756}function MP(o,l){o=o|0,l=l|0,yM(o,l)}function V3e(o){o=o|0,Qo(o,J3e()|0,2)}function J3e(){return 1772}function K3e(o,l,u,A,d){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0;var m=0,B=0,k=0,T=0,M=0;m=I,I=I+32|0,T=m+16|0,M=m+12|0,B=m,k=da(z3e()|0)|0,u=zy(u)|0,n[M>>2]=n[A>>2],n[T>>2]=n[M>>2],A=fd(T)|0,n[B>>2]=n[d>>2],T=d+4|0,n[B+4>>2]=n[T>>2],M=d+8|0,n[B+8>>2]=n[M>>2],n[M>>2]=0,n[T>>2]=0,n[d>>2]=0,MP(o,Li(0,k|0,l|0,u|0,A|0,$M(B)|0)|0),np(B),I=m}function z3e(){var o=0;return s[8008]|0||(X3e(10768),o=8008,n[o>>2]=1,n[o+4>>2]=0),10768}function X3e(o){o=o|0,Qo(o,Z3e()|0,3)}function Z3e(){return 1784}function $3e(o,l,u,A,d){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0;var m=0,B=0,k=0,T=0;m=I,I=I+16|0,k=m+4|0,T=m,B=da(e8e()|0)|0,u=zy(u)|0,n[T>>2]=n[A>>2],n[k>>2]=n[T>>2],A=fd(k)|0,MP(o,Li(0,B|0,l|0,u|0,A|0,ZM(d)|0)|0),I=m}function e8e(){var o=0;return s[8016]|0||(t8e(10780),o=8016,n[o>>2]=1,n[o+4>>2]=0),10780}function t8e(o){o=o|0,Qo(o,r8e()|0,3)}function r8e(){return 1800}function n8e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=da(i8e()|0)|0,MP(o,dn(0,A|0,l|0,zy(u)|0)|0)}function i8e(){var o=0;return s[8024]|0||(s8e(10792),o=8024,n[o>>2]=1,n[o+4>>2]=0),10792}function s8e(o){o=o|0,Qo(o,o8e()|0,1)}function o8e(){return 1816}function a8e(){l8e(),c8e(),u8e()}function l8e(){n[2702]=xZ(65536)|0}function c8e(){k8e(10856)}function u8e(){f8e(10816)}function f8e(o){o=o|0,A8e(o,5044),p8e(o)|0}function A8e(o,l){o=o|0,l=l|0;var u=0;u=WX()|0,n[o>>2]=u,v8e(u,l),jh(n[o>>2]|0)}function p8e(o){o=o|0;var l=0;return l=n[o>>2]|0,cd(l,h8e()|0),o|0}function h8e(){var o=0;return s[8032]|0||(rZ(10820),gr(64,10820,U|0)|0,o=8032,n[o>>2]=1,n[o+4>>2]=0),_r(10820)|0||rZ(10820),10820}function rZ(o){o=o|0,m8e(o),ud(o,25)}function g8e(o){o=o|0,d8e(o+24|0)}function d8e(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function m8e(o){o=o|0;var l=0;l=tn()|0,rn(o,5,18,l,C8e()|0,1),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function y8e(o,l){o=o|0,l=l|0,E8e(o,l)}function E8e(o,l){o=o|0,l=l|0;var u=0,A=0,d=0;u=I,I=I+16|0,A=u,d=u+4|0,ad(d,l),n[A>>2]=ld(d,l)|0,I8e(o,A),I=u}function I8e(o,l){o=o|0,l=l|0,nZ(o+4|0,n[l>>2]|0),s[o+8>>0]=1}function nZ(o,l){o=o|0,l=l|0,n[o>>2]=l}function C8e(){return 1824}function w8e(o){return o=o|0,B8e(o)|0}function B8e(o){o=o|0;var l=0,u=0,A=0,d=0,m=0,B=0,k=0;return u=I,I=I+16|0,d=u+4|0,B=u,A=Rl(8)|0,l=A,k=Kt(4)|0,ad(d,o),nZ(k,ld(d,o)|0),m=l+4|0,n[m>>2]=k,o=Kt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],YX(o,m,d),n[A>>2]=o,I=u,l|0}function Rl(o){o=o|0;var l=0,u=0;return o=o+7&-8,o>>>0<=32768&&(l=n[2701]|0,o>>>0<=(65536-l|0)>>>0)?(u=(n[2702]|0)+l|0,n[2701]=l+o,o=u):(o=xZ(o+8|0)|0,n[o>>2]=n[2703],n[2703]=o,o=o+8|0),o|0}function v8e(o,l){o=o|0,l=l|0,n[o>>2]=S8e()|0,n[o+4>>2]=D8e()|0,n[o+12>>2]=l,n[o+8>>2]=b8e()|0,n[o+32>>2]=9}function S8e(){return 11744}function D8e(){return 1832}function b8e(){return NP()|0}function P8e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0,(Hh(A,896)|0)==512?u|0&&(x8e(u),It(u)):l|0&&It(l)}function x8e(o){o=o|0,o=n[o+4>>2]|0,o|0&&Gh(o)}function k8e(o){o=o|0,Q8e(o,5052),T8e(o)|0,R8e(o,5058,26)|0,F8e(o,5069,1)|0,N8e(o,5077,10)|0,O8e(o,5087,19)|0,L8e(o,5094,27)|0}function Q8e(o,l){o=o|0,l=l|0;var u=0;u=xje()|0,n[o>>2]=u,kje(u,l),jh(n[o>>2]|0)}function T8e(o){o=o|0;var l=0;return l=n[o>>2]|0,cd(l,gje()|0),o|0}function R8e(o,l,u){return o=o|0,l=l|0,u=u|0,XHe(o,Bn(l)|0,u,0),o|0}function F8e(o,l,u){return o=o|0,l=l|0,u=u|0,OHe(o,Bn(l)|0,u,0),o|0}function N8e(o,l,u){return o=o|0,l=l|0,u=u|0,hHe(o,Bn(l)|0,u,0),o|0}function O8e(o,l,u){return o=o|0,l=l|0,u=u|0,$8e(o,Bn(l)|0,u,0),o|0}function iZ(o,l){o=o|0,l=l|0;var u=0,A=0;e:for(;;){for(u=n[2703]|0;;){if((u|0)==(l|0))break e;if(A=n[u>>2]|0,n[2703]=A,!u)u=A;else break}It(u)}n[2701]=o}function L8e(o,l,u){return o=o|0,l=l|0,u=u|0,M8e(o,Bn(l)|0,u,0),o|0}function M8e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0;m=n[o>>2]|0,d=eU()|0,o=U8e(u)|0,vn(m,l,d,o,_8e(u,A)|0,A)}function eU(){var o=0,l=0;if(s[8040]|0||(oZ(10860),gr(65,10860,U|0)|0,l=8040,n[l>>2]=1,n[l+4>>2]=0),!(_r(10860)|0)){o=10860,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));oZ(10860)}return 10860}function U8e(o){return o=o|0,o|0}function _8e(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0;return k=I,I=I+16|0,d=k,m=k+4|0,n[d>>2]=o,T=eU()|0,B=T+24|0,l=yr(l,4)|0,n[m>>2]=l,u=T+28|0,A=n[u>>2]|0,A>>>0<(n[T+32>>2]|0)>>>0?(sZ(A,o,l),l=(n[u>>2]|0)+8|0,n[u>>2]=l):(H8e(B,d,m),l=n[u>>2]|0),I=k,(l-(n[B>>2]|0)>>3)+-1|0}function sZ(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,n[o+4>>2]=u}function H8e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0;if(k=I,I=I+32|0,d=k,m=o+4|0,B=((n[m>>2]|0)-(n[o>>2]|0)>>3)+1|0,A=j8e(o)|0,A>>>0>>0)an(o);else{T=n[o>>2]|0,L=(n[o+8>>2]|0)-T|0,M=L>>2,G8e(d,L>>3>>>0>>1>>>0?M>>>0>>0?B:M:A,(n[m>>2]|0)-T>>3,o+8|0),B=d+8|0,sZ(n[B>>2]|0,n[l>>2]|0,n[u>>2]|0),n[B>>2]=(n[B>>2]|0)+8,q8e(o,d),W8e(d),I=k;return}}function j8e(o){return o=o|0,536870911}function G8e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>536870911)Nt();else{d=Kt(l<<3)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u<<3)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l<<3)}function q8e(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function W8e(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~((A+-8-l|0)>>>3)<<3)),o=n[o>>2]|0,o|0&&It(o)}function oZ(o){o=o|0,J8e(o)}function Y8e(o){o=o|0,V8e(o+24|0)}function V8e(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function J8e(o){o=o|0;var l=0;l=tn()|0,rn(o,1,11,l,K8e()|0,2),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function K8e(){return 1840}function z8e(o,l,u){o=o|0,l=l|0,u=u|0,Z8e(n[(X8e(o)|0)>>2]|0,l,u)}function X8e(o){return o=o|0,(n[(eU()|0)+24>>2]|0)+(o<<3)|0}function Z8e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0;A=I,I=I+16|0,m=A+1|0,d=A,ad(m,l),l=ld(m,l)|0,ad(d,u),u=ld(d,u)|0,sp[o&31](l,u),I=A}function $8e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0;m=n[o>>2]|0,d=tU()|0,o=eHe(u)|0,vn(m,l,d,o,tHe(u,A)|0,A)}function tU(){var o=0,l=0;if(s[8048]|0||(lZ(10896),gr(66,10896,U|0)|0,l=8048,n[l>>2]=1,n[l+4>>2]=0),!(_r(10896)|0)){o=10896,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));lZ(10896)}return 10896}function eHe(o){return o=o|0,o|0}function tHe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0;return k=I,I=I+16|0,d=k,m=k+4|0,n[d>>2]=o,T=tU()|0,B=T+24|0,l=yr(l,4)|0,n[m>>2]=l,u=T+28|0,A=n[u>>2]|0,A>>>0<(n[T+32>>2]|0)>>>0?(aZ(A,o,l),l=(n[u>>2]|0)+8|0,n[u>>2]=l):(rHe(B,d,m),l=n[u>>2]|0),I=k,(l-(n[B>>2]|0)>>3)+-1|0}function aZ(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,n[o+4>>2]=u}function rHe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0;if(k=I,I=I+32|0,d=k,m=o+4|0,B=((n[m>>2]|0)-(n[o>>2]|0)>>3)+1|0,A=nHe(o)|0,A>>>0>>0)an(o);else{T=n[o>>2]|0,L=(n[o+8>>2]|0)-T|0,M=L>>2,iHe(d,L>>3>>>0>>1>>>0?M>>>0>>0?B:M:A,(n[m>>2]|0)-T>>3,o+8|0),B=d+8|0,aZ(n[B>>2]|0,n[l>>2]|0,n[u>>2]|0),n[B>>2]=(n[B>>2]|0)+8,sHe(o,d),oHe(d),I=k;return}}function nHe(o){return o=o|0,536870911}function iHe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>536870911)Nt();else{d=Kt(l<<3)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u<<3)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l<<3)}function sHe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function oHe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~((A+-8-l|0)>>>3)<<3)),o=n[o>>2]|0,o|0&&It(o)}function lZ(o){o=o|0,cHe(o)}function aHe(o){o=o|0,lHe(o+24|0)}function lHe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function cHe(o){o=o|0;var l=0;l=tn()|0,rn(o,1,11,l,uHe()|0,1),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function uHe(){return 1852}function fHe(o,l){return o=o|0,l=l|0,pHe(n[(AHe(o)|0)>>2]|0,l)|0}function AHe(o){return o=o|0,(n[(tU()|0)+24>>2]|0)+(o<<3)|0}function pHe(o,l){o=o|0,l=l|0;var u=0,A=0;return u=I,I=I+16|0,A=u,ad(A,l),l=ld(A,l)|0,l=RP(gd[o&31](l)|0)|0,I=u,l|0}function hHe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0;m=n[o>>2]|0,d=rU()|0,o=gHe(u)|0,vn(m,l,d,o,dHe(u,A)|0,A)}function rU(){var o=0,l=0;if(s[8056]|0||(uZ(10932),gr(67,10932,U|0)|0,l=8056,n[l>>2]=1,n[l+4>>2]=0),!(_r(10932)|0)){o=10932,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));uZ(10932)}return 10932}function gHe(o){return o=o|0,o|0}function dHe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0;return k=I,I=I+16|0,d=k,m=k+4|0,n[d>>2]=o,T=rU()|0,B=T+24|0,l=yr(l,4)|0,n[m>>2]=l,u=T+28|0,A=n[u>>2]|0,A>>>0<(n[T+32>>2]|0)>>>0?(cZ(A,o,l),l=(n[u>>2]|0)+8|0,n[u>>2]=l):(mHe(B,d,m),l=n[u>>2]|0),I=k,(l-(n[B>>2]|0)>>3)+-1|0}function cZ(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,n[o+4>>2]=u}function mHe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0;if(k=I,I=I+32|0,d=k,m=o+4|0,B=((n[m>>2]|0)-(n[o>>2]|0)>>3)+1|0,A=yHe(o)|0,A>>>0>>0)an(o);else{T=n[o>>2]|0,L=(n[o+8>>2]|0)-T|0,M=L>>2,EHe(d,L>>3>>>0>>1>>>0?M>>>0>>0?B:M:A,(n[m>>2]|0)-T>>3,o+8|0),B=d+8|0,cZ(n[B>>2]|0,n[l>>2]|0,n[u>>2]|0),n[B>>2]=(n[B>>2]|0)+8,IHe(o,d),CHe(d),I=k;return}}function yHe(o){return o=o|0,536870911}function EHe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>536870911)Nt();else{d=Kt(l<<3)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u<<3)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l<<3)}function IHe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function CHe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~((A+-8-l|0)>>>3)<<3)),o=n[o>>2]|0,o|0&&It(o)}function uZ(o){o=o|0,vHe(o)}function wHe(o){o=o|0,BHe(o+24|0)}function BHe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function vHe(o){o=o|0;var l=0;l=tn()|0,rn(o,1,7,l,SHe()|0,2),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function SHe(){return 1860}function DHe(o,l,u){return o=o|0,l=l|0,u=u|0,PHe(n[(bHe(o)|0)>>2]|0,l,u)|0}function bHe(o){return o=o|0,(n[(rU()|0)+24>>2]|0)+(o<<3)|0}function PHe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0;return A=I,I=I+32|0,B=A+12|0,m=A+8|0,k=A,T=A+16|0,d=A+4|0,xHe(T,l),kHe(k,T,l),Mh(d,u),u=Uh(d,u)|0,n[B>>2]=n[k>>2],F2[o&15](m,B,u),u=QHe(m)|0,Df(m),_h(d),I=A,u|0}function xHe(o,l){o=o|0,l=l|0}function kHe(o,l,u){o=o|0,l=l|0,u=u|0,THe(o,u)}function QHe(o){return o=o|0,Os(o)|0}function THe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0;d=I,I=I+16|0,u=d,A=l,A&1?(RHe(u,0),Me(A|0,u|0)|0,FHe(o,u),NHe(u)):n[o>>2]=n[l>>2],I=d}function RHe(o,l){o=o|0,l=l|0,Su(o,l),n[o+4>>2]=0,s[o+8>>0]=0}function FHe(o,l){o=o|0,l=l|0,n[o>>2]=n[l+4>>2]}function NHe(o){o=o|0,s[o+8>>0]=0}function OHe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0;m=n[o>>2]|0,d=nU()|0,o=LHe(u)|0,vn(m,l,d,o,MHe(u,A)|0,A)}function nU(){var o=0,l=0;if(s[8064]|0||(AZ(10968),gr(68,10968,U|0)|0,l=8064,n[l>>2]=1,n[l+4>>2]=0),!(_r(10968)|0)){o=10968,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));AZ(10968)}return 10968}function LHe(o){return o=o|0,o|0}function MHe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0;return k=I,I=I+16|0,d=k,m=k+4|0,n[d>>2]=o,T=nU()|0,B=T+24|0,l=yr(l,4)|0,n[m>>2]=l,u=T+28|0,A=n[u>>2]|0,A>>>0<(n[T+32>>2]|0)>>>0?(fZ(A,o,l),l=(n[u>>2]|0)+8|0,n[u>>2]=l):(UHe(B,d,m),l=n[u>>2]|0),I=k,(l-(n[B>>2]|0)>>3)+-1|0}function fZ(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,n[o+4>>2]=u}function UHe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0;if(k=I,I=I+32|0,d=k,m=o+4|0,B=((n[m>>2]|0)-(n[o>>2]|0)>>3)+1|0,A=_He(o)|0,A>>>0>>0)an(o);else{T=n[o>>2]|0,L=(n[o+8>>2]|0)-T|0,M=L>>2,HHe(d,L>>3>>>0>>1>>>0?M>>>0>>0?B:M:A,(n[m>>2]|0)-T>>3,o+8|0),B=d+8|0,fZ(n[B>>2]|0,n[l>>2]|0,n[u>>2]|0),n[B>>2]=(n[B>>2]|0)+8,jHe(o,d),GHe(d),I=k;return}}function _He(o){return o=o|0,536870911}function HHe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>536870911)Nt();else{d=Kt(l<<3)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u<<3)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l<<3)}function jHe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function GHe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~((A+-8-l|0)>>>3)<<3)),o=n[o>>2]|0,o|0&&It(o)}function AZ(o){o=o|0,YHe(o)}function qHe(o){o=o|0,WHe(o+24|0)}function WHe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function YHe(o){o=o|0;var l=0;l=tn()|0,rn(o,1,1,l,VHe()|0,5),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function VHe(){return 1872}function JHe(o,l,u,A,d,m){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0,zHe(n[(KHe(o)|0)>>2]|0,l,u,A,d,m)}function KHe(o){return o=o|0,(n[(nU()|0)+24>>2]|0)+(o<<3)|0}function zHe(o,l,u,A,d,m){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0;var B=0,k=0,T=0,M=0,L=0,q=0;B=I,I=I+32|0,k=B+16|0,T=B+12|0,M=B+8|0,L=B+4|0,q=B,Mh(k,l),l=Uh(k,l)|0,Mh(T,u),u=Uh(T,u)|0,Mh(M,A),A=Uh(M,A)|0,Mh(L,d),d=Uh(L,d)|0,Mh(q,m),m=Uh(q,m)|0,FZ[o&1](l,u,A,d,m),_h(q),_h(L),_h(M),_h(T),_h(k),I=B}function XHe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0;m=n[o>>2]|0,d=iU()|0,o=ZHe(u)|0,vn(m,l,d,o,$He(u,A)|0,A)}function iU(){var o=0,l=0;if(s[8072]|0||(hZ(11004),gr(69,11004,U|0)|0,l=8072,n[l>>2]=1,n[l+4>>2]=0),!(_r(11004)|0)){o=11004,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));hZ(11004)}return 11004}function ZHe(o){return o=o|0,o|0}function $He(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,T=0;return k=I,I=I+16|0,d=k,m=k+4|0,n[d>>2]=o,T=iU()|0,B=T+24|0,l=yr(l,4)|0,n[m>>2]=l,u=T+28|0,A=n[u>>2]|0,A>>>0<(n[T+32>>2]|0)>>>0?(pZ(A,o,l),l=(n[u>>2]|0)+8|0,n[u>>2]=l):(eje(B,d,m),l=n[u>>2]|0),I=k,(l-(n[B>>2]|0)>>3)+-1|0}function pZ(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,n[o+4>>2]=u}function eje(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0;if(k=I,I=I+32|0,d=k,m=o+4|0,B=((n[m>>2]|0)-(n[o>>2]|0)>>3)+1|0,A=tje(o)|0,A>>>0>>0)an(o);else{T=n[o>>2]|0,L=(n[o+8>>2]|0)-T|0,M=L>>2,rje(d,L>>3>>>0>>1>>>0?M>>>0>>0?B:M:A,(n[m>>2]|0)-T>>3,o+8|0),B=d+8|0,pZ(n[B>>2]|0,n[l>>2]|0,n[u>>2]|0),n[B>>2]=(n[B>>2]|0)+8,nje(o,d),ije(d),I=k;return}}function tje(o){return o=o|0,536870911}function rje(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>536870911)Nt();else{d=Kt(l<<3)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u<<3)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l<<3)}function nje(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function ije(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~((A+-8-l|0)>>>3)<<3)),o=n[o>>2]|0,o|0&&It(o)}function hZ(o){o=o|0,aje(o)}function sje(o){o=o|0,oje(o+24|0)}function oje(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function aje(o){o=o|0;var l=0;l=tn()|0,rn(o,1,12,l,lje()|0,2),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function lje(){return 1896}function cje(o,l,u){o=o|0,l=l|0,u=u|0,fje(n[(uje(o)|0)>>2]|0,l,u)}function uje(o){return o=o|0,(n[(iU()|0)+24>>2]|0)+(o<<3)|0}function fje(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0;A=I,I=I+16|0,m=A+4|0,d=A,Aje(m,l),l=pje(m,l)|0,Mh(d,u),u=Uh(d,u)|0,sp[o&31](l,u),_h(d),I=A}function Aje(o,l){o=o|0,l=l|0}function pje(o,l){return o=o|0,l=l|0,hje(l)|0}function hje(o){return o=o|0,o|0}function gje(){var o=0;return s[8080]|0||(gZ(11040),gr(70,11040,U|0)|0,o=8080,n[o>>2]=1,n[o+4>>2]=0),_r(11040)|0||gZ(11040),11040}function gZ(o){o=o|0,yje(o),ud(o,71)}function dje(o){o=o|0,mje(o+24|0)}function mje(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function yje(o){o=o|0;var l=0;l=tn()|0,rn(o,5,7,l,wje()|0,0),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function Eje(o){o=o|0,Ije(o)}function Ije(o){o=o|0,Cje(o)}function Cje(o){o=o|0,s[o+8>>0]=1}function wje(){return 1936}function Bje(){return vje()|0}function vje(){var o=0,l=0,u=0,A=0,d=0,m=0,B=0;return l=I,I=I+16|0,d=l+4|0,B=l,u=Rl(8)|0,o=u,m=o+4|0,n[m>>2]=Kt(1)|0,A=Kt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],Sje(A,m,d),n[u>>2]=A,I=l,o|0}function Sje(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,u=Kt(16)|0,n[u+4>>2]=0,n[u+8>>2]=0,n[u>>2]=1916,n[u+12>>2]=l,n[o+4>>2]=u}function Dje(o){o=o|0,$y(o),It(o)}function bje(o){o=o|0,o=n[o+12>>2]|0,o|0&&It(o)}function Pje(o){o=o|0,It(o)}function xje(){var o=0;return s[8088]|0||(Oje(11076),gr(25,11076,U|0)|0,o=8088,n[o>>2]=1,n[o+4>>2]=0),11076}function kje(o,l){o=o|0,l=l|0,n[o>>2]=Qje()|0,n[o+4>>2]=Tje()|0,n[o+12>>2]=l,n[o+8>>2]=Rje()|0,n[o+32>>2]=10}function Qje(){return 11745}function Tje(){return 1940}function Rje(){return FP()|0}function Fje(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0,(Hh(A,896)|0)==512?u|0&&(Nje(u),It(u)):l|0&&It(l)}function Nje(o){o=o|0,o=n[o+4>>2]|0,o|0&&Gh(o)}function Oje(o){o=o|0,Lh(o)}function bu(o,l){o=o|0,l=l|0,n[o>>2]=l}function sU(o){return o=o|0,n[o>>2]|0}function Lje(o){return o=o|0,s[n[o>>2]>>0]|0}function Mje(o,l){o=o|0,l=l|0;var u=0,A=0;u=I,I=I+16|0,A=u,n[A>>2]=n[o>>2],Uje(l,A)|0,I=u}function Uje(o,l){o=o|0,l=l|0;var u=0;return u=_je(n[o>>2]|0,l)|0,l=o+4|0,n[(n[l>>2]|0)+8>>2]=u,n[(n[l>>2]|0)+8>>2]|0}function _je(o,l){o=o|0,l=l|0;var u=0,A=0;return u=I,I=I+16|0,A=u,Fl(A),o=Os(o)|0,l=Hje(o,n[l>>2]|0)|0,Nl(A),I=u,l|0}function Fl(o){o=o|0,n[o>>2]=n[2701],n[o+4>>2]=n[2703]}function Hje(o,l){o=o|0,l=l|0;var u=0;return u=da(jje()|0)|0,dn(0,u|0,o|0,ZM(l)|0)|0}function Nl(o){o=o|0,iZ(n[o>>2]|0,n[o+4>>2]|0)}function jje(){var o=0;return s[8096]|0||(Gje(11120),o=8096,n[o>>2]=1,n[o+4>>2]=0),11120}function Gje(o){o=o|0,Qo(o,qje()|0,1)}function qje(){return 1948}function Wje(){Yje()}function Yje(){var o=0,l=0,u=0,A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0,Ye=0,Le=0,Qe=0;if(Le=I,I=I+16|0,L=Le+4|0,q=Le,oa(65536,10804,n[2702]|0,10812),u=UX()|0,l=n[u>>2]|0,o=n[l>>2]|0,o|0)for(A=n[u+8>>2]|0,u=n[u+4>>2]|0;pf(o|0,c[u>>0]|0|0,s[A>>0]|0),l=l+4|0,o=n[l>>2]|0,o;)A=A+1|0,u=u+1|0;if(o=_X()|0,l=n[o>>2]|0,l|0)do NA(l|0,n[o+4>>2]|0),o=o+8|0,l=n[o>>2]|0;while(l|0);NA(Vje()|0,5167),M=Jy()|0,o=n[M>>2]|0;e:do if(o|0){do Jje(n[o+4>>2]|0),o=n[o>>2]|0;while(o|0);if(o=n[M>>2]|0,o|0){T=M;do{for(;d=o,o=n[o>>2]|0,d=n[d+4>>2]|0,!!(Kje(d)|0);)if(n[q>>2]=T,n[L>>2]=n[q>>2],zje(M,L)|0,!o)break e;if(Xje(d),T=n[T>>2]|0,l=dZ(d)|0,m=Oi()|0,B=I,I=I+((1*(l<<2)|0)+15&-16)|0,k=I,I=I+((1*(l<<2)|0)+15&-16)|0,l=n[(ZX(d)|0)>>2]|0,l|0)for(u=B,A=k;n[u>>2]=n[(Ky(n[l+4>>2]|0)|0)>>2],n[A>>2]=n[l+8>>2],l=n[l>>2]|0,l;)u=u+4|0,A=A+4|0;Qe=Ky(d)|0,l=Zje(d)|0,u=dZ(d)|0,A=$je(d)|0,oc(Qe|0,l|0,B|0,k|0,u|0,A|0,YM(d)|0),FA(m|0)}while(o|0)}}while(!1);if(o=n[(VM()|0)>>2]|0,o|0)do Qe=o+4|0,M=JM(Qe)|0,d=k2(M)|0,m=P2(M)|0,B=(x2(M)|0)+1|0,k=UP(M)|0,T=mZ(Qe)|0,M=_r(M)|0,L=OP(Qe)|0,q=oU(Qe)|0,uu(0,d|0,m|0,B|0,k|0,T|0,M|0,L|0,q|0,aU(Qe)|0),o=n[o>>2]|0;while(o|0);o=n[(Jy()|0)>>2]|0;e:do if(o|0){t:for(;;){if(l=n[o+4>>2]|0,l|0&&(ae=n[(Ky(l)|0)>>2]|0,Ye=n[($X(l)|0)>>2]|0,Ye|0)){u=Ye;do{l=u+4|0,A=JM(l)|0;r:do if(A|0)switch(_r(A)|0){case 0:break t;case 4:case 3:case 2:{k=k2(A)|0,T=P2(A)|0,M=(x2(A)|0)+1|0,L=UP(A)|0,q=_r(A)|0,Qe=OP(l)|0,uu(ae|0,k|0,T|0,M|0,L|0,0,q|0,Qe|0,oU(l)|0,aU(l)|0);break r}case 1:{B=k2(A)|0,k=P2(A)|0,T=(x2(A)|0)+1|0,M=UP(A)|0,L=mZ(l)|0,q=_r(A)|0,Qe=OP(l)|0,uu(ae|0,B|0,k|0,T|0,M|0,L|0,q|0,Qe|0,oU(l)|0,aU(l)|0);break r}case 5:{M=k2(A)|0,L=P2(A)|0,q=(x2(A)|0)+1|0,Qe=UP(A)|0,uu(ae|0,M|0,L|0,q|0,Qe|0,e6e(A)|0,_r(A)|0,0,0,0);break r}default:break r}while(!1);u=n[u>>2]|0}while(u|0)}if(o=n[o>>2]|0,!o)break e}Nt()}while(!1);ve(),I=Le}function Vje(){return 11703}function Jje(o){o=o|0,s[o+40>>0]=0}function Kje(o){return o=o|0,(s[o+40>>0]|0)!=0|0}function zje(o,l){return o=o|0,l=l|0,l=t6e(l)|0,o=n[l>>2]|0,n[l>>2]=n[o>>2],It(o),n[l>>2]|0}function Xje(o){o=o|0,s[o+40>>0]=1}function dZ(o){return o=o|0,n[o+20>>2]|0}function Zje(o){return o=o|0,n[o+8>>2]|0}function $je(o){return o=o|0,n[o+32>>2]|0}function UP(o){return o=o|0,n[o+4>>2]|0}function mZ(o){return o=o|0,n[o+4>>2]|0}function oU(o){return o=o|0,n[o+8>>2]|0}function aU(o){return o=o|0,n[o+16>>2]|0}function e6e(o){return o=o|0,n[o+20>>2]|0}function t6e(o){return o=o|0,n[o>>2]|0}function _P(o){o=o|0;var l=0,u=0,A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0,Ye=0,Le=0,Qe=0,tt=0,Ze=0,ct=0,He=0,We=0,Lt=0;Lt=I,I=I+16|0,ae=Lt;do if(o>>>0<245){if(M=o>>>0<11?16:o+11&-8,o=M>>>3,q=n[2783]|0,u=q>>>o,u&3|0)return l=(u&1^1)+o|0,o=11172+(l<<1<<2)|0,u=o+8|0,A=n[u>>2]|0,d=A+8|0,m=n[d>>2]|0,(o|0)==(m|0)?n[2783]=q&~(1<>2]=o,n[u>>2]=m),We=l<<3,n[A+4>>2]=We|3,We=A+We+4|0,n[We>>2]=n[We>>2]|1,We=d,I=Lt,We|0;if(L=n[2785]|0,M>>>0>L>>>0){if(u|0)return l=2<>>12&16,l=l>>>B,u=l>>>5&8,l=l>>>u,d=l>>>2&4,l=l>>>d,o=l>>>1&2,l=l>>>o,A=l>>>1&1,A=(u|B|d|o|A)+(l>>>A)|0,l=11172+(A<<1<<2)|0,o=l+8|0,d=n[o>>2]|0,B=d+8|0,u=n[B>>2]|0,(l|0)==(u|0)?(o=q&~(1<>2]=l,n[o>>2]=u,o=q),m=(A<<3)-M|0,n[d+4>>2]=M|3,A=d+M|0,n[A+4>>2]=m|1,n[A+m>>2]=m,L|0&&(d=n[2788]|0,l=L>>>3,u=11172+(l<<1<<2)|0,l=1<>2]|0):(n[2783]=o|l,l=u,o=u+8|0),n[o>>2]=d,n[l+12>>2]=d,n[d+8>>2]=l,n[d+12>>2]=u),n[2785]=m,n[2788]=A,We=B,I=Lt,We|0;if(k=n[2784]|0,k){if(u=(k&0-k)+-1|0,B=u>>>12&16,u=u>>>B,m=u>>>5&8,u=u>>>m,T=u>>>2&4,u=u>>>T,A=u>>>1&2,u=u>>>A,o=u>>>1&1,o=n[11436+((m|B|T|A|o)+(u>>>o)<<2)>>2]|0,u=(n[o+4>>2]&-8)-M|0,A=n[o+16+(((n[o+16>>2]|0)==0&1)<<2)>>2]|0,!A)T=o,m=u;else{do B=(n[A+4>>2]&-8)-M|0,T=B>>>0>>0,u=T?B:u,o=T?A:o,A=n[A+16+(((n[A+16>>2]|0)==0&1)<<2)>>2]|0;while(A|0);T=o,m=u}if(B=T+M|0,T>>>0>>0){d=n[T+24>>2]|0,l=n[T+12>>2]|0;do if((l|0)==(T|0)){if(o=T+20|0,l=n[o>>2]|0,!l&&(o=T+16|0,l=n[o>>2]|0,!l)){u=0;break}for(;;){if(u=l+20|0,A=n[u>>2]|0,A|0){l=A,o=u;continue}if(u=l+16|0,A=n[u>>2]|0,A)l=A,o=u;else break}n[o>>2]=0,u=l}else u=n[T+8>>2]|0,n[u+12>>2]=l,n[l+8>>2]=u,u=l;while(!1);do if(d|0){if(l=n[T+28>>2]|0,o=11436+(l<<2)|0,(T|0)==(n[o>>2]|0)){if(n[o>>2]=u,!u){n[2784]=k&~(1<>2]|0)!=(T|0)&1)<<2)>>2]=u,!u)break;n[u+24>>2]=d,l=n[T+16>>2]|0,l|0&&(n[u+16>>2]=l,n[l+24>>2]=u),l=n[T+20>>2]|0,l|0&&(n[u+20>>2]=l,n[l+24>>2]=u)}while(!1);return m>>>0<16?(We=m+M|0,n[T+4>>2]=We|3,We=T+We+4|0,n[We>>2]=n[We>>2]|1):(n[T+4>>2]=M|3,n[B+4>>2]=m|1,n[B+m>>2]=m,L|0&&(A=n[2788]|0,l=L>>>3,u=11172+(l<<1<<2)|0,l=1<>2]|0):(n[2783]=q|l,l=u,o=u+8|0),n[o>>2]=A,n[l+12>>2]=A,n[A+8>>2]=l,n[A+12>>2]=u),n[2785]=m,n[2788]=B),We=T+8|0,I=Lt,We|0}else q=M}else q=M}else q=M}else if(o>>>0<=4294967231)if(o=o+11|0,M=o&-8,T=n[2784]|0,T){A=0-M|0,o=o>>>8,o?M>>>0>16777215?k=31:(q=(o+1048320|0)>>>16&8,He=o<>>16&4,He=He<>>16&2,k=14-(L|q|k)+(He<>>15)|0,k=M>>>(k+7|0)&1|k<<1):k=0,u=n[11436+(k<<2)>>2]|0;e:do if(!u)u=0,o=0,He=57;else for(o=0,B=M<<((k|0)==31?0:25-(k>>>1)|0),m=0;;){if(d=(n[u+4>>2]&-8)-M|0,d>>>0>>0)if(d)o=u,A=d;else{o=u,A=0,d=u,He=61;break e}if(d=n[u+20>>2]|0,u=n[u+16+(B>>>31<<2)>>2]|0,m=(d|0)==0|(d|0)==(u|0)?m:d,d=(u|0)==0,d){u=m,He=57;break}else B=B<<((d^1)&1)}while(!1);if((He|0)==57){if((u|0)==0&(o|0)==0){if(o=2<>>12&16,q=q>>>B,m=q>>>5&8,q=q>>>m,k=q>>>2&4,q=q>>>k,L=q>>>1&2,q=q>>>L,u=q>>>1&1,o=0,u=n[11436+((m|B|k|L|u)+(q>>>u)<<2)>>2]|0}u?(d=u,He=61):(k=o,B=A)}if((He|0)==61)for(;;)if(He=0,u=(n[d+4>>2]&-8)-M|0,q=u>>>0>>0,u=q?u:A,o=q?d:o,d=n[d+16+(((n[d+16>>2]|0)==0&1)<<2)>>2]|0,d)A=u,He=61;else{k=o,B=u;break}if(k|0&&B>>>0<((n[2785]|0)-M|0)>>>0){if(m=k+M|0,k>>>0>=m>>>0)return We=0,I=Lt,We|0;d=n[k+24>>2]|0,l=n[k+12>>2]|0;do if((l|0)==(k|0)){if(o=k+20|0,l=n[o>>2]|0,!l&&(o=k+16|0,l=n[o>>2]|0,!l)){l=0;break}for(;;){if(u=l+20|0,A=n[u>>2]|0,A|0){l=A,o=u;continue}if(u=l+16|0,A=n[u>>2]|0,A)l=A,o=u;else break}n[o>>2]=0}else We=n[k+8>>2]|0,n[We+12>>2]=l,n[l+8>>2]=We;while(!1);do if(d){if(o=n[k+28>>2]|0,u=11436+(o<<2)|0,(k|0)==(n[u>>2]|0)){if(n[u>>2]=l,!l){A=T&~(1<>2]|0)!=(k|0)&1)<<2)>>2]=l,!l){A=T;break}n[l+24>>2]=d,o=n[k+16>>2]|0,o|0&&(n[l+16>>2]=o,n[o+24>>2]=l),o=n[k+20>>2]|0,o&&(n[l+20>>2]=o,n[o+24>>2]=l),A=T}else A=T;while(!1);do if(B>>>0>=16){if(n[k+4>>2]=M|3,n[m+4>>2]=B|1,n[m+B>>2]=B,l=B>>>3,B>>>0<256){u=11172+(l<<1<<2)|0,o=n[2783]|0,l=1<>2]|0):(n[2783]=o|l,l=u,o=u+8|0),n[o>>2]=m,n[l+12>>2]=m,n[m+8>>2]=l,n[m+12>>2]=u;break}if(l=B>>>8,l?B>>>0>16777215?l=31:(He=(l+1048320|0)>>>16&8,We=l<>>16&4,We=We<>>16&2,l=14-(ct|He|l)+(We<>>15)|0,l=B>>>(l+7|0)&1|l<<1):l=0,u=11436+(l<<2)|0,n[m+28>>2]=l,o=m+16|0,n[o+4>>2]=0,n[o>>2]=0,o=1<>2]=m,n[m+24>>2]=u,n[m+12>>2]=m,n[m+8>>2]=m;break}for(o=B<<((l|0)==31?0:25-(l>>>1)|0),u=n[u>>2]|0;;){if((n[u+4>>2]&-8|0)==(B|0)){He=97;break}if(A=u+16+(o>>>31<<2)|0,l=n[A>>2]|0,l)o=o<<1,u=l;else{He=96;break}}if((He|0)==96){n[A>>2]=m,n[m+24>>2]=u,n[m+12>>2]=m,n[m+8>>2]=m;break}else if((He|0)==97){He=u+8|0,We=n[He>>2]|0,n[We+12>>2]=m,n[He>>2]=m,n[m+8>>2]=We,n[m+12>>2]=u,n[m+24>>2]=0;break}}else We=B+M|0,n[k+4>>2]=We|3,We=k+We+4|0,n[We>>2]=n[We>>2]|1;while(!1);return We=k+8|0,I=Lt,We|0}else q=M}else q=M;else q=-1;while(!1);if(u=n[2785]|0,u>>>0>=q>>>0)return l=u-q|0,o=n[2788]|0,l>>>0>15?(We=o+q|0,n[2788]=We,n[2785]=l,n[We+4>>2]=l|1,n[We+l>>2]=l,n[o+4>>2]=q|3):(n[2785]=0,n[2788]=0,n[o+4>>2]=u|3,We=o+u+4|0,n[We>>2]=n[We>>2]|1),We=o+8|0,I=Lt,We|0;if(B=n[2786]|0,B>>>0>q>>>0)return ct=B-q|0,n[2786]=ct,We=n[2789]|0,He=We+q|0,n[2789]=He,n[He+4>>2]=ct|1,n[We+4>>2]=q|3,We=We+8|0,I=Lt,We|0;if(n[2901]|0?o=n[2903]|0:(n[2903]=4096,n[2902]=4096,n[2904]=-1,n[2905]=-1,n[2906]=0,n[2894]=0,o=ae&-16^1431655768,n[ae>>2]=o,n[2901]=o,o=4096),k=q+48|0,T=q+47|0,m=o+T|0,d=0-o|0,M=m&d,M>>>0<=q>>>0||(o=n[2893]|0,o|0&&(L=n[2891]|0,ae=L+M|0,ae>>>0<=L>>>0|ae>>>0>o>>>0)))return We=0,I=Lt,We|0;e:do if(n[2894]&4)l=0,He=133;else{u=n[2789]|0;t:do if(u){for(A=11580;o=n[A>>2]|0,!(o>>>0<=u>>>0&&(Qe=A+4|0,(o+(n[Qe>>2]|0)|0)>>>0>u>>>0));)if(o=n[A+8>>2]|0,o)A=o;else{He=118;break t}if(l=m-B&d,l>>>0<2147483647)if(o=qh(l|0)|0,(o|0)==((n[A>>2]|0)+(n[Qe>>2]|0)|0)){if((o|0)!=-1){B=l,m=o,He=135;break e}}else A=o,He=126;else l=0}else He=118;while(!1);do if((He|0)==118)if(u=qh(0)|0,(u|0)!=-1&&(l=u,Ye=n[2902]|0,Le=Ye+-1|0,l=(Le&l|0?(Le+l&0-Ye)-l|0:0)+M|0,Ye=n[2891]|0,Le=l+Ye|0,l>>>0>q>>>0&l>>>0<2147483647)){if(Qe=n[2893]|0,Qe|0&&Le>>>0<=Ye>>>0|Le>>>0>Qe>>>0){l=0;break}if(o=qh(l|0)|0,(o|0)==(u|0)){B=l,m=u,He=135;break e}else A=o,He=126}else l=0;while(!1);do if((He|0)==126){if(u=0-l|0,!(k>>>0>l>>>0&(l>>>0<2147483647&(A|0)!=-1)))if((A|0)==-1){l=0;break}else{B=l,m=A,He=135;break e}if(o=n[2903]|0,o=T-l+o&0-o,o>>>0>=2147483647){B=l,m=A,He=135;break e}if((qh(o|0)|0)==-1){qh(u|0)|0,l=0;break}else{B=o+l|0,m=A,He=135;break e}}while(!1);n[2894]=n[2894]|4,He=133}while(!1);if((He|0)==133&&M>>>0<2147483647&&(ct=qh(M|0)|0,Qe=qh(0)|0,tt=Qe-ct|0,Ze=tt>>>0>(q+40|0)>>>0,!((ct|0)==-1|Ze^1|ct>>>0>>0&((ct|0)!=-1&(Qe|0)!=-1)^1))&&(B=Ze?tt:l,m=ct,He=135),(He|0)==135){l=(n[2891]|0)+B|0,n[2891]=l,l>>>0>(n[2892]|0)>>>0&&(n[2892]=l),T=n[2789]|0;do if(T){for(l=11580;;){if(o=n[l>>2]|0,u=l+4|0,A=n[u>>2]|0,(m|0)==(o+A|0)){He=145;break}if(d=n[l+8>>2]|0,d)l=d;else break}if((He|0)==145&&!(n[l+12>>2]&8|0)&&T>>>0>>0&T>>>0>=o>>>0){n[u>>2]=A+B,We=T+8|0,We=We&7|0?0-We&7:0,He=T+We|0,We=(n[2786]|0)+(B-We)|0,n[2789]=He,n[2786]=We,n[He+4>>2]=We|1,n[He+We+4>>2]=40,n[2790]=n[2905];break}for(m>>>0<(n[2787]|0)>>>0&&(n[2787]=m),u=m+B|0,l=11580;;){if((n[l>>2]|0)==(u|0)){He=153;break}if(o=n[l+8>>2]|0,o)l=o;else break}if((He|0)==153&&!(n[l+12>>2]&8|0)){n[l>>2]=m,L=l+4|0,n[L>>2]=(n[L>>2]|0)+B,L=m+8|0,L=m+(L&7|0?0-L&7:0)|0,l=u+8|0,l=u+(l&7|0?0-l&7:0)|0,M=L+q|0,k=l-L-q|0,n[L+4>>2]=q|3;do if((l|0)!=(T|0)){if((l|0)==(n[2788]|0)){We=(n[2785]|0)+k|0,n[2785]=We,n[2788]=M,n[M+4>>2]=We|1,n[M+We>>2]=We;break}if(o=n[l+4>>2]|0,(o&3|0)==1){B=o&-8,A=o>>>3;e:do if(o>>>0<256)if(o=n[l+8>>2]|0,u=n[l+12>>2]|0,(u|0)==(o|0)){n[2783]=n[2783]&~(1<>2]=u,n[u+8>>2]=o;break}else{m=n[l+24>>2]|0,o=n[l+12>>2]|0;do if((o|0)==(l|0)){if(A=l+16|0,u=A+4|0,o=n[u>>2]|0,!o)if(o=n[A>>2]|0,o)u=A;else{o=0;break}for(;;){if(A=o+20|0,d=n[A>>2]|0,d|0){o=d,u=A;continue}if(A=o+16|0,d=n[A>>2]|0,d)o=d,u=A;else break}n[u>>2]=0}else We=n[l+8>>2]|0,n[We+12>>2]=o,n[o+8>>2]=We;while(!1);if(!m)break;u=n[l+28>>2]|0,A=11436+(u<<2)|0;do if((l|0)!=(n[A>>2]|0)){if(n[m+16+(((n[m+16>>2]|0)!=(l|0)&1)<<2)>>2]=o,!o)break e}else{if(n[A>>2]=o,o|0)break;n[2784]=n[2784]&~(1<>2]=m,u=l+16|0,A=n[u>>2]|0,A|0&&(n[o+16>>2]=A,n[A+24>>2]=o),u=n[u+4>>2]|0,!u)break;n[o+20>>2]=u,n[u+24>>2]=o}while(!1);l=l+B|0,d=B+k|0}else d=k;if(l=l+4|0,n[l>>2]=n[l>>2]&-2,n[M+4>>2]=d|1,n[M+d>>2]=d,l=d>>>3,d>>>0<256){u=11172+(l<<1<<2)|0,o=n[2783]|0,l=1<>2]|0):(n[2783]=o|l,l=u,o=u+8|0),n[o>>2]=M,n[l+12>>2]=M,n[M+8>>2]=l,n[M+12>>2]=u;break}l=d>>>8;do if(!l)l=0;else{if(d>>>0>16777215){l=31;break}He=(l+1048320|0)>>>16&8,We=l<>>16&4,We=We<>>16&2,l=14-(ct|He|l)+(We<>>15)|0,l=d>>>(l+7|0)&1|l<<1}while(!1);if(A=11436+(l<<2)|0,n[M+28>>2]=l,o=M+16|0,n[o+4>>2]=0,n[o>>2]=0,o=n[2784]|0,u=1<>2]=M,n[M+24>>2]=A,n[M+12>>2]=M,n[M+8>>2]=M;break}for(o=d<<((l|0)==31?0:25-(l>>>1)|0),u=n[A>>2]|0;;){if((n[u+4>>2]&-8|0)==(d|0)){He=194;break}if(A=u+16+(o>>>31<<2)|0,l=n[A>>2]|0,l)o=o<<1,u=l;else{He=193;break}}if((He|0)==193){n[A>>2]=M,n[M+24>>2]=u,n[M+12>>2]=M,n[M+8>>2]=M;break}else if((He|0)==194){He=u+8|0,We=n[He>>2]|0,n[We+12>>2]=M,n[He>>2]=M,n[M+8>>2]=We,n[M+12>>2]=u,n[M+24>>2]=0;break}}else We=(n[2786]|0)+k|0,n[2786]=We,n[2789]=M,n[M+4>>2]=We|1;while(!1);return We=L+8|0,I=Lt,We|0}for(l=11580;o=n[l>>2]|0,!(o>>>0<=T>>>0&&(We=o+(n[l+4>>2]|0)|0,We>>>0>T>>>0));)l=n[l+8>>2]|0;d=We+-47|0,o=d+8|0,o=d+(o&7|0?0-o&7:0)|0,d=T+16|0,o=o>>>0>>0?T:o,l=o+8|0,u=m+8|0,u=u&7|0?0-u&7:0,He=m+u|0,u=B+-40-u|0,n[2789]=He,n[2786]=u,n[He+4>>2]=u|1,n[He+u+4>>2]=40,n[2790]=n[2905],u=o+4|0,n[u>>2]=27,n[l>>2]=n[2895],n[l+4>>2]=n[2896],n[l+8>>2]=n[2897],n[l+12>>2]=n[2898],n[2895]=m,n[2896]=B,n[2898]=0,n[2897]=l,l=o+24|0;do He=l,l=l+4|0,n[l>>2]=7;while((He+8|0)>>>0>>0);if((o|0)!=(T|0)){if(m=o-T|0,n[u>>2]=n[u>>2]&-2,n[T+4>>2]=m|1,n[o>>2]=m,l=m>>>3,m>>>0<256){u=11172+(l<<1<<2)|0,o=n[2783]|0,l=1<>2]|0):(n[2783]=o|l,l=u,o=u+8|0),n[o>>2]=T,n[l+12>>2]=T,n[T+8>>2]=l,n[T+12>>2]=u;break}if(l=m>>>8,l?m>>>0>16777215?u=31:(He=(l+1048320|0)>>>16&8,We=l<>>16&4,We=We<>>16&2,u=14-(ct|He|u)+(We<>>15)|0,u=m>>>(u+7|0)&1|u<<1):u=0,A=11436+(u<<2)|0,n[T+28>>2]=u,n[T+20>>2]=0,n[d>>2]=0,l=n[2784]|0,o=1<>2]=T,n[T+24>>2]=A,n[T+12>>2]=T,n[T+8>>2]=T;break}for(o=m<<((u|0)==31?0:25-(u>>>1)|0),u=n[A>>2]|0;;){if((n[u+4>>2]&-8|0)==(m|0)){He=216;break}if(A=u+16+(o>>>31<<2)|0,l=n[A>>2]|0,l)o=o<<1,u=l;else{He=215;break}}if((He|0)==215){n[A>>2]=T,n[T+24>>2]=u,n[T+12>>2]=T,n[T+8>>2]=T;break}else if((He|0)==216){He=u+8|0,We=n[He>>2]|0,n[We+12>>2]=T,n[He>>2]=T,n[T+8>>2]=We,n[T+12>>2]=u,n[T+24>>2]=0;break}}}else{We=n[2787]|0,(We|0)==0|m>>>0>>0&&(n[2787]=m),n[2895]=m,n[2896]=B,n[2898]=0,n[2792]=n[2901],n[2791]=-1,l=0;do We=11172+(l<<1<<2)|0,n[We+12>>2]=We,n[We+8>>2]=We,l=l+1|0;while((l|0)!=32);We=m+8|0,We=We&7|0?0-We&7:0,He=m+We|0,We=B+-40-We|0,n[2789]=He,n[2786]=We,n[He+4>>2]=We|1,n[He+We+4>>2]=40,n[2790]=n[2905]}while(!1);if(l=n[2786]|0,l>>>0>q>>>0)return ct=l-q|0,n[2786]=ct,We=n[2789]|0,He=We+q|0,n[2789]=He,n[He+4>>2]=ct|1,n[We+4>>2]=q|3,We=We+8|0,I=Lt,We|0}return n[(Xy()|0)>>2]=12,We=0,I=Lt,We|0}function HP(o){o=o|0;var l=0,u=0,A=0,d=0,m=0,B=0,k=0,T=0;if(o){u=o+-8|0,d=n[2787]|0,o=n[o+-4>>2]|0,l=o&-8,T=u+l|0;do if(o&1)k=u,B=u;else{if(A=n[u>>2]|0,!(o&3)||(B=u+(0-A)|0,m=A+l|0,B>>>0>>0))return;if((B|0)==(n[2788]|0)){if(o=T+4|0,l=n[o>>2]|0,(l&3|0)!=3){k=B,l=m;break}n[2785]=m,n[o>>2]=l&-2,n[B+4>>2]=m|1,n[B+m>>2]=m;return}if(u=A>>>3,A>>>0<256)if(o=n[B+8>>2]|0,l=n[B+12>>2]|0,(l|0)==(o|0)){n[2783]=n[2783]&~(1<>2]=l,n[l+8>>2]=o,k=B,l=m;break}d=n[B+24>>2]|0,o=n[B+12>>2]|0;do if((o|0)==(B|0)){if(u=B+16|0,l=u+4|0,o=n[l>>2]|0,!o)if(o=n[u>>2]|0,o)l=u;else{o=0;break}for(;;){if(u=o+20|0,A=n[u>>2]|0,A|0){o=A,l=u;continue}if(u=o+16|0,A=n[u>>2]|0,A)o=A,l=u;else break}n[l>>2]=0}else k=n[B+8>>2]|0,n[k+12>>2]=o,n[o+8>>2]=k;while(!1);if(d){if(l=n[B+28>>2]|0,u=11436+(l<<2)|0,(B|0)==(n[u>>2]|0)){if(n[u>>2]=o,!o){n[2784]=n[2784]&~(1<>2]|0)!=(B|0)&1)<<2)>>2]=o,!o){k=B,l=m;break}n[o+24>>2]=d,l=B+16|0,u=n[l>>2]|0,u|0&&(n[o+16>>2]=u,n[u+24>>2]=o),l=n[l+4>>2]|0,l?(n[o+20>>2]=l,n[l+24>>2]=o,k=B,l=m):(k=B,l=m)}else k=B,l=m}while(!1);if(!(B>>>0>=T>>>0)&&(o=T+4|0,A=n[o>>2]|0,!!(A&1))){if(A&2)n[o>>2]=A&-2,n[k+4>>2]=l|1,n[B+l>>2]=l,d=l;else{if(o=n[2788]|0,(T|0)==(n[2789]|0)){if(T=(n[2786]|0)+l|0,n[2786]=T,n[2789]=k,n[k+4>>2]=T|1,(k|0)!=(o|0))return;n[2788]=0,n[2785]=0;return}if((T|0)==(o|0)){T=(n[2785]|0)+l|0,n[2785]=T,n[2788]=B,n[k+4>>2]=T|1,n[B+T>>2]=T;return}d=(A&-8)+l|0,u=A>>>3;do if(A>>>0<256)if(l=n[T+8>>2]|0,o=n[T+12>>2]|0,(o|0)==(l|0)){n[2783]=n[2783]&~(1<>2]=o,n[o+8>>2]=l;break}else{m=n[T+24>>2]|0,o=n[T+12>>2]|0;do if((o|0)==(T|0)){if(u=T+16|0,l=u+4|0,o=n[l>>2]|0,!o)if(o=n[u>>2]|0,o)l=u;else{u=0;break}for(;;){if(u=o+20|0,A=n[u>>2]|0,A|0){o=A,l=u;continue}if(u=o+16|0,A=n[u>>2]|0,A)o=A,l=u;else break}n[l>>2]=0,u=o}else u=n[T+8>>2]|0,n[u+12>>2]=o,n[o+8>>2]=u,u=o;while(!1);if(m|0){if(o=n[T+28>>2]|0,l=11436+(o<<2)|0,(T|0)==(n[l>>2]|0)){if(n[l>>2]=u,!u){n[2784]=n[2784]&~(1<>2]|0)!=(T|0)&1)<<2)>>2]=u,!u)break;n[u+24>>2]=m,o=T+16|0,l=n[o>>2]|0,l|0&&(n[u+16>>2]=l,n[l+24>>2]=u),o=n[o+4>>2]|0,o|0&&(n[u+20>>2]=o,n[o+24>>2]=u)}}while(!1);if(n[k+4>>2]=d|1,n[B+d>>2]=d,(k|0)==(n[2788]|0)){n[2785]=d;return}}if(o=d>>>3,d>>>0<256){u=11172+(o<<1<<2)|0,l=n[2783]|0,o=1<>2]|0):(n[2783]=l|o,o=u,l=u+8|0),n[l>>2]=k,n[o+12>>2]=k,n[k+8>>2]=o,n[k+12>>2]=u;return}o=d>>>8,o?d>>>0>16777215?o=31:(B=(o+1048320|0)>>>16&8,T=o<>>16&4,T=T<>>16&2,o=14-(m|B|o)+(T<>>15)|0,o=d>>>(o+7|0)&1|o<<1):o=0,A=11436+(o<<2)|0,n[k+28>>2]=o,n[k+20>>2]=0,n[k+16>>2]=0,l=n[2784]|0,u=1<>>1)|0),u=n[A>>2]|0;;){if((n[u+4>>2]&-8|0)==(d|0)){o=73;break}if(A=u+16+(l>>>31<<2)|0,o=n[A>>2]|0,o)l=l<<1,u=o;else{o=72;break}}if((o|0)==72){n[A>>2]=k,n[k+24>>2]=u,n[k+12>>2]=k,n[k+8>>2]=k;break}else if((o|0)==73){B=u+8|0,T=n[B>>2]|0,n[T+12>>2]=k,n[B>>2]=k,n[k+8>>2]=T,n[k+12>>2]=u,n[k+24>>2]=0;break}}else n[2784]=l|u,n[A>>2]=k,n[k+24>>2]=A,n[k+12>>2]=k,n[k+8>>2]=k;while(!1);if(T=(n[2791]|0)+-1|0,n[2791]=T,!T)o=11588;else return;for(;o=n[o>>2]|0,o;)o=o+8|0;n[2791]=-1}}}function r6e(){return 11628}function n6e(o){o=o|0;var l=0,u=0;return l=I,I=I+16|0,u=l,n[u>>2]=o6e(n[o+60>>2]|0)|0,o=jP(Au(6,u|0)|0)|0,I=l,o|0}function yZ(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0,Ye=0;q=I,I=I+48|0,M=q+16|0,m=q,d=q+32|0,k=o+28|0,A=n[k>>2]|0,n[d>>2]=A,T=o+20|0,A=(n[T>>2]|0)-A|0,n[d+4>>2]=A,n[d+8>>2]=l,n[d+12>>2]=u,A=A+u|0,B=o+60|0,n[m>>2]=n[B>>2],n[m+4>>2]=d,n[m+8>>2]=2,m=jP(La(146,m|0)|0)|0;e:do if((A|0)!=(m|0)){for(l=2;!((m|0)<0);)if(A=A-m|0,Ye=n[d+4>>2]|0,ae=m>>>0>Ye>>>0,d=ae?d+8|0:d,l=(ae<<31>>31)+l|0,Ye=m-(ae?Ye:0)|0,n[d>>2]=(n[d>>2]|0)+Ye,ae=d+4|0,n[ae>>2]=(n[ae>>2]|0)-Ye,n[M>>2]=n[B>>2],n[M+4>>2]=d,n[M+8>>2]=l,m=jP(La(146,M|0)|0)|0,(A|0)==(m|0)){L=3;break e}n[o+16>>2]=0,n[k>>2]=0,n[T>>2]=0,n[o>>2]=n[o>>2]|32,(l|0)==2?u=0:u=u-(n[d+4>>2]|0)|0}else L=3;while(!1);return(L|0)==3&&(Ye=n[o+44>>2]|0,n[o+16>>2]=Ye+(n[o+48>>2]|0),n[k>>2]=Ye,n[T>>2]=Ye),I=q,u|0}function i6e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0;return d=I,I=I+32|0,m=d,A=d+20|0,n[m>>2]=n[o+60>>2],n[m+4>>2]=0,n[m+8>>2]=l,n[m+12>>2]=A,n[m+16>>2]=u,(jP(Oa(140,m|0)|0)|0)<0?(n[A>>2]=-1,o=-1):o=n[A>>2]|0,I=d,o|0}function jP(o){return o=o|0,o>>>0>4294963200&&(n[(Xy()|0)>>2]=0-o,o=-1),o|0}function Xy(){return(s6e()|0)+64|0}function s6e(){return lU()|0}function lU(){return 2084}function o6e(o){return o=o|0,o|0}function a6e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0;return d=I,I=I+32|0,A=d,n[o+36>>2]=1,!(n[o>>2]&64|0)&&(n[A>>2]=n[o+60>>2],n[A+4>>2]=21523,n[A+8>>2]=d+16,no(54,A|0)|0)&&(s[o+75>>0]=-1),A=yZ(o,l,u)|0,I=d,A|0}function EZ(o,l){o=o|0,l=l|0;var u=0,A=0;if(u=s[o>>0]|0,A=s[l>>0]|0,!(u<<24>>24)||u<<24>>24!=A<<24>>24)o=A;else{do o=o+1|0,l=l+1|0,u=s[o>>0]|0,A=s[l>>0]|0;while(!(!(u<<24>>24)||u<<24>>24!=A<<24>>24));o=A}return(u&255)-(o&255)|0}function l6e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0;e:do if(!u)o=0;else{for(;A=s[o>>0]|0,d=s[l>>0]|0,A<<24>>24==d<<24>>24;)if(u=u+-1|0,u)o=o+1|0,l=l+1|0;else{o=0;break e}o=(A&255)-(d&255)|0}while(!1);return o|0}function IZ(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0,Ye=0,Le=0,Qe=0;Qe=I,I=I+224|0,L=Qe+120|0,q=Qe+80|0,Ye=Qe,Le=Qe+136|0,A=q,d=A+40|0;do n[A>>2]=0,A=A+4|0;while((A|0)<(d|0));return n[L>>2]=n[u>>2],(cU(0,l,L,Ye,q)|0)<0?u=-1:((n[o+76>>2]|0)>-1?ae=c6e(o)|0:ae=0,u=n[o>>2]|0,M=u&32,(s[o+74>>0]|0)<1&&(n[o>>2]=u&-33),A=o+48|0,n[A>>2]|0?u=cU(o,l,L,Ye,q)|0:(d=o+44|0,m=n[d>>2]|0,n[d>>2]=Le,B=o+28|0,n[B>>2]=Le,k=o+20|0,n[k>>2]=Le,n[A>>2]=80,T=o+16|0,n[T>>2]=Le+80,u=cU(o,l,L,Ye,q)|0,m&&(YP[n[o+36>>2]&7](o,0,0)|0,u=n[k>>2]|0?u:-1,n[d>>2]=m,n[A>>2]=0,n[T>>2]=0,n[B>>2]=0,n[k>>2]=0)),A=n[o>>2]|0,n[o>>2]=A|M,ae|0&&u6e(o),u=A&32|0?-1:u),I=Qe,u|0}function cU(o,l,u,A,d){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0;var m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0,Ye=0,Le=0,Qe=0,tt=0,Ze=0,ct=0,He=0,We=0,Lt=0,Gr=0,fr=0,$t=0,Tr=0,Hr=0,cr=0;cr=I,I=I+64|0,fr=cr+16|0,$t=cr,Lt=cr+24|0,Tr=cr+8|0,Hr=cr+20|0,n[fr>>2]=l,ct=(o|0)!=0,He=Lt+40|0,We=He,Lt=Lt+39|0,Gr=Tr+4|0,B=0,m=0,L=0;e:for(;;){do if((m|0)>-1)if((B|0)>(2147483647-m|0)){n[(Xy()|0)>>2]=75,m=-1;break}else{m=B+m|0;break}while(!1);if(B=s[l>>0]|0,B<<24>>24)k=l;else{Ze=87;break}t:for(;;){switch(B<<24>>24){case 37:{B=k,Ze=9;break t}case 0:{B=k;break t}default:}tt=k+1|0,n[fr>>2]=tt,B=s[tt>>0]|0,k=tt}t:do if((Ze|0)==9)for(;;){if(Ze=0,(s[k+1>>0]|0)!=37)break t;if(B=B+1|0,k=k+2|0,n[fr>>2]=k,(s[k>>0]|0)==37)Ze=9;else break}while(!1);if(B=B-l|0,ct&&vs(o,l,B),B|0){l=k;continue}T=k+1|0,B=(s[T>>0]|0)+-48|0,B>>>0<10?(tt=(s[k+2>>0]|0)==36,Qe=tt?B:-1,L=tt?1:L,T=tt?k+3|0:T):Qe=-1,n[fr>>2]=T,B=s[T>>0]|0,k=(B<<24>>24)+-32|0;t:do if(k>>>0<32)for(M=0,q=B;;){if(B=1<>2]=T,B=s[T>>0]|0,k=(B<<24>>24)+-32|0,k>>>0>=32)break;q=B}else M=0;while(!1);if(B<<24>>24==42){if(k=T+1|0,B=(s[k>>0]|0)+-48|0,B>>>0<10&&(s[T+2>>0]|0)==36)n[d+(B<<2)>>2]=10,B=n[A+((s[k>>0]|0)+-48<<3)>>2]|0,L=1,T=T+3|0;else{if(L|0){m=-1;break}ct?(L=(n[u>>2]|0)+3&-4,B=n[L>>2]|0,n[u>>2]=L+4,L=0,T=k):(B=0,L=0,T=k)}n[fr>>2]=T,tt=(B|0)<0,B=tt?0-B|0:B,M=tt?M|8192:M}else{if(B=CZ(fr)|0,(B|0)<0){m=-1;break}T=n[fr>>2]|0}do if((s[T>>0]|0)==46){if((s[T+1>>0]|0)!=42){n[fr>>2]=T+1,k=CZ(fr)|0,T=n[fr>>2]|0;break}if(q=T+2|0,k=(s[q>>0]|0)+-48|0,k>>>0<10&&(s[T+3>>0]|0)==36){n[d+(k<<2)>>2]=10,k=n[A+((s[q>>0]|0)+-48<<3)>>2]|0,T=T+4|0,n[fr>>2]=T;break}if(L|0){m=-1;break e}ct?(tt=(n[u>>2]|0)+3&-4,k=n[tt>>2]|0,n[u>>2]=tt+4):k=0,n[fr>>2]=q,T=q}else k=-1;while(!1);for(Le=0;;){if(((s[T>>0]|0)+-65|0)>>>0>57){m=-1;break e}if(tt=T+1|0,n[fr>>2]=tt,q=s[(s[T>>0]|0)+-65+(5178+(Le*58|0))>>0]|0,ae=q&255,(ae+-1|0)>>>0<8)Le=ae,T=tt;else break}if(!(q<<24>>24)){m=-1;break}Ye=(Qe|0)>-1;do if(q<<24>>24==19)if(Ye){m=-1;break e}else Ze=49;else{if(Ye){n[d+(Qe<<2)>>2]=ae,Ye=A+(Qe<<3)|0,Qe=n[Ye+4>>2]|0,Ze=$t,n[Ze>>2]=n[Ye>>2],n[Ze+4>>2]=Qe,Ze=49;break}if(!ct){m=0;break e}wZ($t,ae,u)}while(!1);if((Ze|0)==49&&(Ze=0,!ct)){B=0,l=tt;continue}T=s[T>>0]|0,T=(Le|0)!=0&(T&15|0)==3?T&-33:T,Ye=M&-65537,Qe=M&8192|0?Ye:M;t:do switch(T|0){case 110:switch((Le&255)<<24>>24){case 0:{n[n[$t>>2]>>2]=m,B=0,l=tt;continue e}case 1:{n[n[$t>>2]>>2]=m,B=0,l=tt;continue e}case 2:{B=n[$t>>2]|0,n[B>>2]=m,n[B+4>>2]=((m|0)<0)<<31>>31,B=0,l=tt;continue e}case 3:{a[n[$t>>2]>>1]=m,B=0,l=tt;continue e}case 4:{s[n[$t>>2]>>0]=m,B=0,l=tt;continue e}case 6:{n[n[$t>>2]>>2]=m,B=0,l=tt;continue e}case 7:{B=n[$t>>2]|0,n[B>>2]=m,n[B+4>>2]=((m|0)<0)<<31>>31,B=0,l=tt;continue e}default:{B=0,l=tt;continue e}}case 112:{T=120,k=k>>>0>8?k:8,l=Qe|8,Ze=61;break}case 88:case 120:{l=Qe,Ze=61;break}case 111:{T=$t,l=n[T>>2]|0,T=n[T+4>>2]|0,ae=A6e(l,T,He)|0,Ye=We-ae|0,M=0,q=5642,k=(Qe&8|0)==0|(k|0)>(Ye|0)?k:Ye+1|0,Ye=Qe,Ze=67;break}case 105:case 100:if(T=$t,l=n[T>>2]|0,T=n[T+4>>2]|0,(T|0)<0){l=GP(0,0,l|0,T|0)|0,T=ye,M=$t,n[M>>2]=l,n[M+4>>2]=T,M=1,q=5642,Ze=66;break t}else{M=(Qe&2049|0)!=0&1,q=Qe&2048|0?5643:Qe&1|0?5644:5642,Ze=66;break t}case 117:{T=$t,M=0,q=5642,l=n[T>>2]|0,T=n[T+4>>2]|0,Ze=66;break}case 99:{s[Lt>>0]=n[$t>>2],l=Lt,M=0,q=5642,ae=He,T=1,k=Ye;break}case 109:{T=p6e(n[(Xy()|0)>>2]|0)|0,Ze=71;break}case 115:{T=n[$t>>2]|0,T=T|0?T:5652,Ze=71;break}case 67:{n[Tr>>2]=n[$t>>2],n[Gr>>2]=0,n[$t>>2]=Tr,ae=-1,T=Tr,Ze=75;break}case 83:{l=n[$t>>2]|0,k?(ae=k,T=l,Ze=75):(Ls(o,32,B,0,Qe),l=0,Ze=84);break}case 65:case 71:case 70:case 69:case 97:case 103:case 102:case 101:{B=g6e(o,+E[$t>>3],B,k,Qe,T)|0,l=tt;continue e}default:M=0,q=5642,ae=He,T=k,k=Qe}while(!1);t:do if((Ze|0)==61)Qe=$t,Le=n[Qe>>2]|0,Qe=n[Qe+4>>2]|0,ae=f6e(Le,Qe,He,T&32)|0,q=(l&8|0)==0|(Le|0)==0&(Qe|0)==0,M=q?0:2,q=q?5642:5642+(T>>4)|0,Ye=l,l=Le,T=Qe,Ze=67;else if((Ze|0)==66)ae=Zy(l,T,He)|0,Ye=Qe,Ze=67;else if((Ze|0)==71)Ze=0,Qe=h6e(T,0,k)|0,Le=(Qe|0)==0,l=T,M=0,q=5642,ae=Le?T+k|0:Qe,T=Le?k:Qe-T|0,k=Ye;else if((Ze|0)==75){for(Ze=0,q=T,l=0,k=0;M=n[q>>2]|0,!(!M||(k=BZ(Hr,M)|0,(k|0)<0|k>>>0>(ae-l|0)>>>0));)if(l=k+l|0,ae>>>0>l>>>0)q=q+4|0;else break;if((k|0)<0){m=-1;break e}if(Ls(o,32,B,l,Qe),!l)l=0,Ze=84;else for(M=0;;){if(k=n[T>>2]|0,!k){Ze=84;break t}if(k=BZ(Hr,k)|0,M=k+M|0,(M|0)>(l|0)){Ze=84;break t}if(vs(o,Hr,k),M>>>0>=l>>>0){Ze=84;break}else T=T+4|0}}while(!1);if((Ze|0)==67)Ze=0,T=(l|0)!=0|(T|0)!=0,Qe=(k|0)!=0|T,T=((T^1)&1)+(We-ae)|0,l=Qe?ae:He,ae=He,T=Qe?(k|0)>(T|0)?k:T:k,k=(k|0)>-1?Ye&-65537:Ye;else if((Ze|0)==84){Ze=0,Ls(o,32,B,l,Qe^8192),B=(B|0)>(l|0)?B:l,l=tt;continue}Le=ae-l|0,Ye=(T|0)<(Le|0)?Le:T,Qe=Ye+M|0,B=(B|0)<(Qe|0)?Qe:B,Ls(o,32,B,Qe,k),vs(o,q,M),Ls(o,48,B,Qe,k^65536),Ls(o,48,Ye,Le,0),vs(o,l,Le),Ls(o,32,B,Qe,k^8192),l=tt}e:do if((Ze|0)==87&&!o)if(!L)m=0;else{for(m=1;l=n[d+(m<<2)>>2]|0,!!l;)if(wZ(A+(m<<3)|0,l,u),m=m+1|0,(m|0)>=10){m=1;break e}for(;;){if(n[d+(m<<2)>>2]|0){m=-1;break e}if(m=m+1|0,(m|0)>=10){m=1;break}}}while(!1);return I=cr,m|0}function c6e(o){return o=o|0,0}function u6e(o){o=o|0}function vs(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]&32||v6e(l,u,o)|0}function CZ(o){o=o|0;var l=0,u=0,A=0;if(u=n[o>>2]|0,A=(s[u>>0]|0)+-48|0,A>>>0<10){l=0;do l=A+(l*10|0)|0,u=u+1|0,n[o>>2]=u,A=(s[u>>0]|0)+-48|0;while(A>>>0<10)}else l=0;return l|0}function wZ(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0;e:do if(l>>>0<=20)do switch(l|0){case 9:{A=(n[u>>2]|0)+3&-4,l=n[A>>2]|0,n[u>>2]=A+4,n[o>>2]=l;break e}case 10:{A=(n[u>>2]|0)+3&-4,l=n[A>>2]|0,n[u>>2]=A+4,A=o,n[A>>2]=l,n[A+4>>2]=((l|0)<0)<<31>>31;break e}case 11:{A=(n[u>>2]|0)+3&-4,l=n[A>>2]|0,n[u>>2]=A+4,A=o,n[A>>2]=l,n[A+4>>2]=0;break e}case 12:{A=(n[u>>2]|0)+7&-8,l=A,d=n[l>>2]|0,l=n[l+4>>2]|0,n[u>>2]=A+8,A=o,n[A>>2]=d,n[A+4>>2]=l;break e}case 13:{d=(n[u>>2]|0)+3&-4,A=n[d>>2]|0,n[u>>2]=d+4,A=(A&65535)<<16>>16,d=o,n[d>>2]=A,n[d+4>>2]=((A|0)<0)<<31>>31;break e}case 14:{d=(n[u>>2]|0)+3&-4,A=n[d>>2]|0,n[u>>2]=d+4,d=o,n[d>>2]=A&65535,n[d+4>>2]=0;break e}case 15:{d=(n[u>>2]|0)+3&-4,A=n[d>>2]|0,n[u>>2]=d+4,A=(A&255)<<24>>24,d=o,n[d>>2]=A,n[d+4>>2]=((A|0)<0)<<31>>31;break e}case 16:{d=(n[u>>2]|0)+3&-4,A=n[d>>2]|0,n[u>>2]=d+4,d=o,n[d>>2]=A&255,n[d+4>>2]=0;break e}case 17:{d=(n[u>>2]|0)+7&-8,m=+E[d>>3],n[u>>2]=d+8,E[o>>3]=m;break e}case 18:{d=(n[u>>2]|0)+7&-8,m=+E[d>>3],n[u>>2]=d+8,E[o>>3]=m;break e}default:break e}while(!1);while(!1)}function f6e(o,l,u,A){if(o=o|0,l=l|0,u=u|0,A=A|0,!((o|0)==0&(l|0)==0))do u=u+-1|0,s[u>>0]=c[5694+(o&15)>>0]|0|A,o=qP(o|0,l|0,4)|0,l=ye;while(!((o|0)==0&(l|0)==0));return u|0}function A6e(o,l,u){if(o=o|0,l=l|0,u=u|0,!((o|0)==0&(l|0)==0))do u=u+-1|0,s[u>>0]=o&7|48,o=qP(o|0,l|0,3)|0,l=ye;while(!((o|0)==0&(l|0)==0));return u|0}function Zy(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;if(l>>>0>0|(l|0)==0&o>>>0>4294967295){for(;A=pU(o|0,l|0,10,0)|0,u=u+-1|0,s[u>>0]=A&255|48,A=o,o=AU(o|0,l|0,10,0)|0,l>>>0>9|(l|0)==9&A>>>0>4294967295;)l=ye;l=o}else l=o;if(l)for(;u=u+-1|0,s[u>>0]=(l>>>0)%10|0|48,!(l>>>0<10);)l=(l>>>0)/10|0;return u|0}function p6e(o){return o=o|0,I6e(o,n[(E6e()|0)+188>>2]|0)|0}function h6e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;m=l&255,A=(u|0)!=0;e:do if(A&(o&3|0)!=0)for(d=l&255;;){if((s[o>>0]|0)==d<<24>>24){B=6;break e}if(o=o+1|0,u=u+-1|0,A=(u|0)!=0,!(A&(o&3|0)!=0)){B=5;break}}else B=5;while(!1);(B|0)==5&&(A?B=6:u=0);e:do if((B|0)==6&&(d=l&255,(s[o>>0]|0)!=d<<24>>24)){A=Ue(m,16843009)|0;t:do if(u>>>0>3){for(;m=n[o>>2]^A,!((m&-2139062144^-2139062144)&m+-16843009|0);)if(o=o+4|0,u=u+-4|0,u>>>0<=3){B=11;break t}}else B=11;while(!1);if((B|0)==11&&!u){u=0;break}for(;;){if((s[o>>0]|0)==d<<24>>24)break e;if(o=o+1|0,u=u+-1|0,!u){u=0;break}}}while(!1);return(u|0?o:0)|0}function Ls(o,l,u,A,d){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0;var m=0,B=0;if(B=I,I=I+256|0,m=B,(u|0)>(A|0)&(d&73728|0)==0){if(d=u-A|0,eE(m|0,l|0,(d>>>0<256?d:256)|0)|0,d>>>0>255){l=u-A|0;do vs(o,m,256),d=d+-256|0;while(d>>>0>255);d=l&255}vs(o,m,d)}I=B}function BZ(o,l){return o=o|0,l=l|0,o?o=m6e(o,l,0)|0:o=0,o|0}function g6e(o,l,u,A,d,m){o=o|0,l=+l,u=u|0,A=A|0,d=d|0,m=m|0;var B=0,k=0,T=0,M=0,L=0,q=0,ae=0,Ye=0,Le=0,Qe=0,tt=0,Ze=0,ct=0,He=0,We=0,Lt=0,Gr=0,fr=0,$t=0,Tr=0,Hr=0,cr=0,Hn=0;Hn=I,I=I+560|0,T=Hn+8|0,tt=Hn,cr=Hn+524|0,Hr=cr,M=Hn+512|0,n[tt>>2]=0,Tr=M+12|0,vZ(l)|0,(ye|0)<0?(l=-l,fr=1,Gr=5659):(fr=(d&2049|0)!=0&1,Gr=d&2048|0?5662:d&1|0?5665:5660),vZ(l)|0,$t=ye&2146435072;do if($t>>>0<2146435072|($t|0)==2146435072&!1){if(Ye=+d6e(l,tt)*2,B=Ye!=0,B&&(n[tt>>2]=(n[tt>>2]|0)+-1),ct=m|32,(ct|0)==97){Le=m&32,ae=Le|0?Gr+9|0:Gr,q=fr|2,B=12-A|0;do if(A>>>0>11|(B|0)==0)l=Ye;else{l=8;do B=B+-1|0,l=l*16;while(B|0);if((s[ae>>0]|0)==45){l=-(l+(-Ye-l));break}else{l=Ye+l-l;break}}while(!1);k=n[tt>>2]|0,B=(k|0)<0?0-k|0:k,B=Zy(B,((B|0)<0)<<31>>31,Tr)|0,(B|0)==(Tr|0)&&(B=M+11|0,s[B>>0]=48),s[B+-1>>0]=(k>>31&2)+43,L=B+-2|0,s[L>>0]=m+15,M=(A|0)<1,T=(d&8|0)==0,B=cr;do $t=~~l,k=B+1|0,s[B>>0]=c[5694+$t>>0]|Le,l=(l-+($t|0))*16,(k-Hr|0)==1&&!(T&(M&l==0))?(s[k>>0]=46,B=B+2|0):B=k;while(l!=0);$t=B-Hr|0,Hr=Tr-L|0,Tr=(A|0)!=0&($t+-2|0)<(A|0)?A+2|0:$t,B=Hr+q+Tr|0,Ls(o,32,u,B,d),vs(o,ae,q),Ls(o,48,u,B,d^65536),vs(o,cr,$t),Ls(o,48,Tr-$t|0,0,0),vs(o,L,Hr),Ls(o,32,u,B,d^8192);break}k=(A|0)<0?6:A,B?(B=(n[tt>>2]|0)+-28|0,n[tt>>2]=B,l=Ye*268435456):(l=Ye,B=n[tt>>2]|0),$t=(B|0)<0?T:T+288|0,T=$t;do We=~~l>>>0,n[T>>2]=We,T=T+4|0,l=(l-+(We>>>0))*1e9;while(l!=0);if((B|0)>0)for(M=$t,q=T;;){if(L=(B|0)<29?B:29,B=q+-4|0,B>>>0>=M>>>0){T=0;do He=kZ(n[B>>2]|0,0,L|0)|0,He=fU(He|0,ye|0,T|0,0)|0,We=ye,Ze=pU(He|0,We|0,1e9,0)|0,n[B>>2]=Ze,T=AU(He|0,We|0,1e9,0)|0,B=B+-4|0;while(B>>>0>=M>>>0);T&&(M=M+-4|0,n[M>>2]=T)}for(T=q;!(T>>>0<=M>>>0);)if(B=T+-4|0,!(n[B>>2]|0))T=B;else break;if(B=(n[tt>>2]|0)-L|0,n[tt>>2]=B,(B|0)>0)q=T;else break}else M=$t;if((B|0)<0){A=((k+25|0)/9|0)+1|0,Qe=(ct|0)==102;do{if(Le=0-B|0,Le=(Le|0)<9?Le:9,M>>>0>>0){L=(1<>>Le,ae=0,B=M;do We=n[B>>2]|0,n[B>>2]=(We>>>Le)+ae,ae=Ue(We&L,q)|0,B=B+4|0;while(B>>>0>>0);B=n[M>>2]|0?M:M+4|0,ae?(n[T>>2]=ae,M=B,B=T+4|0):(M=B,B=T)}else M=n[M>>2]|0?M:M+4|0,B=T;T=Qe?$t:M,T=(B-T>>2|0)>(A|0)?T+(A<<2)|0:B,B=(n[tt>>2]|0)+Le|0,n[tt>>2]=B}while((B|0)<0);B=M,A=T}else B=M,A=T;if(We=$t,B>>>0>>0){if(T=(We-B>>2)*9|0,L=n[B>>2]|0,L>>>0>=10){M=10;do M=M*10|0,T=T+1|0;while(L>>>0>=M>>>0)}}else T=0;if(Qe=(ct|0)==103,Ze=(k|0)!=0,M=k-((ct|0)!=102?T:0)+((Ze&Qe)<<31>>31)|0,(M|0)<(((A-We>>2)*9|0)+-9|0)){if(M=M+9216|0,Le=$t+4+(((M|0)/9|0)+-1024<<2)|0,M=((M|0)%9|0)+1|0,(M|0)<9){L=10;do L=L*10|0,M=M+1|0;while((M|0)!=9)}else L=10;if(q=n[Le>>2]|0,ae=(q>>>0)%(L>>>0)|0,M=(Le+4|0)==(A|0),M&(ae|0)==0)M=Le;else if(Ye=((q>>>0)/(L>>>0)|0)&1|0?9007199254740994:9007199254740992,He=(L|0)/2|0,l=ae>>>0>>0?.5:M&(ae|0)==(He|0)?1:1.5,fr&&(He=(s[Gr>>0]|0)==45,l=He?-l:l,Ye=He?-Ye:Ye),M=q-ae|0,n[Le>>2]=M,Ye+l!=Ye){if(He=M+L|0,n[Le>>2]=He,He>>>0>999999999)for(T=Le;M=T+-4|0,n[T>>2]=0,M>>>0>>0&&(B=B+-4|0,n[B>>2]=0),He=(n[M>>2]|0)+1|0,n[M>>2]=He,He>>>0>999999999;)T=M;else M=Le;if(T=(We-B>>2)*9|0,q=n[B>>2]|0,q>>>0>=10){L=10;do L=L*10|0,T=T+1|0;while(q>>>0>=L>>>0)}}else M=Le;M=M+4|0,M=A>>>0>M>>>0?M:A,He=B}else M=A,He=B;for(ct=M;;){if(ct>>>0<=He>>>0){tt=0;break}if(B=ct+-4|0,!(n[B>>2]|0))ct=B;else{tt=1;break}}A=0-T|0;do if(Qe)if(B=((Ze^1)&1)+k|0,(B|0)>(T|0)&(T|0)>-5?(L=m+-1|0,k=B+-1-T|0):(L=m+-2|0,k=B+-1|0),B=d&8,B)Le=B;else{if(tt&&(Lt=n[ct+-4>>2]|0,(Lt|0)!=0))if((Lt>>>0)%10|0)M=0;else{M=0,B=10;do B=B*10|0,M=M+1|0;while(!((Lt>>>0)%(B>>>0)|0|0))}else M=9;if(B=((ct-We>>2)*9|0)+-9|0,(L|32|0)==102){Le=B-M|0,Le=(Le|0)>0?Le:0,k=(k|0)<(Le|0)?k:Le,Le=0;break}else{Le=B+T-M|0,Le=(Le|0)>0?Le:0,k=(k|0)<(Le|0)?k:Le,Le=0;break}}else L=m,Le=d&8;while(!1);if(Qe=k|Le,q=(Qe|0)!=0&1,ae=(L|32|0)==102,ae)Ze=0,B=(T|0)>0?T:0;else{if(B=(T|0)<0?A:T,B=Zy(B,((B|0)<0)<<31>>31,Tr)|0,M=Tr,(M-B|0)<2)do B=B+-1|0,s[B>>0]=48;while((M-B|0)<2);s[B+-1>>0]=(T>>31&2)+43,B=B+-2|0,s[B>>0]=L,Ze=B,B=M-B|0}if(B=fr+1+k+q+B|0,Ls(o,32,u,B,d),vs(o,Gr,fr),Ls(o,48,u,B,d^65536),ae){L=He>>>0>$t>>>0?$t:He,Le=cr+9|0,q=Le,ae=cr+8|0,M=L;do{if(T=Zy(n[M>>2]|0,0,Le)|0,(M|0)==(L|0))(T|0)==(Le|0)&&(s[ae>>0]=48,T=ae);else if(T>>>0>cr>>>0){eE(cr|0,48,T-Hr|0)|0;do T=T+-1|0;while(T>>>0>cr>>>0)}vs(o,T,q-T|0),M=M+4|0}while(M>>>0<=$t>>>0);if(Qe|0&&vs(o,5710,1),M>>>0>>0&(k|0)>0)for(;;){if(T=Zy(n[M>>2]|0,0,Le)|0,T>>>0>cr>>>0){eE(cr|0,48,T-Hr|0)|0;do T=T+-1|0;while(T>>>0>cr>>>0)}if(vs(o,T,(k|0)<9?k:9),M=M+4|0,T=k+-9|0,M>>>0>>0&(k|0)>9)k=T;else{k=T;break}}Ls(o,48,k+9|0,9,0)}else{if(Qe=tt?ct:He+4|0,(k|0)>-1){tt=cr+9|0,Le=(Le|0)==0,A=tt,q=0-Hr|0,ae=cr+8|0,L=He;do{T=Zy(n[L>>2]|0,0,tt)|0,(T|0)==(tt|0)&&(s[ae>>0]=48,T=ae);do if((L|0)==(He|0)){if(M=T+1|0,vs(o,T,1),Le&(k|0)<1){T=M;break}vs(o,5710,1),T=M}else{if(T>>>0<=cr>>>0)break;eE(cr|0,48,T+q|0)|0;do T=T+-1|0;while(T>>>0>cr>>>0)}while(!1);Hr=A-T|0,vs(o,T,(k|0)>(Hr|0)?Hr:k),k=k-Hr|0,L=L+4|0}while(L>>>0>>0&(k|0)>-1)}Ls(o,48,k+18|0,18,0),vs(o,Ze,Tr-Ze|0)}Ls(o,32,u,B,d^8192)}else cr=(m&32|0)!=0,B=fr+3|0,Ls(o,32,u,B,d&-65537),vs(o,Gr,fr),vs(o,l!=l|!1?cr?5686:5690:cr?5678:5682,3),Ls(o,32,u,B,d^8192);while(!1);return I=Hn,((B|0)<(u|0)?u:B)|0}function vZ(o){o=+o;var l=0;return E[S>>3]=o,l=n[S>>2]|0,ye=n[S+4>>2]|0,l|0}function d6e(o,l){return o=+o,l=l|0,+ +SZ(o,l)}function SZ(o,l){o=+o,l=l|0;var u=0,A=0,d=0;switch(E[S>>3]=o,u=n[S>>2]|0,A=n[S+4>>2]|0,d=qP(u|0,A|0,52)|0,d&2047){case 0:{o!=0?(o=+SZ(o*18446744073709552e3,l),u=(n[l>>2]|0)+-64|0):u=0,n[l>>2]=u;break}case 2047:break;default:n[l>>2]=(d&2047)+-1022,n[S>>2]=u,n[S+4>>2]=A&-2146435073|1071644672,o=+E[S>>3]}return+o}function m6e(o,l,u){o=o|0,l=l|0,u=u|0;do if(o){if(l>>>0<128){s[o>>0]=l,o=1;break}if(!(n[n[(y6e()|0)+188>>2]>>2]|0))if((l&-128|0)==57216){s[o>>0]=l,o=1;break}else{n[(Xy()|0)>>2]=84,o=-1;break}if(l>>>0<2048){s[o>>0]=l>>>6|192,s[o+1>>0]=l&63|128,o=2;break}if(l>>>0<55296|(l&-8192|0)==57344){s[o>>0]=l>>>12|224,s[o+1>>0]=l>>>6&63|128,s[o+2>>0]=l&63|128,o=3;break}if((l+-65536|0)>>>0<1048576){s[o>>0]=l>>>18|240,s[o+1>>0]=l>>>12&63|128,s[o+2>>0]=l>>>6&63|128,s[o+3>>0]=l&63|128,o=4;break}else{n[(Xy()|0)>>2]=84,o=-1;break}}else o=1;while(!1);return o|0}function y6e(){return lU()|0}function E6e(){return lU()|0}function I6e(o,l){o=o|0,l=l|0;var u=0,A=0;for(A=0;;){if((c[5712+A>>0]|0)==(o|0)){o=2;break}if(u=A+1|0,(u|0)==87){u=5800,A=87,o=5;break}else A=u}if((o|0)==2&&(A?(u=5800,o=5):u=5800),(o|0)==5)for(;;){do o=u,u=u+1|0;while(s[o>>0]|0);if(A=A+-1|0,A)o=5;else break}return C6e(u,n[l+20>>2]|0)|0}function C6e(o,l){return o=o|0,l=l|0,w6e(o,l)|0}function w6e(o,l){return o=o|0,l=l|0,l?l=B6e(n[l>>2]|0,n[l+4>>2]|0,o)|0:l=0,(l|0?l:o)|0}function B6e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0;ae=(n[o>>2]|0)+1794895138|0,m=Ad(n[o+8>>2]|0,ae)|0,A=Ad(n[o+12>>2]|0,ae)|0,d=Ad(n[o+16>>2]|0,ae)|0;e:do if(m>>>0>>2>>>0&&(q=l-(m<<2)|0,A>>>0>>0&d>>>0>>0)&&!((d|A)&3|0)){for(q=A>>>2,L=d>>>2,M=0;;){if(k=m>>>1,T=M+k|0,B=T<<1,d=B+q|0,A=Ad(n[o+(d<<2)>>2]|0,ae)|0,d=Ad(n[o+(d+1<<2)>>2]|0,ae)|0,!(d>>>0>>0&A>>>0<(l-d|0)>>>0)){A=0;break e}if(s[o+(d+A)>>0]|0){A=0;break e}if(A=EZ(u,o+d|0)|0,!A)break;if(A=(A|0)<0,(m|0)==1){A=0;break e}else M=A?M:T,m=A?k:m-k|0}A=B+L|0,d=Ad(n[o+(A<<2)>>2]|0,ae)|0,A=Ad(n[o+(A+1<<2)>>2]|0,ae)|0,A>>>0>>0&d>>>0<(l-A|0)>>>0?A=s[o+(A+d)>>0]|0?0:o+A|0:A=0}else A=0;while(!1);return A|0}function Ad(o,l){o=o|0,l=l|0;var u=0;return u=RZ(o|0)|0,(l|0?u:o)|0}function v6e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=u+16|0,d=n[A>>2]|0,d?m=5:S6e(u)|0?A=0:(d=n[A>>2]|0,m=5);e:do if((m|0)==5){if(k=u+20|0,B=n[k>>2]|0,A=B,(d-B|0)>>>0>>0){A=YP[n[u+36>>2]&7](u,o,l)|0;break}t:do if((s[u+75>>0]|0)>-1){for(B=l;;){if(!B){m=0,d=o;break t}if(d=B+-1|0,(s[o+d>>0]|0)==10)break;B=d}if(A=YP[n[u+36>>2]&7](u,o,B)|0,A>>>0>>0)break e;m=B,d=o+B|0,l=l-B|0,A=n[k>>2]|0}else m=0,d=o;while(!1);Qr(A|0,d|0,l|0)|0,n[k>>2]=(n[k>>2]|0)+l,A=m+l|0}while(!1);return A|0}function S6e(o){o=o|0;var l=0,u=0;return l=o+74|0,u=s[l>>0]|0,s[l>>0]=u+255|u,l=n[o>>2]|0,l&8?(n[o>>2]=l|32,o=-1):(n[o+8>>2]=0,n[o+4>>2]=0,u=n[o+44>>2]|0,n[o+28>>2]=u,n[o+20>>2]=u,n[o+16>>2]=u+(n[o+48>>2]|0),o=0),o|0}function $n(o,l){o=y(o),l=y(l);var u=0,A=0;u=DZ(o)|0;do if((u&2147483647)>>>0<=2139095040){if(A=DZ(l)|0,(A&2147483647)>>>0<=2139095040)if((A^u|0)<0){o=(u|0)<0?l:o;break}else{o=o>2]=o,n[S>>2]|0|0}function pd(o,l){o=y(o),l=y(l);var u=0,A=0;u=bZ(o)|0;do if((u&2147483647)>>>0<=2139095040){if(A=bZ(l)|0,(A&2147483647)>>>0<=2139095040)if((A^u|0)<0){o=(u|0)<0?o:l;break}else{o=o>2]=o,n[S>>2]|0|0}function uU(o,l){o=y(o),l=y(l);var u=0,A=0,d=0,m=0,B=0,k=0,T=0,M=0;m=(h[S>>2]=o,n[S>>2]|0),k=(h[S>>2]=l,n[S>>2]|0),u=m>>>23&255,B=k>>>23&255,T=m&-2147483648,d=k<<1;e:do if(d|0&&!((u|0)==255|((D6e(l)|0)&2147483647)>>>0>2139095040)){if(A=m<<1,A>>>0<=d>>>0)return l=y(o*y(0)),y((A|0)==(d|0)?l:o);if(u)A=m&8388607|8388608;else{if(u=m<<9,(u|0)>-1){A=u,u=0;do u=u+-1|0,A=A<<1;while((A|0)>-1)}else u=0;A=m<<1-u}if(B)k=k&8388607|8388608;else{if(m=k<<9,(m|0)>-1){d=0;do d=d+-1|0,m=m<<1;while((m|0)>-1)}else d=0;B=d,k=k<<1-d}d=A-k|0,m=(d|0)>-1;t:do if((u|0)>(B|0)){for(;;){if(m)if(d)A=d;else break;if(A=A<<1,u=u+-1|0,d=A-k|0,m=(d|0)>-1,(u|0)<=(B|0))break t}l=y(o*y(0));break e}while(!1);if(m)if(d)A=d;else{l=y(o*y(0));break}if(A>>>0<8388608)do A=A<<1,u=u+-1|0;while(A>>>0<8388608);(u|0)>0?u=A+-8388608|u<<23:u=A>>>(1-u|0),l=(n[S>>2]=u|T,y(h[S>>2]))}else M=3;while(!1);return(M|0)==3&&(l=y(o*l),l=y(l/l)),y(l)}function D6e(o){return o=y(o),h[S>>2]=o,n[S>>2]|0|0}function b6e(o,l){return o=o|0,l=l|0,IZ(n[582]|0,o,l)|0}function an(o){o=o|0,Nt()}function $y(o){o=o|0}function P6e(o,l){return o=o|0,l=l|0,0}function x6e(o){return o=o|0,(PZ(o+4|0)|0)==-1?(ip[n[(n[o>>2]|0)+8>>2]&127](o),o=1):o=0,o|0}function PZ(o){o=o|0;var l=0;return l=n[o>>2]|0,n[o>>2]=l+-1,l+-1|0}function Gh(o){o=o|0,x6e(o)|0&&k6e(o)}function k6e(o){o=o|0;var l=0;l=o+8|0,n[l>>2]|0&&(PZ(l)|0)!=-1||ip[n[(n[o>>2]|0)+16>>2]&127](o)}function Kt(o){o=o|0;var l=0;for(l=o|0?o:1;o=_P(l)|0,!(o|0);){if(o=T6e()|0,!o){o=0;break}GZ[o&0]()}return o|0}function xZ(o){return o=o|0,Kt(o)|0}function It(o){o=o|0,HP(o)}function Q6e(o){o=o|0,(s[o+11>>0]|0)<0&&It(n[o>>2]|0)}function T6e(){var o=0;return o=n[2923]|0,n[2923]=o+0,o|0}function R6e(){}function GP(o,l,u,A){return o=o|0,l=l|0,u=u|0,A=A|0,A=l-A-(u>>>0>o>>>0|0)>>>0,ye=A,o-u>>>0|0|0}function fU(o,l,u,A){return o=o|0,l=l|0,u=u|0,A=A|0,u=o+u>>>0,ye=l+A+(u>>>0>>0|0)>>>0,u|0|0}function eE(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;if(m=o+u|0,l=l&255,(u|0)>=67){for(;o&3;)s[o>>0]=l,o=o+1|0;for(A=m&-4|0,d=A-64|0,B=l|l<<8|l<<16|l<<24;(o|0)<=(d|0);)n[o>>2]=B,n[o+4>>2]=B,n[o+8>>2]=B,n[o+12>>2]=B,n[o+16>>2]=B,n[o+20>>2]=B,n[o+24>>2]=B,n[o+28>>2]=B,n[o+32>>2]=B,n[o+36>>2]=B,n[o+40>>2]=B,n[o+44>>2]=B,n[o+48>>2]=B,n[o+52>>2]=B,n[o+56>>2]=B,n[o+60>>2]=B,o=o+64|0;for(;(o|0)<(A|0);)n[o>>2]=B,o=o+4|0}for(;(o|0)<(m|0);)s[o>>0]=l,o=o+1|0;return m-u|0}function kZ(o,l,u){return o=o|0,l=l|0,u=u|0,(u|0)<32?(ye=l<>>32-u,o<>>u,o>>>u|(l&(1<>>u-32|0)}function Qr(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0;if((u|0)>=8192)return OA(o|0,l|0,u|0)|0;if(m=o|0,d=o+u|0,(o&3)==(l&3)){for(;o&3;){if(!u)return m|0;s[o>>0]=s[l>>0]|0,o=o+1|0,l=l+1|0,u=u-1|0}for(u=d&-4|0,A=u-64|0;(o|0)<=(A|0);)n[o>>2]=n[l>>2],n[o+4>>2]=n[l+4>>2],n[o+8>>2]=n[l+8>>2],n[o+12>>2]=n[l+12>>2],n[o+16>>2]=n[l+16>>2],n[o+20>>2]=n[l+20>>2],n[o+24>>2]=n[l+24>>2],n[o+28>>2]=n[l+28>>2],n[o+32>>2]=n[l+32>>2],n[o+36>>2]=n[l+36>>2],n[o+40>>2]=n[l+40>>2],n[o+44>>2]=n[l+44>>2],n[o+48>>2]=n[l+48>>2],n[o+52>>2]=n[l+52>>2],n[o+56>>2]=n[l+56>>2],n[o+60>>2]=n[l+60>>2],o=o+64|0,l=l+64|0;for(;(o|0)<(u|0);)n[o>>2]=n[l>>2],o=o+4|0,l=l+4|0}else for(u=d-4|0;(o|0)<(u|0);)s[o>>0]=s[l>>0]|0,s[o+1>>0]=s[l+1>>0]|0,s[o+2>>0]=s[l+2>>0]|0,s[o+3>>0]=s[l+3>>0]|0,o=o+4|0,l=l+4|0;for(;(o|0)<(d|0);)s[o>>0]=s[l>>0]|0,o=o+1|0,l=l+1|0;return m|0}function QZ(o){o=o|0;var l=0;return l=s[N+(o&255)>>0]|0,(l|0)<8?l|0:(l=s[N+(o>>8&255)>>0]|0,(l|0)<8?l+8|0:(l=s[N+(o>>16&255)>>0]|0,(l|0)<8?l+16|0:(s[N+(o>>>24)>>0]|0)+24|0))}function TZ(o,l,u,A,d){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0;var m=0,B=0,k=0,T=0,M=0,L=0,q=0,ae=0,Ye=0,Le=0;if(L=o,T=l,M=T,B=u,ae=A,k=ae,!M)return m=(d|0)!=0,k?m?(n[d>>2]=o|0,n[d+4>>2]=l&0,ae=0,d=0,ye=ae,d|0):(ae=0,d=0,ye=ae,d|0):(m&&(n[d>>2]=(L>>>0)%(B>>>0),n[d+4>>2]=0),ae=0,d=(L>>>0)/(B>>>0)>>>0,ye=ae,d|0);m=(k|0)==0;do if(B){if(!m){if(m=(b(k|0)|0)-(b(M|0)|0)|0,m>>>0<=31){q=m+1|0,k=31-m|0,l=m-31>>31,B=q,o=L>>>(q>>>0)&l|M<>>(q>>>0)&l,m=0,k=L<>2]=o|0,n[d+4>>2]=T|l&0,ae=0,d=0,ye=ae,d|0):(ae=0,d=0,ye=ae,d|0)}if(m=B-1|0,m&B|0){k=(b(B|0)|0)+33-(b(M|0)|0)|0,Le=64-k|0,q=32-k|0,T=q>>31,Ye=k-32|0,l=Ye>>31,B=k,o=q-1>>31&M>>>(Ye>>>0)|(M<>>(k>>>0))&l,l=l&M>>>(k>>>0),m=L<>>(Ye>>>0))&T|L<>31;break}return d|0&&(n[d>>2]=m&L,n[d+4>>2]=0),(B|0)==1?(Ye=T|l&0,Le=o|0|0,ye=Ye,Le|0):(Le=QZ(B|0)|0,Ye=M>>>(Le>>>0)|0,Le=M<<32-Le|L>>>(Le>>>0)|0,ye=Ye,Le|0)}else{if(m)return d|0&&(n[d>>2]=(M>>>0)%(B>>>0),n[d+4>>2]=0),Ye=0,Le=(M>>>0)/(B>>>0)>>>0,ye=Ye,Le|0;if(!L)return d|0&&(n[d>>2]=0,n[d+4>>2]=(M>>>0)%(k>>>0)),Ye=0,Le=(M>>>0)/(k>>>0)>>>0,ye=Ye,Le|0;if(m=k-1|0,!(m&k))return d|0&&(n[d>>2]=o|0,n[d+4>>2]=m&M|l&0),Ye=0,Le=M>>>((QZ(k|0)|0)>>>0),ye=Ye,Le|0;if(m=(b(k|0)|0)-(b(M|0)|0)|0,m>>>0<=30){l=m+1|0,k=31-m|0,B=l,o=M<>>(l>>>0),l=M>>>(l>>>0),m=0,k=L<>2]=o|0,n[d+4>>2]=T|l&0,Ye=0,Le=0,ye=Ye,Le|0):(Ye=0,Le=0,ye=Ye,Le|0)}while(!1);if(!B)M=k,T=0,k=0;else{q=u|0|0,L=ae|A&0,M=fU(q|0,L|0,-1,-1)|0,u=ye,T=k,k=0;do A=T,T=m>>>31|T<<1,m=k|m<<1,A=o<<1|A>>>31|0,ae=o>>>31|l<<1|0,GP(M|0,u|0,A|0,ae|0)|0,Le=ye,Ye=Le>>31|((Le|0)<0?-1:0)<<1,k=Ye&1,o=GP(A|0,ae|0,Ye&q|0,(((Le|0)<0?-1:0)>>31|((Le|0)<0?-1:0)<<1)&L|0)|0,l=ye,B=B-1|0;while(B|0);M=T,T=0}return B=0,d|0&&(n[d>>2]=o,n[d+4>>2]=l),Ye=(m|0)>>>31|(M|B)<<1|(B<<1|m>>>31)&0|T,Le=(m<<1|0)&-2|k,ye=Ye,Le|0}function AU(o,l,u,A){return o=o|0,l=l|0,u=u|0,A=A|0,TZ(o,l,u,A,0)|0}function qh(o){o=o|0;var l=0,u=0;return u=o+15&-16|0,l=n[C>>2]|0,o=l+u|0,(u|0)>0&(o|0)<(l|0)|(o|0)<0?(oe()|0,fu(12),-1):(n[C>>2]=o,(o|0)>($()|0)&&!(X()|0)?(n[C>>2]=l,fu(12),-1):l|0)}function Q2(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;if((l|0)<(o|0)&(o|0)<(l+u|0)){for(A=o,l=l+u|0,o=o+u|0;(u|0)>0;)o=o-1|0,l=l-1|0,u=u-1|0,s[o>>0]=s[l>>0]|0;o=A}else Qr(o,l,u)|0;return o|0}function pU(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0;return m=I,I=I+16|0,d=m|0,TZ(o,l,u,A,d)|0,I=m,ye=n[d+4>>2]|0,n[d>>2]|0|0}function RZ(o){return o=o|0,(o&255)<<24|(o>>8&255)<<16|(o>>16&255)<<8|o>>>24|0}function F6e(o,l,u,A,d,m){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0,FZ[o&1](l|0,u|0,A|0,d|0,m|0)}function N6e(o,l,u){o=o|0,l=l|0,u=y(u),NZ[o&1](l|0,y(u))}function O6e(o,l,u){o=o|0,l=l|0,u=+u,OZ[o&31](l|0,+u)}function L6e(o,l,u,A){return o=o|0,l=l|0,u=y(u),A=y(A),y(LZ[o&0](l|0,y(u),y(A)))}function M6e(o,l){o=o|0,l=l|0,ip[o&127](l|0)}function U6e(o,l,u){o=o|0,l=l|0,u=u|0,sp[o&31](l|0,u|0)}function _6e(o,l){return o=o|0,l=l|0,gd[o&31](l|0)|0}function H6e(o,l,u,A,d){o=o|0,l=l|0,u=+u,A=+A,d=d|0,MZ[o&1](l|0,+u,+A,d|0)}function j6e(o,l,u,A){o=o|0,l=l|0,u=+u,A=+A,wGe[o&1](l|0,+u,+A)}function G6e(o,l,u,A){return o=o|0,l=l|0,u=u|0,A=A|0,YP[o&7](l|0,u|0,A|0)|0}function q6e(o,l,u,A){return o=o|0,l=l|0,u=u|0,A=A|0,+BGe[o&1](l|0,u|0,A|0)}function W6e(o,l){return o=o|0,l=l|0,+UZ[o&15](l|0)}function Y6e(o,l,u){return o=o|0,l=l|0,u=+u,vGe[o&1](l|0,+u)|0}function V6e(o,l,u){return o=o|0,l=l|0,u=u|0,gU[o&15](l|0,u|0)|0}function J6e(o,l,u,A,d,m){o=o|0,l=l|0,u=u|0,A=+A,d=+d,m=m|0,SGe[o&1](l|0,u|0,+A,+d,m|0)}function K6e(o,l,u,A,d,m,B){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0,B=B|0,DGe[o&1](l|0,u|0,A|0,d|0,m|0,B|0)}function z6e(o,l,u){return o=o|0,l=l|0,u=u|0,+_Z[o&7](l|0,u|0)}function X6e(o){return o=o|0,VP[o&7]()|0}function Z6e(o,l,u,A,d,m){return o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0,HZ[o&1](l|0,u|0,A|0,d|0,m|0)|0}function $6e(o,l,u,A,d){o=o|0,l=l|0,u=u|0,A=A|0,d=+d,bGe[o&1](l|0,u|0,A|0,+d)}function eGe(o,l,u,A,d,m,B){o=o|0,l=l|0,u=u|0,A=y(A),d=d|0,m=y(m),B=B|0,jZ[o&1](l|0,u|0,y(A),d|0,y(m),B|0)}function tGe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0,F2[o&15](l|0,u|0,A|0)}function rGe(o){o=o|0,GZ[o&0]()}function nGe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=+A,qZ[o&15](l|0,u|0,+A)}function iGe(o,l,u){return o=o|0,l=+l,u=+u,PGe[o&1](+l,+u)|0}function sGe(o,l,u,A,d){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,dU[o&15](l|0,u|0,A|0,d|0)}function oGe(o,l,u,A,d){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,F(0)}function aGe(o,l){o=o|0,l=y(l),F(1)}function Xa(o,l){o=o|0,l=+l,F(2)}function lGe(o,l,u){return o=o|0,l=y(l),u=y(u),F(3),$e}function wr(o){o=o|0,F(4)}function T2(o,l){o=o|0,l=l|0,F(5)}function Ol(o){return o=o|0,F(6),0}function cGe(o,l,u,A){o=o|0,l=+l,u=+u,A=A|0,F(7)}function uGe(o,l,u){o=o|0,l=+l,u=+u,F(8)}function fGe(o,l,u){return o=o|0,l=l|0,u=u|0,F(9),0}function AGe(o,l,u){return o=o|0,l=l|0,u=u|0,F(10),0}function hd(o){return o=o|0,F(11),0}function pGe(o,l){return o=o|0,l=+l,F(12),0}function R2(o,l){return o=o|0,l=l|0,F(13),0}function hGe(o,l,u,A,d){o=o|0,l=l|0,u=+u,A=+A,d=d|0,F(14)}function gGe(o,l,u,A,d,m){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0,F(15)}function hU(o,l){return o=o|0,l=l|0,F(16),0}function dGe(){return F(17),0}function mGe(o,l,u,A,d){return o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,F(18),0}function yGe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=+A,F(19)}function EGe(o,l,u,A,d,m){o=o|0,l=l|0,u=y(u),A=A|0,d=y(d),m=m|0,F(20)}function WP(o,l,u){o=o|0,l=l|0,u=u|0,F(21)}function IGe(){F(22)}function tE(o,l,u){o=o|0,l=l|0,u=+u,F(23)}function CGe(o,l){return o=+o,l=+l,F(24),0}function rE(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0,F(25)}var FZ=[oGe,m3e],NZ=[aGe,Ty],OZ=[Xa,Zg,Fh,h2,g2,d2,m2,bf,_y,y2,Pf,$g,ed,E2,I2,wu,td,C2,Hy,Xa,Xa,Xa,Xa,Xa,Xa,Xa,Xa,Xa,Xa,Xa,Xa,Xa],LZ=[lGe],ip=[wr,$y,Xke,Zke,$ke,PFe,xFe,kFe,Y_e,V_e,J_e,i3e,s3e,o3e,Dje,bje,Pje,Bl,Xg,u2,sr,hc,xP,kP,Hke,aQe,EQe,LQe,$Qe,dTe,RTe,JTe,cRe,SRe,HRe,nFe,EFe,VFe,cNe,SNe,HNe,nOe,EOe,MOe,$Oe,pLe,xLe,dP,oMe,wMe,HMe,sUe,IUe,HUe,XUe,e_e,m_e,I_e,L_e,z_e,$_e,d4e,F4e,Iz,g8e,Y8e,aHe,wHe,qHe,sje,dje,Eje,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr],sp=[T2,Ly,JL,f2,A2,xr,so,Xi,Ns,ws,Uy,Rh,B2,CP,id,XL,ZL,wP,BP,tM,xf,ne,jOe,rLe,cUe,y8e,j4e,iZ,T2,T2,T2,T2],gd=[Ol,n6e,Ny,nd,Gy,ga,mP,Nh,w2,zL,EP,qy,vP,rM,Vy,TLe,vUe,E4e,w8e,Rl,Ol,Ol,Ol,Ol,Ol,Ol,Ol,Ol,Ol,Ol,Ol,Ol],MZ=[cGe,aM],wGe=[uGe,__e],YP=[fGe,yZ,i6e,a6e,ITe,XFe,uMe,DHe],BGe=[AGe,WRe],UZ=[hd,Oh,IP,$A,lM,v,D,Q,H,V,hd,hd,hd,hd,hd,hd],vGe=[pGe,JUe],gU=[R2,P6e,SP,Wke,HQe,OTe,XTe,BFe,pNe,mLe,Ry,fHe,R2,R2,R2,R2],SGe=[hGe,BQe],DGe=[gGe,JHe],_Z=[hU,$L,Se,_e,pt,aFe,hU,hU],VP=[dGe,Wt,Fy,gP,i_e,v_e,n4e,Bje],HZ=[mGe,Sy],bGe=[yGe,WNe],jZ=[EGe,nM],F2=[WP,ko,yP,eM,vu,nTe,ARe,aOe,BOe,VL,_3e,z8e,cje,WP,WP,WP],GZ=[IGe],qZ=[tE,KL,My,ZA,p2,Bu,jy,rd,xNe,DMe,qUe,tE,tE,tE,tE,tE],PGe=[CGe,q_e],dU=[rE,xRe,_Le,WMe,RUe,u_e,k_e,u4e,U4e,P8e,Fje,rE,rE,rE,rE,rE];return{_llvm_bswap_i32:RZ,dynCall_idd:iGe,dynCall_i:X6e,_i64Subtract:GP,___udivdi3:AU,dynCall_vif:N6e,setThrew:ca,dynCall_viii:tGe,_bitshift64Lshr:qP,_bitshift64Shl:kZ,dynCall_vi:M6e,dynCall_viiddi:J6e,dynCall_diii:q6e,dynCall_iii:V6e,_memset:eE,_sbrk:qh,_memcpy:Qr,__GLOBAL__sub_I_Yoga_cpp:a2,dynCall_vii:U6e,___uremdi3:pU,dynCall_vid:O6e,stackAlloc:Ua,_nbind_init:Wje,getTempRet0:MA,dynCall_di:W6e,dynCall_iid:Y6e,setTempRet0:LA,_i64Add:fU,dynCall_fiff:L6e,dynCall_iiii:G6e,_emscripten_get_global_libc:r6e,dynCall_viid:nGe,dynCall_viiid:$6e,dynCall_viififi:eGe,dynCall_ii:_6e,__GLOBAL__sub_I_Binding_cc:a8e,dynCall_viiii:sGe,dynCall_iiiiii:Z6e,stackSave:hf,dynCall_viiiii:F6e,__GLOBAL__sub_I_nbind_cc:Sr,dynCall_vidd:j6e,_free:HP,runPostSets:R6e,dynCall_viiiiii:K6e,establishStackSpace:wn,_memmove:Q2,stackRestore:lc,_malloc:_P,__GLOBAL__sub_I_common_cc:b4e,dynCall_viddi:H6e,dynCall_dii:z6e,dynCall_v:rGe}}(Module.asmGlobalArg,Module.asmLibraryArg,buffer),_llvm_bswap_i32=Module._llvm_bswap_i32=asm._llvm_bswap_i32,getTempRet0=Module.getTempRet0=asm.getTempRet0,___udivdi3=Module.___udivdi3=asm.___udivdi3,setThrew=Module.setThrew=asm.setThrew,_bitshift64Lshr=Module._bitshift64Lshr=asm._bitshift64Lshr,_bitshift64Shl=Module._bitshift64Shl=asm._bitshift64Shl,_memset=Module._memset=asm._memset,_sbrk=Module._sbrk=asm._sbrk,_memcpy=Module._memcpy=asm._memcpy,stackAlloc=Module.stackAlloc=asm.stackAlloc,___uremdi3=Module.___uremdi3=asm.___uremdi3,_nbind_init=Module._nbind_init=asm._nbind_init,_i64Subtract=Module._i64Subtract=asm._i64Subtract,setTempRet0=Module.setTempRet0=asm.setTempRet0,_i64Add=Module._i64Add=asm._i64Add,_emscripten_get_global_libc=Module._emscripten_get_global_libc=asm._emscripten_get_global_libc,__GLOBAL__sub_I_Yoga_cpp=Module.__GLOBAL__sub_I_Yoga_cpp=asm.__GLOBAL__sub_I_Yoga_cpp,__GLOBAL__sub_I_Binding_cc=Module.__GLOBAL__sub_I_Binding_cc=asm.__GLOBAL__sub_I_Binding_cc,stackSave=Module.stackSave=asm.stackSave,__GLOBAL__sub_I_nbind_cc=Module.__GLOBAL__sub_I_nbind_cc=asm.__GLOBAL__sub_I_nbind_cc,_free=Module._free=asm._free,runPostSets=Module.runPostSets=asm.runPostSets,establishStackSpace=Module.establishStackSpace=asm.establishStackSpace,_memmove=Module._memmove=asm._memmove,stackRestore=Module.stackRestore=asm.stackRestore,_malloc=Module._malloc=asm._malloc,__GLOBAL__sub_I_common_cc=Module.__GLOBAL__sub_I_common_cc=asm.__GLOBAL__sub_I_common_cc,dynCall_viiiii=Module.dynCall_viiiii=asm.dynCall_viiiii,dynCall_vif=Module.dynCall_vif=asm.dynCall_vif,dynCall_vid=Module.dynCall_vid=asm.dynCall_vid,dynCall_fiff=Module.dynCall_fiff=asm.dynCall_fiff,dynCall_vi=Module.dynCall_vi=asm.dynCall_vi,dynCall_vii=Module.dynCall_vii=asm.dynCall_vii,dynCall_ii=Module.dynCall_ii=asm.dynCall_ii,dynCall_viddi=Module.dynCall_viddi=asm.dynCall_viddi,dynCall_vidd=Module.dynCall_vidd=asm.dynCall_vidd,dynCall_iiii=Module.dynCall_iiii=asm.dynCall_iiii,dynCall_diii=Module.dynCall_diii=asm.dynCall_diii,dynCall_di=Module.dynCall_di=asm.dynCall_di,dynCall_iid=Module.dynCall_iid=asm.dynCall_iid,dynCall_iii=Module.dynCall_iii=asm.dynCall_iii,dynCall_viiddi=Module.dynCall_viiddi=asm.dynCall_viiddi,dynCall_viiiiii=Module.dynCall_viiiiii=asm.dynCall_viiiiii,dynCall_dii=Module.dynCall_dii=asm.dynCall_dii,dynCall_i=Module.dynCall_i=asm.dynCall_i,dynCall_iiiiii=Module.dynCall_iiiiii=asm.dynCall_iiiiii,dynCall_viiid=Module.dynCall_viiid=asm.dynCall_viiid,dynCall_viififi=Module.dynCall_viififi=asm.dynCall_viififi,dynCall_viii=Module.dynCall_viii=asm.dynCall_viii,dynCall_v=Module.dynCall_v=asm.dynCall_v,dynCall_viid=Module.dynCall_viid=asm.dynCall_viid,dynCall_idd=Module.dynCall_idd=asm.dynCall_idd,dynCall_viiii=Module.dynCall_viiii=asm.dynCall_viiii;Runtime.stackAlloc=Module.stackAlloc,Runtime.stackSave=Module.stackSave,Runtime.stackRestore=Module.stackRestore,Runtime.establishStackSpace=Module.establishStackSpace,Runtime.setTempRet0=Module.setTempRet0,Runtime.getTempRet0=Module.getTempRet0,Module.asm=asm;function ExitStatus(t){this.name="ExitStatus",this.message="Program terminated with exit("+t+")",this.status=t}ExitStatus.prototype=new Error,ExitStatus.prototype.constructor=ExitStatus;var initialStackTop,preloadStartTime=null,calledMain=!1;dependenciesFulfilled=function t(){Module.calledRun||run(),Module.calledRun||(dependenciesFulfilled=t)},Module.callMain=Module.callMain=function t(e){e=e||[],ensureInitRuntime();var r=e.length+1;function s(){for(var p=0;p<3;p++)a.push(0)}var a=[allocate(intArrayFromString(Module.thisProgram),"i8",ALLOC_NORMAL)];s();for(var n=0;n0||(preRun(),runDependencies>0)||Module.calledRun)return;function e(){Module.calledRun||(Module.calledRun=!0,!ABORT&&(ensureInitRuntime(),preMain(),Module.onRuntimeInitialized&&Module.onRuntimeInitialized(),Module._main&&shouldRunNow&&Module.callMain(t),postRun()))}Module.setStatus?(Module.setStatus("Running..."),setTimeout(function(){setTimeout(function(){Module.setStatus("")},1),e()},1)):e()}Module.run=Module.run=run;function exit(t,e){e&&Module.noExitRuntime||(Module.noExitRuntime||(ABORT=!0,EXITSTATUS=t,STACKTOP=initialStackTop,exitRuntime(),Module.onExit&&Module.onExit(t)),ENVIRONMENT_IS_NODE&&process.exit(t),Module.quit(t,new ExitStatus(t)))}Module.exit=Module.exit=exit;var abortDecorators=[];function abort(t){Module.onAbort&&Module.onAbort(t),t!==void 0?(Module.print(t),Module.printErr(t),t=JSON.stringify(t)):t="",ABORT=!0,EXITSTATUS=1;var e=` +If this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.`,r="abort("+t+") at "+stackTrace()+e;throw abortDecorators&&abortDecorators.forEach(function(s){r=s(r,t)}),r}if(Module.abort=Module.abort=abort,Module.preInit)for(typeof Module.preInit=="function"&&(Module.preInit=[Module.preInit]);Module.preInit.length>0;)Module.preInit.pop()();var shouldRunNow=!0;Module.noInitialRun&&(shouldRunNow=!1),run()})});var Fm=_((PKt,Rwe)=>{"use strict";var Ppt=Qwe(),xpt=Twe(),K9=!1,z9=null;xpt({},function(t,e){if(!K9){if(K9=!0,t)throw t;z9=e}});if(!K9)throw new Error("Failed to load the yoga module - it needed to be loaded synchronously, but didn't");Rwe.exports=Ppt(z9.bind,z9.lib)});var Z9=_((xKt,X9)=>{"use strict";var Fwe=t=>Number.isNaN(t)?!1:t>=4352&&(t<=4447||t===9001||t===9002||11904<=t&&t<=12871&&t!==12351||12880<=t&&t<=19903||19968<=t&&t<=42182||43360<=t&&t<=43388||44032<=t&&t<=55203||63744<=t&&t<=64255||65040<=t&&t<=65049||65072<=t&&t<=65131||65281<=t&&t<=65376||65504<=t&&t<=65510||110592<=t&&t<=110593||127488<=t&&t<=127569||131072<=t&&t<=262141);X9.exports=Fwe;X9.exports.default=Fwe});var Owe=_((kKt,Nwe)=>{"use strict";Nwe.exports=function(){return/\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62(?:\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67|\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74|\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73)\uDB40\uDC7F|\uD83D\uDC68(?:\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68\uD83C\uDFFB|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFE])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83D\uDC68|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D[\uDC66\uDC67])|[\u2695\u2696\u2708]\uFE0F|\uD83D[\uDC66\uDC67]|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|(?:\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708])\uFE0F|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C[\uDFFB-\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFB\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D\uD83D\uDC69)\uD83C\uDFFB|\uD83E\uDDD1(?:\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])|\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1)|(?:\uD83E\uDDD1\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFE])|(?:\uD83E\uDDD1\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D\uD83D\uDC69)(?:\uD83C[\uDFFB\uDFFC])|\uD83D\uDC69(?:\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFC-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|(?:\uD83E\uDDD1\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D\uD83D\uDC69)(?:\uD83C[\uDFFB-\uDFFD])|\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D\uDC41\uFE0F\u200D\uD83D\uDDE8|\uD83D\uDC69(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|(?:(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)\uFE0F|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF])\u200D[\u2640\u2642]|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD6-\uDDDD])(?:(?:\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|\u200D[\u2640\u2642])|\uD83C\uDFF4\u200D\u2620)\uFE0F|\uD83D\uDC69\u200D\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|\uD83C\uDFF3\uFE0F\u200D\uD83C\uDF08|\uD83D\uDC15\u200D\uD83E\uDDBA|\uD83D\uDC69\u200D\uD83D\uDC66|\uD83D\uDC69\u200D\uD83D\uDC67|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDF4\uD83C\uDDF2|\uD83C\uDDF6\uD83C\uDDE6|[#\*0-9]\uFE0F\u20E3|\uD83C\uDDE7(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF])|\uD83C\uDDF9(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF])|\uD83C\uDDEA(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA])|\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])|\uD83C\uDDF7(?:\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC])|\uD83D\uDC69(?:\uD83C[\uDFFB-\uDFFF])|\uD83C\uDDF2(?:\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF])|\uD83C\uDDE6(?:\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF])|\uD83C\uDDF0(?:\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF])|\uD83C\uDDED(?:\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA])|\uD83C\uDDE9(?:\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF])|\uD83C\uDDFE(?:\uD83C[\uDDEA\uDDF9])|\uD83C\uDDEC(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE])|\uD83C\uDDF8(?:\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF])|\uD83C\uDDEB(?:\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7])|\uD83C\uDDF5(?:\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE])|\uD83C\uDDFB(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA])|\uD83C\uDDF3(?:\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF])|\uD83C\uDDE8(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF])|\uD83C\uDDF1(?:\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE])|\uD83C\uDDFF(?:\uD83C[\uDDE6\uDDF2\uDDFC])|\uD83C\uDDFC(?:\uD83C[\uDDEB\uDDF8])|\uD83C\uDDFA(?:\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF])|\uD83C\uDDEE(?:\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9])|\uD83C\uDDEF(?:\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5])|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u261D\u270A-\u270D]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC70\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDCAA\uDD74\uDD7A\uDD90\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD36\uDDB5\uDDB6\uDDBB\uDDD2-\uDDD5])(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF93\uDFA0-\uDFCA\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF4\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDD7A\uDD95\uDD96\uDDA4\uDDFB-\uDE4F\uDE80-\uDEC5\uDECC\uDED0-\uDED2\uDED5\uDEEB\uDEEC\uDEF4-\uDEFA\uDFE0-\uDFEB]|\uD83E[\uDD0D-\uDD3A\uDD3C-\uDD45\uDD47-\uDD71\uDD73-\uDD76\uDD7A-\uDDA2\uDDA5-\uDDAA\uDDAE-\uDDCA\uDDCD-\uDDFF\uDE70-\uDE73\uDE78-\uDE7A\uDE80-\uDE82\uDE90-\uDE95])|(?:[#\*0-9\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692-\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD7A\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA4\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED2\uDED5\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3-\uDEFA\uDFE0-\uDFEB]|\uD83E[\uDD0D-\uDD3A\uDD3C-\uDD45\uDD47-\uDD71\uDD73-\uDD76\uDD7A-\uDDA2\uDDA5-\uDDAA\uDDAE-\uDDCA\uDDCD-\uDDFF\uDE70-\uDE73\uDE78-\uDE7A\uDE80-\uDE82\uDE90-\uDE95])\uFE0F|(?:[\u261D\u26F9\u270A-\u270D]|\uD83C[\uDF85\uDFC2-\uDFC4\uDFC7\uDFCA-\uDFCC]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66-\uDC78\uDC7C\uDC81-\uDC83\uDC85-\uDC87\uDC8F\uDC91\uDCAA\uDD74\uDD75\uDD7A\uDD90\uDD95\uDD96\uDE45-\uDE47\uDE4B-\uDE4F\uDEA3\uDEB4-\uDEB6\uDEC0\uDECC]|\uD83E[\uDD0F\uDD18-\uDD1F\uDD26\uDD30-\uDD39\uDD3C-\uDD3E\uDDB5\uDDB6\uDDB8\uDDB9\uDDBB\uDDCD-\uDDCF\uDDD1-\uDDDD])/g}});var GS=_((QKt,$9)=>{"use strict";var kpt=dk(),Qpt=Z9(),Tpt=Owe(),Lwe=t=>{if(typeof t!="string"||t.length===0||(t=kpt(t),t.length===0))return 0;t=t.replace(Tpt()," ");let e=0;for(let r=0;r=127&&s<=159||s>=768&&s<=879||(s>65535&&r++,e+=Qpt(s)?2:1)}return e};$9.exports=Lwe;$9.exports.default=Lwe});var tW=_((TKt,eW)=>{"use strict";var Rpt=GS(),Mwe=t=>{let e=0;for(let r of t.split(` +`))e=Math.max(e,Rpt(r));return e};eW.exports=Mwe;eW.exports.default=Mwe});var Uwe=_(qS=>{"use strict";var Fpt=qS&&qS.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(qS,"__esModule",{value:!0});var Npt=Fpt(tW()),rW={};qS.default=t=>{if(t.length===0)return{width:0,height:0};if(rW[t])return rW[t];let e=Npt.default(t),r=t.split(` +`).length;return rW[t]={width:e,height:r},{width:e,height:r}}});var _we=_(WS=>{"use strict";var Opt=WS&&WS.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(WS,"__esModule",{value:!0});var bn=Opt(Fm()),Lpt=(t,e)=>{"position"in e&&t.setPositionType(e.position==="absolute"?bn.default.POSITION_TYPE_ABSOLUTE:bn.default.POSITION_TYPE_RELATIVE)},Mpt=(t,e)=>{"marginLeft"in e&&t.setMargin(bn.default.EDGE_START,e.marginLeft||0),"marginRight"in e&&t.setMargin(bn.default.EDGE_END,e.marginRight||0),"marginTop"in e&&t.setMargin(bn.default.EDGE_TOP,e.marginTop||0),"marginBottom"in e&&t.setMargin(bn.default.EDGE_BOTTOM,e.marginBottom||0)},Upt=(t,e)=>{"paddingLeft"in e&&t.setPadding(bn.default.EDGE_LEFT,e.paddingLeft||0),"paddingRight"in e&&t.setPadding(bn.default.EDGE_RIGHT,e.paddingRight||0),"paddingTop"in e&&t.setPadding(bn.default.EDGE_TOP,e.paddingTop||0),"paddingBottom"in e&&t.setPadding(bn.default.EDGE_BOTTOM,e.paddingBottom||0)},_pt=(t,e)=>{var r;"flexGrow"in e&&t.setFlexGrow((r=e.flexGrow)!==null&&r!==void 0?r:0),"flexShrink"in e&&t.setFlexShrink(typeof e.flexShrink=="number"?e.flexShrink:1),"flexDirection"in e&&(e.flexDirection==="row"&&t.setFlexDirection(bn.default.FLEX_DIRECTION_ROW),e.flexDirection==="row-reverse"&&t.setFlexDirection(bn.default.FLEX_DIRECTION_ROW_REVERSE),e.flexDirection==="column"&&t.setFlexDirection(bn.default.FLEX_DIRECTION_COLUMN),e.flexDirection==="column-reverse"&&t.setFlexDirection(bn.default.FLEX_DIRECTION_COLUMN_REVERSE)),"flexBasis"in e&&(typeof e.flexBasis=="number"?t.setFlexBasis(e.flexBasis):typeof e.flexBasis=="string"?t.setFlexBasisPercent(Number.parseInt(e.flexBasis,10)):t.setFlexBasis(NaN)),"alignItems"in e&&((e.alignItems==="stretch"||!e.alignItems)&&t.setAlignItems(bn.default.ALIGN_STRETCH),e.alignItems==="flex-start"&&t.setAlignItems(bn.default.ALIGN_FLEX_START),e.alignItems==="center"&&t.setAlignItems(bn.default.ALIGN_CENTER),e.alignItems==="flex-end"&&t.setAlignItems(bn.default.ALIGN_FLEX_END)),"alignSelf"in e&&((e.alignSelf==="auto"||!e.alignSelf)&&t.setAlignSelf(bn.default.ALIGN_AUTO),e.alignSelf==="flex-start"&&t.setAlignSelf(bn.default.ALIGN_FLEX_START),e.alignSelf==="center"&&t.setAlignSelf(bn.default.ALIGN_CENTER),e.alignSelf==="flex-end"&&t.setAlignSelf(bn.default.ALIGN_FLEX_END)),"justifyContent"in e&&((e.justifyContent==="flex-start"||!e.justifyContent)&&t.setJustifyContent(bn.default.JUSTIFY_FLEX_START),e.justifyContent==="center"&&t.setJustifyContent(bn.default.JUSTIFY_CENTER),e.justifyContent==="flex-end"&&t.setJustifyContent(bn.default.JUSTIFY_FLEX_END),e.justifyContent==="space-between"&&t.setJustifyContent(bn.default.JUSTIFY_SPACE_BETWEEN),e.justifyContent==="space-around"&&t.setJustifyContent(bn.default.JUSTIFY_SPACE_AROUND))},Hpt=(t,e)=>{var r,s;"width"in e&&(typeof e.width=="number"?t.setWidth(e.width):typeof e.width=="string"?t.setWidthPercent(Number.parseInt(e.width,10)):t.setWidthAuto()),"height"in e&&(typeof e.height=="number"?t.setHeight(e.height):typeof e.height=="string"?t.setHeightPercent(Number.parseInt(e.height,10)):t.setHeightAuto()),"minWidth"in e&&(typeof e.minWidth=="string"?t.setMinWidthPercent(Number.parseInt(e.minWidth,10)):t.setMinWidth((r=e.minWidth)!==null&&r!==void 0?r:0)),"minHeight"in e&&(typeof e.minHeight=="string"?t.setMinHeightPercent(Number.parseInt(e.minHeight,10)):t.setMinHeight((s=e.minHeight)!==null&&s!==void 0?s:0))},jpt=(t,e)=>{"display"in e&&t.setDisplay(e.display==="flex"?bn.default.DISPLAY_FLEX:bn.default.DISPLAY_NONE)},Gpt=(t,e)=>{if("borderStyle"in e){let r=typeof e.borderStyle=="string"?1:0;t.setBorder(bn.default.EDGE_TOP,r),t.setBorder(bn.default.EDGE_BOTTOM,r),t.setBorder(bn.default.EDGE_LEFT,r),t.setBorder(bn.default.EDGE_RIGHT,r)}};WS.default=(t,e={})=>{Lpt(t,e),Mpt(t,e),Upt(t,e),_pt(t,e),Hpt(t,e),jpt(t,e),Gpt(t,e)}});var Gwe=_((NKt,jwe)=>{"use strict";var YS=GS(),qpt=dk(),Wpt=sk(),iW=new Set(["\x1B","\x9B"]),Ypt=39,Hwe=t=>`${iW.values().next().value}[${t}m`,Vpt=t=>t.split(" ").map(e=>YS(e)),nW=(t,e,r)=>{let s=[...e],a=!1,n=YS(qpt(t[t.length-1]));for(let[c,f]of s.entries()){let p=YS(f);if(n+p<=r?t[t.length-1]+=f:(t.push(f),n=0),iW.has(f))a=!0;else if(a&&f==="m"){a=!1;continue}a||(n+=p,n===r&&c0&&t.length>1&&(t[t.length-2]+=t.pop())},Jpt=t=>{let e=t.split(" "),r=e.length;for(;r>0&&!(YS(e[r-1])>0);)r--;return r===e.length?t:e.slice(0,r).join(" ")+e.slice(r).join("")},Kpt=(t,e,r={})=>{if(r.trim!==!1&&t.trim()==="")return"";let s="",a="",n,c=Vpt(t),f=[""];for(let[p,h]of t.split(" ").entries()){r.trim!==!1&&(f[f.length-1]=f[f.length-1].trimLeft());let E=YS(f[f.length-1]);if(p!==0&&(E>=e&&(r.wordWrap===!1||r.trim===!1)&&(f.push(""),E=0),(E>0||r.trim===!1)&&(f[f.length-1]+=" ",E++)),r.hard&&c[p]>e){let C=e-E,S=1+Math.floor((c[p]-C-1)/e);Math.floor((c[p]-1)/e)e&&E>0&&c[p]>0){if(r.wordWrap===!1&&Ee&&r.wordWrap===!1){nW(f,h,e);continue}f[f.length-1]+=h}r.trim!==!1&&(f=f.map(Jpt)),s=f.join(` +`);for(let[p,h]of[...s].entries()){if(a+=h,iW.has(h)){let C=parseFloat(/\d[^m]*/.exec(s.slice(p,p+4)));n=C===Ypt?null:C}let E=Wpt.codes.get(Number(n));n&&E&&(s[p+1]===` +`?a+=Hwe(E):h===` +`&&(a+=Hwe(n)))}return a};jwe.exports=(t,e,r)=>String(t).normalize().replace(/\r\n/g,` +`).split(` +`).map(s=>Kpt(s,e,r)).join(` +`)});var Ywe=_((OKt,Wwe)=>{"use strict";var qwe="[\uD800-\uDBFF][\uDC00-\uDFFF]",zpt=t=>t&&t.exact?new RegExp(`^${qwe}$`):new RegExp(qwe,"g");Wwe.exports=zpt});var sW=_((LKt,zwe)=>{"use strict";var Xpt=Z9(),Zpt=Ywe(),Vwe=sk(),Kwe=["\x1B","\x9B"],NF=t=>`${Kwe[0]}[${t}m`,Jwe=(t,e,r)=>{let s=[];t=[...t];for(let a of t){let n=a;a.match(";")&&(a=a.split(";")[0][0]+"0");let c=Vwe.codes.get(parseInt(a,10));if(c){let f=t.indexOf(c.toString());f>=0?t.splice(f,1):s.push(NF(e?c:n))}else if(e){s.push(NF(0));break}else s.push(NF(n))}if(e&&(s=s.filter((a,n)=>s.indexOf(a)===n),r!==void 0)){let a=NF(Vwe.codes.get(parseInt(r,10)));s=s.reduce((n,c)=>c===a?[c,...n]:[...n,c],[])}return s.join("")};zwe.exports=(t,e,r)=>{let s=[...t.normalize()],a=[];r=typeof r=="number"?r:s.length;let n=!1,c,f=0,p="";for(let[h,E]of s.entries()){let C=!1;if(Kwe.includes(E)){let S=/\d[^m]*/.exec(t.slice(h,h+18));c=S&&S.length>0?S[0]:void 0,fe&&f<=r)p+=E;else if(f===e&&!n&&c!==void 0)p=Jwe(a);else if(f>=r){p+=Jwe(a,!0,c);break}}return p}});var Zwe=_((MKt,Xwe)=>{"use strict";var $0=sW(),$pt=GS();function OF(t,e,r){if(t.charAt(e)===" ")return e;for(let s=1;s<=3;s++)if(r){if(t.charAt(e+s)===" ")return e+s}else if(t.charAt(e-s)===" ")return e-s;return e}Xwe.exports=(t,e,r)=>{r={position:"end",preferTruncationOnSpace:!1,...r};let{position:s,space:a,preferTruncationOnSpace:n}=r,c="\u2026",f=1;if(typeof t!="string")throw new TypeError(`Expected \`input\` to be a string, got ${typeof t}`);if(typeof e!="number")throw new TypeError(`Expected \`columns\` to be a number, got ${typeof e}`);if(e<1)return"";if(e===1)return c;let p=$pt(t);if(p<=e)return t;if(s==="start"){if(n){let h=OF(t,p-e+1,!0);return c+$0(t,h,p).trim()}return a===!0&&(c+=" ",f=2),c+$0(t,p-e+f,p)}if(s==="middle"){a===!0&&(c=" "+c+" ",f=3);let h=Math.floor(e/2);if(n){let E=OF(t,h),C=OF(t,p-(e-h)+1,!0);return $0(t,0,E)+c+$0(t,C,p).trim()}return $0(t,0,h)+c+$0(t,p-(e-h)+f,p)}if(s==="end"){if(n){let h=OF(t,e-1);return $0(t,0,h)+c}return a===!0&&(c=" "+c,f=2),$0(t,0,e-f)+c}throw new Error(`Expected \`options.position\` to be either \`start\`, \`middle\` or \`end\`, got ${s}`)}});var aW=_(VS=>{"use strict";var $we=VS&&VS.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(VS,"__esModule",{value:!0});var eht=$we(Gwe()),tht=$we(Zwe()),oW={};VS.default=(t,e,r)=>{let s=t+String(e)+String(r);if(oW[s])return oW[s];let a=t;if(r==="wrap"&&(a=eht.default(t,e,{trim:!1,hard:!0})),r.startsWith("truncate")){let n="end";r==="truncate-middle"&&(n="middle"),r==="truncate-start"&&(n="start"),a=tht.default(t,e,{position:n})}return oW[s]=a,a}});var cW=_(lW=>{"use strict";Object.defineProperty(lW,"__esModule",{value:!0});var e1e=t=>{let e="";if(t.childNodes.length>0)for(let r of t.childNodes){let s="";r.nodeName==="#text"?s=r.nodeValue:((r.nodeName==="ink-text"||r.nodeName==="ink-virtual-text")&&(s=e1e(r)),s.length>0&&typeof r.internal_transform=="function"&&(s=r.internal_transform(s))),e+=s}return e};lW.default=e1e});var uW=_(bi=>{"use strict";var JS=bi&&bi.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(bi,"__esModule",{value:!0});bi.setTextNodeValue=bi.createTextNode=bi.setStyle=bi.setAttribute=bi.removeChildNode=bi.insertBeforeNode=bi.appendChildNode=bi.createNode=bi.TEXT_NAME=void 0;var rht=JS(Fm()),t1e=JS(Uwe()),nht=JS(_we()),iht=JS(aW()),sht=JS(cW());bi.TEXT_NAME="#text";bi.createNode=t=>{var e;let r={nodeName:t,style:{},attributes:{},childNodes:[],parentNode:null,yogaNode:t==="ink-virtual-text"?void 0:rht.default.Node.create()};return t==="ink-text"&&((e=r.yogaNode)===null||e===void 0||e.setMeasureFunc(oht.bind(null,r))),r};bi.appendChildNode=(t,e)=>{var r;e.parentNode&&bi.removeChildNode(e.parentNode,e),e.parentNode=t,t.childNodes.push(e),e.yogaNode&&((r=t.yogaNode)===null||r===void 0||r.insertChild(e.yogaNode,t.yogaNode.getChildCount())),(t.nodeName==="ink-text"||t.nodeName==="ink-virtual-text")&&LF(t)};bi.insertBeforeNode=(t,e,r)=>{var s,a;e.parentNode&&bi.removeChildNode(e.parentNode,e),e.parentNode=t;let n=t.childNodes.indexOf(r);if(n>=0){t.childNodes.splice(n,0,e),e.yogaNode&&((s=t.yogaNode)===null||s===void 0||s.insertChild(e.yogaNode,n));return}t.childNodes.push(e),e.yogaNode&&((a=t.yogaNode)===null||a===void 0||a.insertChild(e.yogaNode,t.yogaNode.getChildCount())),(t.nodeName==="ink-text"||t.nodeName==="ink-virtual-text")&&LF(t)};bi.removeChildNode=(t,e)=>{var r,s;e.yogaNode&&((s=(r=e.parentNode)===null||r===void 0?void 0:r.yogaNode)===null||s===void 0||s.removeChild(e.yogaNode)),e.parentNode=null;let a=t.childNodes.indexOf(e);a>=0&&t.childNodes.splice(a,1),(t.nodeName==="ink-text"||t.nodeName==="ink-virtual-text")&&LF(t)};bi.setAttribute=(t,e,r)=>{t.attributes[e]=r};bi.setStyle=(t,e)=>{t.style=e,t.yogaNode&&nht.default(t.yogaNode,e)};bi.createTextNode=t=>{let e={nodeName:"#text",nodeValue:t,yogaNode:void 0,parentNode:null,style:{}};return bi.setTextNodeValue(e,t),e};var oht=function(t,e){var r,s;let a=t.nodeName==="#text"?t.nodeValue:sht.default(t),n=t1e.default(a);if(n.width<=e||n.width>=1&&e>0&&e<1)return n;let c=(s=(r=t.style)===null||r===void 0?void 0:r.textWrap)!==null&&s!==void 0?s:"wrap",f=iht.default(a,e,c);return t1e.default(f)},r1e=t=>{var e;if(!(!t||!t.parentNode))return(e=t.yogaNode)!==null&&e!==void 0?e:r1e(t.parentNode)},LF=t=>{let e=r1e(t);e?.markDirty()};bi.setTextNodeValue=(t,e)=>{typeof e!="string"&&(e=String(e)),t.nodeValue=e,LF(t)}});var a1e=_(KS=>{"use strict";var o1e=KS&&KS.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(KS,"__esModule",{value:!0});var n1e=Y9(),aht=o1e(Swe()),i1e=o1e(Fm()),ea=uW(),s1e=t=>{t?.unsetMeasureFunc(),t?.freeRecursive()};KS.default=aht.default({schedulePassiveEffects:n1e.unstable_scheduleCallback,cancelPassiveEffects:n1e.unstable_cancelCallback,now:Date.now,getRootHostContext:()=>({isInsideText:!1}),prepareForCommit:()=>null,preparePortalMount:()=>null,clearContainer:()=>!1,shouldDeprioritizeSubtree:()=>!1,resetAfterCommit:t=>{if(t.isStaticDirty){t.isStaticDirty=!1,typeof t.onImmediateRender=="function"&&t.onImmediateRender();return}typeof t.onRender=="function"&&t.onRender()},getChildHostContext:(t,e)=>{let r=t.isInsideText,s=e==="ink-text"||e==="ink-virtual-text";return r===s?t:{isInsideText:s}},shouldSetTextContent:()=>!1,createInstance:(t,e,r,s)=>{if(s.isInsideText&&t==="ink-box")throw new Error(" can\u2019t be nested inside component");let a=t==="ink-text"&&s.isInsideText?"ink-virtual-text":t,n=ea.createNode(a);for(let[c,f]of Object.entries(e))c!=="children"&&(c==="style"?ea.setStyle(n,f):c==="internal_transform"?n.internal_transform=f:c==="internal_static"?n.internal_static=!0:ea.setAttribute(n,c,f));return n},createTextInstance:(t,e,r)=>{if(!r.isInsideText)throw new Error(`Text string "${t}" must be rendered inside component`);return ea.createTextNode(t)},resetTextContent:()=>{},hideTextInstance:t=>{ea.setTextNodeValue(t,"")},unhideTextInstance:(t,e)=>{ea.setTextNodeValue(t,e)},getPublicInstance:t=>t,hideInstance:t=>{var e;(e=t.yogaNode)===null||e===void 0||e.setDisplay(i1e.default.DISPLAY_NONE)},unhideInstance:t=>{var e;(e=t.yogaNode)===null||e===void 0||e.setDisplay(i1e.default.DISPLAY_FLEX)},appendInitialChild:ea.appendChildNode,appendChild:ea.appendChildNode,insertBefore:ea.insertBeforeNode,finalizeInitialChildren:(t,e,r,s)=>(t.internal_static&&(s.isStaticDirty=!0,s.staticNode=t),!1),supportsMutation:!0,appendChildToContainer:ea.appendChildNode,insertInContainerBefore:ea.insertBeforeNode,removeChildFromContainer:(t,e)=>{ea.removeChildNode(t,e),s1e(e.yogaNode)},prepareUpdate:(t,e,r,s,a)=>{t.internal_static&&(a.isStaticDirty=!0);let n={},c=Object.keys(s);for(let f of c)if(s[f]!==r[f]){if(f==="style"&&typeof s.style=="object"&&typeof r.style=="object"){let h=s.style,E=r.style,C=Object.keys(h);for(let S of C){if(S==="borderStyle"||S==="borderColor"){if(typeof n.style!="object"){let P={};n.style=P}n.style.borderStyle=h.borderStyle,n.style.borderColor=h.borderColor}if(h[S]!==E[S]){if(typeof n.style!="object"){let P={};n.style=P}n.style[S]=h[S]}}continue}n[f]=s[f]}return n},commitUpdate:(t,e)=>{for(let[r,s]of Object.entries(e))r!=="children"&&(r==="style"?ea.setStyle(t,s):r==="internal_transform"?t.internal_transform=s:r==="internal_static"?t.internal_static=!0:ea.setAttribute(t,r,s))},commitTextUpdate:(t,e,r)=>{ea.setTextNodeValue(t,r)},removeChild:(t,e)=>{ea.removeChildNode(t,e),s1e(e.yogaNode)}})});var c1e=_((GKt,l1e)=>{"use strict";l1e.exports=(t,e=1,r)=>{if(r={indent:" ",includeEmptyLines:!1,...r},typeof t!="string")throw new TypeError(`Expected \`input\` to be a \`string\`, got \`${typeof t}\``);if(typeof e!="number")throw new TypeError(`Expected \`count\` to be a \`number\`, got \`${typeof e}\``);if(typeof r.indent!="string")throw new TypeError(`Expected \`options.indent\` to be a \`string\`, got \`${typeof r.indent}\``);if(e===0)return t;let s=r.includeEmptyLines?/^/gm:/^(?!\s*$)/gm;return t.replace(s,r.indent.repeat(e))}});var u1e=_(zS=>{"use strict";var lht=zS&&zS.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(zS,"__esModule",{value:!0});var MF=lht(Fm());zS.default=t=>t.getComputedWidth()-t.getComputedPadding(MF.default.EDGE_LEFT)-t.getComputedPadding(MF.default.EDGE_RIGHT)-t.getComputedBorder(MF.default.EDGE_LEFT)-t.getComputedBorder(MF.default.EDGE_RIGHT)});var f1e=_((WKt,cht)=>{cht.exports={single:{topLeft:"\u250C",topRight:"\u2510",bottomRight:"\u2518",bottomLeft:"\u2514",vertical:"\u2502",horizontal:"\u2500"},double:{topLeft:"\u2554",topRight:"\u2557",bottomRight:"\u255D",bottomLeft:"\u255A",vertical:"\u2551",horizontal:"\u2550"},round:{topLeft:"\u256D",topRight:"\u256E",bottomRight:"\u256F",bottomLeft:"\u2570",vertical:"\u2502",horizontal:"\u2500"},bold:{topLeft:"\u250F",topRight:"\u2513",bottomRight:"\u251B",bottomLeft:"\u2517",vertical:"\u2503",horizontal:"\u2501"},singleDouble:{topLeft:"\u2553",topRight:"\u2556",bottomRight:"\u255C",bottomLeft:"\u2559",vertical:"\u2551",horizontal:"\u2500"},doubleSingle:{topLeft:"\u2552",topRight:"\u2555",bottomRight:"\u255B",bottomLeft:"\u2558",vertical:"\u2502",horizontal:"\u2550"},classic:{topLeft:"+",topRight:"+",bottomRight:"+",bottomLeft:"+",vertical:"|",horizontal:"-"}}});var p1e=_((YKt,fW)=>{"use strict";var A1e=f1e();fW.exports=A1e;fW.exports.default=A1e});var AW=_(ZS=>{"use strict";var uht=ZS&&ZS.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(ZS,"__esModule",{value:!0});var XS=uht(TE()),fht=/^(rgb|hsl|hsv|hwb)\(\s?(\d+),\s?(\d+),\s?(\d+)\s?\)$/,Aht=/^(ansi|ansi256)\(\s?(\d+)\s?\)$/,UF=(t,e)=>e==="foreground"?t:"bg"+t[0].toUpperCase()+t.slice(1);ZS.default=(t,e,r)=>{if(!e)return t;if(e in XS.default){let a=UF(e,r);return XS.default[a](t)}if(e.startsWith("#")){let a=UF("hex",r);return XS.default[a](e)(t)}if(e.startsWith("ansi")){let a=Aht.exec(e);if(!a)return t;let n=UF(a[1],r),c=Number(a[2]);return XS.default[n](c)(t)}if(e.startsWith("rgb")||e.startsWith("hsl")||e.startsWith("hsv")||e.startsWith("hwb")){let a=fht.exec(e);if(!a)return t;let n=UF(a[1],r),c=Number(a[2]),f=Number(a[3]),p=Number(a[4]);return XS.default[n](c,f,p)(t)}return t}});var g1e=_($S=>{"use strict";var h1e=$S&&$S.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty($S,"__esModule",{value:!0});var pht=h1e(p1e()),pW=h1e(AW());$S.default=(t,e,r,s)=>{if(typeof r.style.borderStyle=="string"){let a=r.yogaNode.getComputedWidth(),n=r.yogaNode.getComputedHeight(),c=r.style.borderColor,f=pht.default[r.style.borderStyle],p=pW.default(f.topLeft+f.horizontal.repeat(a-2)+f.topRight,c,"foreground"),h=(pW.default(f.vertical,c,"foreground")+` +`).repeat(n-2),E=pW.default(f.bottomLeft+f.horizontal.repeat(a-2)+f.bottomRight,c,"foreground");s.write(t,e,p,{transformers:[]}),s.write(t,e+1,h,{transformers:[]}),s.write(t+a-1,e+1,h,{transformers:[]}),s.write(t,e+n-1,E,{transformers:[]})}}});var m1e=_(eD=>{"use strict";var Nm=eD&&eD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(eD,"__esModule",{value:!0});var hht=Nm(Fm()),ght=Nm(tW()),dht=Nm(c1e()),mht=Nm(aW()),yht=Nm(u1e()),Eht=Nm(cW()),Iht=Nm(g1e()),Cht=(t,e)=>{var r;let s=(r=t.childNodes[0])===null||r===void 0?void 0:r.yogaNode;if(s){let a=s.getComputedLeft(),n=s.getComputedTop();e=` +`.repeat(n)+dht.default(e,a)}return e},d1e=(t,e,r)=>{var s;let{offsetX:a=0,offsetY:n=0,transformers:c=[],skipStaticElements:f}=r;if(f&&t.internal_static)return;let{yogaNode:p}=t;if(p){if(p.getDisplay()===hht.default.DISPLAY_NONE)return;let h=a+p.getComputedLeft(),E=n+p.getComputedTop(),C=c;if(typeof t.internal_transform=="function"&&(C=[t.internal_transform,...c]),t.nodeName==="ink-text"){let S=Eht.default(t);if(S.length>0){let P=ght.default(S),I=yht.default(p);if(P>I){let R=(s=t.style.textWrap)!==null&&s!==void 0?s:"wrap";S=mht.default(S,I,R)}S=Cht(t,S),e.write(h,E,S,{transformers:C})}return}if(t.nodeName==="ink-box"&&Iht.default(h,E,t,e),t.nodeName==="ink-root"||t.nodeName==="ink-box")for(let S of t.childNodes)d1e(S,e,{offsetX:h,offsetY:E,transformers:C,skipStaticElements:f})}};eD.default=d1e});var I1e=_(tD=>{"use strict";var E1e=tD&&tD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(tD,"__esModule",{value:!0});var y1e=E1e(sW()),wht=E1e(GS()),hW=class{constructor(e){this.writes=[];let{width:r,height:s}=e;this.width=r,this.height=s}write(e,r,s,a){let{transformers:n}=a;s&&this.writes.push({x:e,y:r,text:s,transformers:n})}get(){let e=[];for(let s=0;ss.trimRight()).join(` +`),height:e.length}}};tD.default=hW});var B1e=_(rD=>{"use strict";var gW=rD&&rD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(rD,"__esModule",{value:!0});var Bht=gW(Fm()),C1e=gW(m1e()),w1e=gW(I1e());rD.default=(t,e)=>{var r;if(t.yogaNode.setWidth(e),t.yogaNode){t.yogaNode.calculateLayout(void 0,void 0,Bht.default.DIRECTION_LTR);let s=new w1e.default({width:t.yogaNode.getComputedWidth(),height:t.yogaNode.getComputedHeight()});C1e.default(t,s,{skipStaticElements:!0});let a;!((r=t.staticNode)===null||r===void 0)&&r.yogaNode&&(a=new w1e.default({width:t.staticNode.yogaNode.getComputedWidth(),height:t.staticNode.yogaNode.getComputedHeight()}),C1e.default(t.staticNode,a,{skipStaticElements:!1}));let{output:n,height:c}=s.get();return{output:n,outputHeight:c,staticOutput:a?`${a.get().output} +`:""}}return{output:"",outputHeight:0,staticOutput:""}}});var b1e=_((ZKt,D1e)=>{"use strict";var v1e=Ie("stream"),S1e=["assert","count","countReset","debug","dir","dirxml","error","group","groupCollapsed","groupEnd","info","log","table","time","timeEnd","timeLog","trace","warn"],dW={},vht=t=>{let e=new v1e.PassThrough,r=new v1e.PassThrough;e.write=a=>t("stdout",a),r.write=a=>t("stderr",a);let s=new console.Console(e,r);for(let a of S1e)dW[a]=console[a],console[a]=s[a];return()=>{for(let a of S1e)console[a]=dW[a];dW={}}};D1e.exports=vht});var yW=_(mW=>{"use strict";Object.defineProperty(mW,"__esModule",{value:!0});mW.default=new WeakMap});var IW=_(EW=>{"use strict";Object.defineProperty(EW,"__esModule",{value:!0});var Sht=hn(),P1e=Sht.createContext({exit:()=>{}});P1e.displayName="InternalAppContext";EW.default=P1e});var wW=_(CW=>{"use strict";Object.defineProperty(CW,"__esModule",{value:!0});var Dht=hn(),x1e=Dht.createContext({stdin:void 0,setRawMode:()=>{},isRawModeSupported:!1,internal_exitOnCtrlC:!0});x1e.displayName="InternalStdinContext";CW.default=x1e});var vW=_(BW=>{"use strict";Object.defineProperty(BW,"__esModule",{value:!0});var bht=hn(),k1e=bht.createContext({stdout:void 0,write:()=>{}});k1e.displayName="InternalStdoutContext";BW.default=k1e});var DW=_(SW=>{"use strict";Object.defineProperty(SW,"__esModule",{value:!0});var Pht=hn(),Q1e=Pht.createContext({stderr:void 0,write:()=>{}});Q1e.displayName="InternalStderrContext";SW.default=Q1e});var _F=_(bW=>{"use strict";Object.defineProperty(bW,"__esModule",{value:!0});var xht=hn(),T1e=xht.createContext({activeId:void 0,add:()=>{},remove:()=>{},activate:()=>{},deactivate:()=>{},enableFocus:()=>{},disableFocus:()=>{},focusNext:()=>{},focusPrevious:()=>{},focus:()=>{}});T1e.displayName="InternalFocusContext";bW.default=T1e});var F1e=_((szt,R1e)=>{"use strict";var kht=/[|\\{}()[\]^$+*?.-]/g;R1e.exports=t=>{if(typeof t!="string")throw new TypeError("Expected a string");return t.replace(kht,"\\$&")}});var M1e=_((ozt,L1e)=>{"use strict";var Qht=F1e(),Tht=typeof process=="object"&&process&&typeof process.cwd=="function"?process.cwd():".",O1e=[].concat(Ie("module").builtinModules,"bootstrap_node","node").map(t=>new RegExp(`(?:\\((?:node:)?${t}(?:\\.js)?:\\d+:\\d+\\)$|^\\s*at (?:node:)?${t}(?:\\.js)?:\\d+:\\d+$)`));O1e.push(/\((?:node:)?internal\/[^:]+:\d+:\d+\)$/,/\s*at (?:node:)?internal\/[^:]+:\d+:\d+$/,/\/\.node-spawn-wrap-\w+-\w+\/node:\d+:\d+\)?$/);var PW=class t{constructor(e){e={ignoredPackages:[],...e},"internals"in e||(e.internals=t.nodeInternals()),"cwd"in e||(e.cwd=Tht),this._cwd=e.cwd.replace(/\\/g,"/"),this._internals=[].concat(e.internals,Rht(e.ignoredPackages)),this._wrapCallSite=e.wrapCallSite||!1}static nodeInternals(){return[...O1e]}clean(e,r=0){r=" ".repeat(r),Array.isArray(e)||(e=e.split(` +`)),!/^\s*at /.test(e[0])&&/^\s*at /.test(e[1])&&(e=e.slice(1));let s=!1,a=null,n=[];return e.forEach(c=>{if(c=c.replace(/\\/g,"/"),this._internals.some(p=>p.test(c)))return;let f=/^\s*at /.test(c);s?c=c.trimEnd().replace(/^(\s+)at /,"$1"):(c=c.trim(),f&&(c=c.slice(3))),c=c.replace(`${this._cwd}/`,""),c&&(f?(a&&(n.push(a),a=null),n.push(c)):(s=!0,a=c))}),n.map(c=>`${r}${c} +`).join("")}captureString(e,r=this.captureString){typeof e=="function"&&(r=e,e=1/0);let{stackTraceLimit:s}=Error;e&&(Error.stackTraceLimit=e);let a={};Error.captureStackTrace(a,r);let{stack:n}=a;return Error.stackTraceLimit=s,this.clean(n)}capture(e,r=this.capture){typeof e=="function"&&(r=e,e=1/0);let{prepareStackTrace:s,stackTraceLimit:a}=Error;Error.prepareStackTrace=(f,p)=>this._wrapCallSite?p.map(this._wrapCallSite):p,e&&(Error.stackTraceLimit=e);let n={};Error.captureStackTrace(n,r);let{stack:c}=n;return Object.assign(Error,{prepareStackTrace:s,stackTraceLimit:a}),c}at(e=this.at){let[r]=this.capture(1,e);if(!r)return{};let s={line:r.getLineNumber(),column:r.getColumnNumber()};N1e(s,r.getFileName(),this._cwd),r.isConstructor()&&(s.constructor=!0),r.isEval()&&(s.evalOrigin=r.getEvalOrigin()),r.isNative()&&(s.native=!0);let a;try{a=r.getTypeName()}catch{}a&&a!=="Object"&&a!=="[object Object]"&&(s.type=a);let n=r.getFunctionName();n&&(s.function=n);let c=r.getMethodName();return c&&n!==c&&(s.method=c),s}parseLine(e){let r=e&&e.match(Fht);if(!r)return null;let s=r[1]==="new",a=r[2],n=r[3],c=r[4],f=Number(r[5]),p=Number(r[6]),h=r[7],E=r[8],C=r[9],S=r[10]==="native",P=r[11]===")",I,R={};if(E&&(R.line=Number(E)),C&&(R.column=Number(C)),P&&h){let N=0;for(let U=h.length-1;U>0;U--)if(h.charAt(U)===")")N++;else if(h.charAt(U)==="("&&h.charAt(U-1)===" "&&(N--,N===-1&&h.charAt(U-1)===" ")){let W=h.slice(0,U-1);h=h.slice(U+1),a+=` (${W}`;break}}if(a){let N=a.match(Nht);N&&(a=N[1],I=N[2])}return N1e(R,h,this._cwd),s&&(R.constructor=!0),n&&(R.evalOrigin=n,R.evalLine=f,R.evalColumn=p,R.evalFile=c&&c.replace(/\\/g,"/")),S&&(R.native=!0),a&&(R.function=a),I&&a!==I&&(R.method=I),R}};function N1e(t,e,r){e&&(e=e.replace(/\\/g,"/"),e.startsWith(`${r}/`)&&(e=e.slice(r.length+1)),t.file=e)}function Rht(t){if(t.length===0)return[];let e=t.map(r=>Qht(r));return new RegExp(`[/\\\\]node_modules[/\\\\](?:${e.join("|")})[/\\\\][^:]+:\\d+:\\d+`)}var Fht=new RegExp("^(?:\\s*at )?(?:(new) )?(?:(.*?) \\()?(?:eval at ([^ ]+) \\((.+?):(\\d+):(\\d+)\\), )?(?:(.+?):(\\d+):(\\d+)|(native))(\\)?)$"),Nht=/^(.*?) \[as (.*?)\]$/;L1e.exports=PW});var _1e=_((azt,U1e)=>{"use strict";U1e.exports=(t,e)=>t.replace(/^\t+/gm,r=>" ".repeat(r.length*(e||2)))});var j1e=_((lzt,H1e)=>{"use strict";var Oht=_1e(),Lht=(t,e)=>{let r=[],s=t-e,a=t+e;for(let n=s;n<=a;n++)r.push(n);return r};H1e.exports=(t,e,r)=>{if(typeof t!="string")throw new TypeError("Source code is missing.");if(!e||e<1)throw new TypeError("Line number must start from `1`.");if(t=Oht(t).split(/\r?\n/),!(e>t.length))return r={around:3,...r},Lht(e,r.around).filter(s=>t[s-1]!==void 0).map(s=>({line:s,value:t[s-1]}))}});var HF=_(rf=>{"use strict";var Mht=rf&&rf.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r),Object.defineProperty(t,s,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),Uht=rf&&rf.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),_ht=rf&&rf.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!=="default"&&Object.hasOwnProperty.call(t,r)&&Mht(e,t,r);return Uht(e,t),e},Hht=rf&&rf.__rest||function(t,e){var r={};for(var s in t)Object.prototype.hasOwnProperty.call(t,s)&&e.indexOf(s)<0&&(r[s]=t[s]);if(t!=null&&typeof Object.getOwnPropertySymbols=="function")for(var a=0,s=Object.getOwnPropertySymbols(t);a{var{children:r}=t,s=Hht(t,["children"]);let a=Object.assign(Object.assign({},s),{marginLeft:s.marginLeft||s.marginX||s.margin||0,marginRight:s.marginRight||s.marginX||s.margin||0,marginTop:s.marginTop||s.marginY||s.margin||0,marginBottom:s.marginBottom||s.marginY||s.margin||0,paddingLeft:s.paddingLeft||s.paddingX||s.padding||0,paddingRight:s.paddingRight||s.paddingX||s.padding||0,paddingTop:s.paddingTop||s.paddingY||s.padding||0,paddingBottom:s.paddingBottom||s.paddingY||s.padding||0});return G1e.default.createElement("ink-box",{ref:e,style:a},r)});xW.displayName="Box";xW.defaultProps={flexDirection:"row",flexGrow:0,flexShrink:1};rf.default=xW});var TW=_(nD=>{"use strict";var kW=nD&&nD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(nD,"__esModule",{value:!0});var jht=kW(hn()),yw=kW(TE()),q1e=kW(AW()),QW=({color:t,backgroundColor:e,dimColor:r,bold:s,italic:a,underline:n,strikethrough:c,inverse:f,wrap:p,children:h})=>{if(h==null)return null;let E=C=>(r&&(C=yw.default.dim(C)),t&&(C=q1e.default(C,t,"foreground")),e&&(C=q1e.default(C,e,"background")),s&&(C=yw.default.bold(C)),a&&(C=yw.default.italic(C)),n&&(C=yw.default.underline(C)),c&&(C=yw.default.strikethrough(C)),f&&(C=yw.default.inverse(C)),C);return jht.default.createElement("ink-text",{style:{flexGrow:0,flexShrink:1,flexDirection:"row",textWrap:p},internal_transform:E},h)};QW.displayName="Text";QW.defaultProps={dimColor:!1,bold:!1,italic:!1,underline:!1,strikethrough:!1,wrap:"wrap"};nD.default=QW});var J1e=_(nf=>{"use strict";var Ght=nf&&nf.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r),Object.defineProperty(t,s,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),qht=nf&&nf.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),Wht=nf&&nf.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!=="default"&&Object.hasOwnProperty.call(t,r)&&Ght(e,t,r);return qht(e,t),e},iD=nf&&nf.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(nf,"__esModule",{value:!0});var W1e=Wht(Ie("fs")),Qs=iD(hn()),Y1e=iD(M1e()),Yht=iD(j1e()),$p=iD(HF()),AA=iD(TW()),V1e=new Y1e.default({cwd:process.cwd(),internals:Y1e.default.nodeInternals()}),Vht=({error:t})=>{let e=t.stack?t.stack.split(` +`).slice(1):void 0,r=e?V1e.parseLine(e[0]):void 0,s,a=0;if(r?.file&&r?.line&&W1e.existsSync(r.file)){let n=W1e.readFileSync(r.file,"utf8");if(s=Yht.default(n,r.line),s)for(let{line:c}of s)a=Math.max(a,String(c).length)}return Qs.default.createElement($p.default,{flexDirection:"column",padding:1},Qs.default.createElement($p.default,null,Qs.default.createElement(AA.default,{backgroundColor:"red",color:"white"}," ","ERROR"," "),Qs.default.createElement(AA.default,null," ",t.message)),r&&Qs.default.createElement($p.default,{marginTop:1},Qs.default.createElement(AA.default,{dimColor:!0},r.file,":",r.line,":",r.column)),r&&s&&Qs.default.createElement($p.default,{marginTop:1,flexDirection:"column"},s.map(({line:n,value:c})=>Qs.default.createElement($p.default,{key:n},Qs.default.createElement($p.default,{width:a+1},Qs.default.createElement(AA.default,{dimColor:n!==r.line,backgroundColor:n===r.line?"red":void 0,color:n===r.line?"white":void 0},String(n).padStart(a," "),":")),Qs.default.createElement(AA.default,{key:n,backgroundColor:n===r.line?"red":void 0,color:n===r.line?"white":void 0}," "+c)))),t.stack&&Qs.default.createElement($p.default,{marginTop:1,flexDirection:"column"},t.stack.split(` +`).slice(1).map(n=>{let c=V1e.parseLine(n);return c?Qs.default.createElement($p.default,{key:n},Qs.default.createElement(AA.default,{dimColor:!0},"- "),Qs.default.createElement(AA.default,{dimColor:!0,bold:!0},c.function),Qs.default.createElement(AA.default,{dimColor:!0,color:"gray"}," ","(",c.file,":",c.line,":",c.column,")")):Qs.default.createElement($p.default,{key:n},Qs.default.createElement(AA.default,{dimColor:!0},"- "),Qs.default.createElement(AA.default,{dimColor:!0,bold:!0},n))})))};nf.default=Vht});var z1e=_(sf=>{"use strict";var Jht=sf&&sf.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r),Object.defineProperty(t,s,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),Kht=sf&&sf.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),zht=sf&&sf.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!=="default"&&Object.hasOwnProperty.call(t,r)&&Jht(e,t,r);return Kht(e,t),e},Lm=sf&&sf.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(sf,"__esModule",{value:!0});var Om=zht(hn()),K1e=Lm(F9()),Xht=Lm(IW()),Zht=Lm(wW()),$ht=Lm(vW()),e0t=Lm(DW()),t0t=Lm(_F()),r0t=Lm(J1e()),n0t=" ",i0t="\x1B[Z",s0t="\x1B",jF=class extends Om.PureComponent{constructor(){super(...arguments),this.state={isFocusEnabled:!0,activeFocusId:void 0,focusables:[],error:void 0},this.rawModeEnabledCount=0,this.handleSetRawMode=e=>{let{stdin:r}=this.props;if(!this.isRawModeSupported())throw r===process.stdin?new Error(`Raw mode is not supported on the current process.stdin, which Ink uses as input stream by default. +Read about how to prevent this error on https://github.com/vadimdemedes/ink/#israwmodesupported`):new Error(`Raw mode is not supported on the stdin provided to Ink. +Read about how to prevent this error on https://github.com/vadimdemedes/ink/#israwmodesupported`);if(r.setEncoding("utf8"),e){this.rawModeEnabledCount===0&&(r.addListener("data",this.handleInput),r.resume(),r.setRawMode(!0)),this.rawModeEnabledCount++;return}--this.rawModeEnabledCount===0&&(r.setRawMode(!1),r.removeListener("data",this.handleInput),r.pause())},this.handleInput=e=>{e===""&&this.props.exitOnCtrlC&&this.handleExit(),e===s0t&&this.state.activeFocusId&&this.setState({activeFocusId:void 0}),this.state.isFocusEnabled&&this.state.focusables.length>0&&(e===n0t&&this.focusNext(),e===i0t&&this.focusPrevious())},this.handleExit=e=>{this.isRawModeSupported()&&this.handleSetRawMode(!1),this.props.onExit(e)},this.enableFocus=()=>{this.setState({isFocusEnabled:!0})},this.disableFocus=()=>{this.setState({isFocusEnabled:!1})},this.focus=e=>{this.setState(r=>r.focusables.some(a=>a?.id===e)?{activeFocusId:e}:r)},this.focusNext=()=>{this.setState(e=>{var r;let s=(r=e.focusables[0])===null||r===void 0?void 0:r.id;return{activeFocusId:this.findNextFocusable(e)||s}})},this.focusPrevious=()=>{this.setState(e=>{var r;let s=(r=e.focusables[e.focusables.length-1])===null||r===void 0?void 0:r.id;return{activeFocusId:this.findPreviousFocusable(e)||s}})},this.addFocusable=(e,{autoFocus:r})=>{this.setState(s=>{let a=s.activeFocusId;return!a&&r&&(a=e),{activeFocusId:a,focusables:[...s.focusables,{id:e,isActive:!0}]}})},this.removeFocusable=e=>{this.setState(r=>({activeFocusId:r.activeFocusId===e?void 0:r.activeFocusId,focusables:r.focusables.filter(s=>s.id!==e)}))},this.activateFocusable=e=>{this.setState(r=>({focusables:r.focusables.map(s=>s.id!==e?s:{id:e,isActive:!0})}))},this.deactivateFocusable=e=>{this.setState(r=>({activeFocusId:r.activeFocusId===e?void 0:r.activeFocusId,focusables:r.focusables.map(s=>s.id!==e?s:{id:e,isActive:!1})}))},this.findNextFocusable=e=>{var r;let s=e.focusables.findIndex(a=>a.id===e.activeFocusId);for(let a=s+1;a{var r;let s=e.focusables.findIndex(a=>a.id===e.activeFocusId);for(let a=s-1;a>=0;a--)if(!((r=e.focusables[a])===null||r===void 0)&&r.isActive)return e.focusables[a].id}}static getDerivedStateFromError(e){return{error:e}}isRawModeSupported(){return this.props.stdin.isTTY}render(){return Om.default.createElement(Xht.default.Provider,{value:{exit:this.handleExit}},Om.default.createElement(Zht.default.Provider,{value:{stdin:this.props.stdin,setRawMode:this.handleSetRawMode,isRawModeSupported:this.isRawModeSupported(),internal_exitOnCtrlC:this.props.exitOnCtrlC}},Om.default.createElement($ht.default.Provider,{value:{stdout:this.props.stdout,write:this.props.writeToStdout}},Om.default.createElement(e0t.default.Provider,{value:{stderr:this.props.stderr,write:this.props.writeToStderr}},Om.default.createElement(t0t.default.Provider,{value:{activeId:this.state.activeFocusId,add:this.addFocusable,remove:this.removeFocusable,activate:this.activateFocusable,deactivate:this.deactivateFocusable,enableFocus:this.enableFocus,disableFocus:this.disableFocus,focusNext:this.focusNext,focusPrevious:this.focusPrevious,focus:this.focus}},this.state.error?Om.default.createElement(r0t.default,{error:this.state.error}):this.props.children)))))}componentDidMount(){K1e.default.hide(this.props.stdout)}componentWillUnmount(){K1e.default.show(this.props.stdout),this.isRawModeSupported()&&this.handleSetRawMode(!1)}componentDidCatch(e){this.handleExit(e)}};sf.default=jF;jF.displayName="InternalApp"});var $1e=_(of=>{"use strict";var o0t=of&&of.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r),Object.defineProperty(t,s,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),a0t=of&&of.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),l0t=of&&of.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!=="default"&&Object.hasOwnProperty.call(t,r)&&o0t(e,t,r);return a0t(e,t),e},af=of&&of.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(of,"__esModule",{value:!0});var c0t=af(hn()),X1e=WCe(),u0t=af(awe()),f0t=af(x9()),A0t=af(pwe()),p0t=af(gwe()),RW=af(a1e()),h0t=af(B1e()),g0t=af(R9()),d0t=af(b1e()),m0t=l0t(uW()),y0t=af(yW()),E0t=af(z1e()),Ew=process.env.CI==="false"?!1:A0t.default,Z1e=()=>{},FW=class{constructor(e){this.resolveExitPromise=()=>{},this.rejectExitPromise=()=>{},this.unsubscribeExit=()=>{},this.onRender=()=>{if(this.isUnmounted)return;let{output:r,outputHeight:s,staticOutput:a}=h0t.default(this.rootNode,this.options.stdout.columns||80),n=a&&a!==` +`;if(this.options.debug){n&&(this.fullStaticOutput+=a),this.options.stdout.write(this.fullStaticOutput+r);return}if(Ew){n&&this.options.stdout.write(a),this.lastOutput=r;return}if(n&&(this.fullStaticOutput+=a),s>=this.options.stdout.rows){this.options.stdout.write(f0t.default.clearTerminal+this.fullStaticOutput+r),this.lastOutput=r;return}n&&(this.log.clear(),this.options.stdout.write(a),this.log(r)),!n&&r!==this.lastOutput&&this.throttledLog(r),this.lastOutput=r},p0t.default(this),this.options=e,this.rootNode=m0t.createNode("ink-root"),this.rootNode.onRender=e.debug?this.onRender:X1e(this.onRender,32,{leading:!0,trailing:!0}),this.rootNode.onImmediateRender=this.onRender,this.log=u0t.default.create(e.stdout),this.throttledLog=e.debug?this.log:X1e(this.log,void 0,{leading:!0,trailing:!0}),this.isUnmounted=!1,this.lastOutput="",this.fullStaticOutput="",this.container=RW.default.createContainer(this.rootNode,0,!1,null),this.unsubscribeExit=g0t.default(this.unmount,{alwaysLast:!1}),e.patchConsole&&this.patchConsole(),Ew||(e.stdout.on("resize",this.onRender),this.unsubscribeResize=()=>{e.stdout.off("resize",this.onRender)})}render(e){let r=c0t.default.createElement(E0t.default,{stdin:this.options.stdin,stdout:this.options.stdout,stderr:this.options.stderr,writeToStdout:this.writeToStdout,writeToStderr:this.writeToStderr,exitOnCtrlC:this.options.exitOnCtrlC,onExit:this.unmount},e);RW.default.updateContainer(r,this.container,null,Z1e)}writeToStdout(e){if(!this.isUnmounted){if(this.options.debug){this.options.stdout.write(e+this.fullStaticOutput+this.lastOutput);return}if(Ew){this.options.stdout.write(e);return}this.log.clear(),this.options.stdout.write(e),this.log(this.lastOutput)}}writeToStderr(e){if(!this.isUnmounted){if(this.options.debug){this.options.stderr.write(e),this.options.stdout.write(this.fullStaticOutput+this.lastOutput);return}if(Ew){this.options.stderr.write(e);return}this.log.clear(),this.options.stderr.write(e),this.log(this.lastOutput)}}unmount(e){this.isUnmounted||(this.onRender(),this.unsubscribeExit(),typeof this.restoreConsole=="function"&&this.restoreConsole(),typeof this.unsubscribeResize=="function"&&this.unsubscribeResize(),Ew?this.options.stdout.write(this.lastOutput+` +`):this.options.debug||this.log.done(),this.isUnmounted=!0,RW.default.updateContainer(null,this.container,null,Z1e),y0t.default.delete(this.options.stdout),e instanceof Error?this.rejectExitPromise(e):this.resolveExitPromise())}waitUntilExit(){return this.exitPromise||(this.exitPromise=new Promise((e,r)=>{this.resolveExitPromise=e,this.rejectExitPromise=r})),this.exitPromise}clear(){!Ew&&!this.options.debug&&this.log.clear()}patchConsole(){this.options.debug||(this.restoreConsole=d0t.default((e,r)=>{e==="stdout"&&this.writeToStdout(r),e==="stderr"&&(r.startsWith("The above error occurred")||this.writeToStderr(r))}))}};of.default=FW});var t2e=_(sD=>{"use strict";var e2e=sD&&sD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(sD,"__esModule",{value:!0});var I0t=e2e($1e()),GF=e2e(yW()),C0t=Ie("stream"),w0t=(t,e)=>{let r=Object.assign({stdout:process.stdout,stdin:process.stdin,stderr:process.stderr,debug:!1,exitOnCtrlC:!0,patchConsole:!0},B0t(e)),s=v0t(r.stdout,()=>new I0t.default(r));return s.render(t),{rerender:s.render,unmount:()=>s.unmount(),waitUntilExit:s.waitUntilExit,cleanup:()=>GF.default.delete(r.stdout),clear:s.clear}};sD.default=w0t;var B0t=(t={})=>t instanceof C0t.Stream?{stdout:t,stdin:process.stdin}:t,v0t=(t,e)=>{let r;return GF.default.has(t)?r=GF.default.get(t):(r=e(),GF.default.set(t,r)),r}});var n2e=_(eh=>{"use strict";var S0t=eh&&eh.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r),Object.defineProperty(t,s,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),D0t=eh&&eh.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),b0t=eh&&eh.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!=="default"&&Object.hasOwnProperty.call(t,r)&&S0t(e,t,r);return D0t(e,t),e};Object.defineProperty(eh,"__esModule",{value:!0});var oD=b0t(hn()),r2e=t=>{let{items:e,children:r,style:s}=t,[a,n]=oD.useState(0),c=oD.useMemo(()=>e.slice(a),[e,a]);oD.useLayoutEffect(()=>{n(e.length)},[e.length]);let f=c.map((h,E)=>r(h,a+E)),p=oD.useMemo(()=>Object.assign({position:"absolute",flexDirection:"column"},s),[s]);return oD.default.createElement("ink-box",{internal_static:!0,style:p},f)};r2e.displayName="Static";eh.default=r2e});var s2e=_(aD=>{"use strict";var P0t=aD&&aD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(aD,"__esModule",{value:!0});var x0t=P0t(hn()),i2e=({children:t,transform:e})=>t==null?null:x0t.default.createElement("ink-text",{style:{flexGrow:0,flexShrink:1,flexDirection:"row"},internal_transform:e},t);i2e.displayName="Transform";aD.default=i2e});var a2e=_(lD=>{"use strict";var k0t=lD&&lD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(lD,"__esModule",{value:!0});var Q0t=k0t(hn()),o2e=({count:t=1})=>Q0t.default.createElement("ink-text",null,` +`.repeat(t));o2e.displayName="Newline";lD.default=o2e});var u2e=_(cD=>{"use strict";var l2e=cD&&cD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(cD,"__esModule",{value:!0});var T0t=l2e(hn()),R0t=l2e(HF()),c2e=()=>T0t.default.createElement(R0t.default,{flexGrow:1});c2e.displayName="Spacer";cD.default=c2e});var qF=_(uD=>{"use strict";var F0t=uD&&uD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(uD,"__esModule",{value:!0});var N0t=hn(),O0t=F0t(wW()),L0t=()=>N0t.useContext(O0t.default);uD.default=L0t});var A2e=_(fD=>{"use strict";var M0t=fD&&fD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(fD,"__esModule",{value:!0});var f2e=hn(),U0t=M0t(qF()),_0t=(t,e={})=>{let{stdin:r,setRawMode:s,internal_exitOnCtrlC:a}=U0t.default();f2e.useEffect(()=>{if(e.isActive!==!1)return s(!0),()=>{s(!1)}},[e.isActive,s]),f2e.useEffect(()=>{if(e.isActive===!1)return;let n=c=>{let f=String(c),p={upArrow:f==="\x1B[A",downArrow:f==="\x1B[B",leftArrow:f==="\x1B[D",rightArrow:f==="\x1B[C",pageDown:f==="\x1B[6~",pageUp:f==="\x1B[5~",return:f==="\r",escape:f==="\x1B",ctrl:!1,shift:!1,tab:f===" "||f==="\x1B[Z",backspace:f==="\b",delete:f==="\x7F"||f==="\x1B[3~",meta:!1};f<=""&&!p.return&&(f=String.fromCharCode(f.charCodeAt(0)+97-1),p.ctrl=!0),f.startsWith("\x1B")&&(f=f.slice(1),p.meta=!0);let h=f>="A"&&f<="Z",E=f>="\u0410"&&f<="\u042F";f.length===1&&(h||E)&&(p.shift=!0),p.tab&&f==="[Z"&&(p.shift=!0),(p.tab||p.backspace||p.delete)&&(f=""),(!(f==="c"&&p.ctrl)||!a)&&t(f,p)};return r?.on("data",n),()=>{r?.off("data",n)}},[e.isActive,r,a,t])};fD.default=_0t});var p2e=_(AD=>{"use strict";var H0t=AD&&AD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(AD,"__esModule",{value:!0});var j0t=hn(),G0t=H0t(IW()),q0t=()=>j0t.useContext(G0t.default);AD.default=q0t});var h2e=_(pD=>{"use strict";var W0t=pD&&pD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(pD,"__esModule",{value:!0});var Y0t=hn(),V0t=W0t(vW()),J0t=()=>Y0t.useContext(V0t.default);pD.default=J0t});var g2e=_(hD=>{"use strict";var K0t=hD&&hD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(hD,"__esModule",{value:!0});var z0t=hn(),X0t=K0t(DW()),Z0t=()=>z0t.useContext(X0t.default);hD.default=Z0t});var m2e=_(dD=>{"use strict";var d2e=dD&&dD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(dD,"__esModule",{value:!0});var gD=hn(),$0t=d2e(_F()),egt=d2e(qF()),tgt=({isActive:t=!0,autoFocus:e=!1,id:r}={})=>{let{isRawModeSupported:s,setRawMode:a}=egt.default(),{activeId:n,add:c,remove:f,activate:p,deactivate:h,focus:E}=gD.useContext($0t.default),C=gD.useMemo(()=>r??Math.random().toString().slice(2,7),[r]);return gD.useEffect(()=>(c(C,{autoFocus:e}),()=>{f(C)}),[C,e]),gD.useEffect(()=>{t?p(C):h(C)},[t,C]),gD.useEffect(()=>{if(!(!s||!t))return a(!0),()=>{a(!1)}},[t]),{isFocused:!!C&&n===C,focus:E}};dD.default=tgt});var y2e=_(mD=>{"use strict";var rgt=mD&&mD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(mD,"__esModule",{value:!0});var ngt=hn(),igt=rgt(_F()),sgt=()=>{let t=ngt.useContext(igt.default);return{enableFocus:t.enableFocus,disableFocus:t.disableFocus,focusNext:t.focusNext,focusPrevious:t.focusPrevious,focus:t.focus}};mD.default=sgt});var E2e=_(NW=>{"use strict";Object.defineProperty(NW,"__esModule",{value:!0});NW.default=t=>{var e,r,s,a;return{width:(r=(e=t.yogaNode)===null||e===void 0?void 0:e.getComputedWidth())!==null&&r!==void 0?r:0,height:(a=(s=t.yogaNode)===null||s===void 0?void 0:s.getComputedHeight())!==null&&a!==void 0?a:0}}});var Wc=_(mo=>{"use strict";Object.defineProperty(mo,"__esModule",{value:!0});var ogt=t2e();Object.defineProperty(mo,"render",{enumerable:!0,get:function(){return ogt.default}});var agt=HF();Object.defineProperty(mo,"Box",{enumerable:!0,get:function(){return agt.default}});var lgt=TW();Object.defineProperty(mo,"Text",{enumerable:!0,get:function(){return lgt.default}});var cgt=n2e();Object.defineProperty(mo,"Static",{enumerable:!0,get:function(){return cgt.default}});var ugt=s2e();Object.defineProperty(mo,"Transform",{enumerable:!0,get:function(){return ugt.default}});var fgt=a2e();Object.defineProperty(mo,"Newline",{enumerable:!0,get:function(){return fgt.default}});var Agt=u2e();Object.defineProperty(mo,"Spacer",{enumerable:!0,get:function(){return Agt.default}});var pgt=A2e();Object.defineProperty(mo,"useInput",{enumerable:!0,get:function(){return pgt.default}});var hgt=p2e();Object.defineProperty(mo,"useApp",{enumerable:!0,get:function(){return hgt.default}});var ggt=qF();Object.defineProperty(mo,"useStdin",{enumerable:!0,get:function(){return ggt.default}});var dgt=h2e();Object.defineProperty(mo,"useStdout",{enumerable:!0,get:function(){return dgt.default}});var mgt=g2e();Object.defineProperty(mo,"useStderr",{enumerable:!0,get:function(){return mgt.default}});var ygt=m2e();Object.defineProperty(mo,"useFocus",{enumerable:!0,get:function(){return ygt.default}});var Egt=y2e();Object.defineProperty(mo,"useFocusManager",{enumerable:!0,get:function(){return Egt.default}});var Igt=E2e();Object.defineProperty(mo,"measureElement",{enumerable:!0,get:function(){return Igt.default}})});var LW={};Vt(LW,{Gem:()=>OW});var I2e,Mm,OW,WF=Xe(()=>{I2e=ut(Wc()),Mm=ut(hn()),OW=(0,Mm.memo)(({active:t})=>{let e=(0,Mm.useMemo)(()=>t?"\u25C9":"\u25EF",[t]),r=(0,Mm.useMemo)(()=>t?"green":"yellow",[t]);return Mm.default.createElement(I2e.Text,{color:r},e)})});var w2e={};Vt(w2e,{useKeypress:()=>Um});function Um({active:t},e,r){let{stdin:s}=(0,C2e.useStdin)(),a=(0,YF.useCallback)((n,c)=>e(n,c),r);(0,YF.useEffect)(()=>{if(!(!t||!s))return s.on("keypress",a),()=>{s.off("keypress",a)}},[t,a,s])}var C2e,YF,yD=Xe(()=>{C2e=ut(Wc()),YF=ut(hn())});var v2e={};Vt(v2e,{FocusRequest:()=>B2e,useFocusRequest:()=>MW});var B2e,MW,UW=Xe(()=>{yD();B2e=(r=>(r.BEFORE="before",r.AFTER="after",r))(B2e||{}),MW=function({active:t},e,r){Um({active:t},(s,a)=>{a.name==="tab"&&(a.shift?e("before"):e("after"))},r)}});var S2e={};Vt(S2e,{useListInput:()=>ED});var ED,VF=Xe(()=>{yD();ED=function(t,e,{active:r,minus:s,plus:a,set:n,loop:c=!0}){Um({active:r},(f,p)=>{let h=e.indexOf(t);switch(p.name){case s:{let E=h-1;if(c){n(e[(e.length+E)%e.length]);return}if(E<0)return;n(e[E])}break;case a:{let E=h+1;if(c){n(e[E%e.length]);return}if(E>=e.length)return;n(e[E])}break}},[e,t,a,n,c])}});var JF={};Vt(JF,{ScrollableItems:()=>Cgt});var eg,dl,Cgt,KF=Xe(()=>{eg=ut(Wc()),dl=ut(hn());UW();VF();Cgt=({active:t=!0,children:e=[],radius:r=10,size:s=1,loop:a=!0,onFocusRequest:n,willReachEnd:c})=>{let f=N=>{if(N.key===null)throw new Error("Expected all children to have a key");return N.key},p=dl.default.Children.map(e,N=>f(N)),h=p[0],[E,C]=(0,dl.useState)(h),S=p.indexOf(E);(0,dl.useEffect)(()=>{p.includes(E)||C(h)},[e]),(0,dl.useEffect)(()=>{c&&S>=p.length-2&&c()},[S]),MW({active:t&&!!n},N=>{n?.(N)},[n]),ED(E,p,{active:t,minus:"up",plus:"down",set:C,loop:a});let P=S-r,I=S+r;I>p.length&&(P-=I-p.length,I=p.length),P<0&&(I+=-P,P=0),I>=p.length&&(I=p.length-1);let R=[];for(let N=P;N<=I;++N){let U=p[N],W=t&&U===E;R.push(dl.default.createElement(eg.Box,{key:U,height:s},dl.default.createElement(eg.Box,{marginLeft:1,marginRight:1},dl.default.createElement(eg.Text,null,W?dl.default.createElement(eg.Text,{color:"cyan",bold:!0},">"):" ")),dl.default.createElement(eg.Box,null,dl.default.cloneElement(e[N],{active:W}))))}return dl.default.createElement(eg.Box,{flexDirection:"column",width:"100%"},R)}});var D2e,th,b2e,_W,P2e,HW=Xe(()=>{D2e=ut(Wc()),th=ut(hn()),b2e=Ie("readline"),_W=th.default.createContext(null),P2e=({children:t})=>{let{stdin:e,setRawMode:r}=(0,D2e.useStdin)();(0,th.useEffect)(()=>{r&&r(!0),e&&(0,b2e.emitKeypressEvents)(e)},[e,r]);let[s,a]=(0,th.useState)(new Map),n=(0,th.useMemo)(()=>({getAll:()=>s,get:c=>s.get(c),set:(c,f)=>a(new Map([...s,[c,f]]))}),[s,a]);return th.default.createElement(_W.Provider,{value:n,children:t})}});var jW={};Vt(jW,{useMinistore:()=>wgt});function wgt(t,e){let r=(0,zF.useContext)(_W);if(r===null)throw new Error("Expected this hook to run with a ministore context attached");if(typeof t>"u")return r.getAll();let s=(0,zF.useCallback)(n=>{r.set(t,n)},[t,r.set]),a=r.get(t);return typeof a>"u"&&(a=e),[a,s]}var zF,GW=Xe(()=>{zF=ut(hn());HW()});var ZF={};Vt(ZF,{renderForm:()=>Bgt});async function Bgt(t,e,{stdin:r,stdout:s,stderr:a}){let n,c=p=>{let{exit:h}=(0,XF.useApp)();Um({active:!0},(E,C)=>{C.name==="return"&&(n=p,h())},[h,p])},{waitUntilExit:f}=(0,XF.render)(qW.default.createElement(P2e,null,qW.default.createElement(t,{...e,useSubmit:c})),{stdin:r,stdout:s,stderr:a});return await f(),n}var XF,qW,$F=Xe(()=>{XF=ut(Wc()),qW=ut(hn());HW();yD()});var T2e=_(ID=>{"use strict";Object.defineProperty(ID,"__esModule",{value:!0});ID.UncontrolledTextInput=void 0;var k2e=hn(),WW=hn(),x2e=Wc(),_m=TE(),Q2e=({value:t,placeholder:e="",focus:r=!0,mask:s,highlightPastedText:a=!1,showCursor:n=!0,onChange:c,onSubmit:f})=>{let[{cursorOffset:p,cursorWidth:h},E]=WW.useState({cursorOffset:(t||"").length,cursorWidth:0});WW.useEffect(()=>{E(R=>{if(!r||!n)return R;let N=t||"";return R.cursorOffset>N.length-1?{cursorOffset:N.length,cursorWidth:0}:R})},[t,r,n]);let C=a?h:0,S=s?s.repeat(t.length):t,P=S,I=e?_m.grey(e):void 0;if(n&&r){I=e.length>0?_m.inverse(e[0])+_m.grey(e.slice(1)):_m.inverse(" "),P=S.length>0?"":_m.inverse(" ");let R=0;for(let N of S)R>=p-C&&R<=p?P+=_m.inverse(N):P+=N,R++;S.length>0&&p===S.length&&(P+=_m.inverse(" "))}return x2e.useInput((R,N)=>{if(N.upArrow||N.downArrow||N.ctrl&&R==="c"||N.tab||N.shift&&N.tab)return;if(N.return){f&&f(t);return}let U=p,W=t,ee=0;N.leftArrow?n&&U--:N.rightArrow?n&&U++:N.backspace||N.delete?p>0&&(W=t.slice(0,p-1)+t.slice(p,t.length),U--):(W=t.slice(0,p)+R+t.slice(p,t.length),U+=R.length,R.length>1&&(ee=R.length)),p<0&&(U=0),p>t.length&&(U=t.length),E({cursorOffset:U,cursorWidth:ee}),W!==t&&c(W)},{isActive:r}),k2e.createElement(x2e.Text,null,e?S.length>0?P:I:P)};ID.default=Q2e;ID.UncontrolledTextInput=({initialValue:t="",...e})=>{let[r,s]=WW.useState(t);return k2e.createElement(Q2e,Object.assign({},e,{value:r,onChange:s}))}});var N2e={};Vt(N2e,{Pad:()=>YW});var R2e,F2e,YW,VW=Xe(()=>{R2e=ut(Wc()),F2e=ut(hn()),YW=({length:t,active:e})=>{if(t===0)return null;let r=t>1?` ${"-".repeat(t-1)}`:" ";return F2e.default.createElement(R2e.Text,{dimColor:!e},r)}});var O2e={};Vt(O2e,{ItemOptions:()=>vgt});var wD,tg,vgt,L2e=Xe(()=>{wD=ut(Wc()),tg=ut(hn());VF();WF();VW();vgt=function({active:t,skewer:e,options:r,value:s,onChange:a,sizes:n=[]}){let c=r.filter(({label:p})=>!!p).map(({value:p})=>p),f=r.findIndex(p=>p.value===s&&p.label!="");return ED(s,c,{active:t,minus:"left",plus:"right",set:a}),tg.default.createElement(tg.default.Fragment,null,r.map(({label:p},h)=>{let E=h===f,C=n[h]-1||0,S=p.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,""),P=Math.max(0,C-S.length-2);return p?tg.default.createElement(wD.Box,{key:p,width:C,marginLeft:1},tg.default.createElement(wD.Text,{wrap:"truncate"},tg.default.createElement(OW,{active:E})," ",p),e?tg.default.createElement(YW,{active:t,length:P}):null):tg.default.createElement(wD.Box,{key:`spacer-${h}`,width:C,marginLeft:1})}))}});var Z2e=_((AZt,X2e)=>{var iY;X2e.exports=()=>(typeof iY>"u"&&(iY=Ie("zlib").brotliDecompressSync(Buffer.from("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","base64")).toString()),iY)});var EBe=_((LZt,yBe)=>{var pY=Symbol("arg flag"),Yc=class t extends Error{constructor(e,r){super(e),this.name="ArgError",this.code=r,Object.setPrototypeOf(this,t.prototype)}};function UD(t,{argv:e=process.argv.slice(2),permissive:r=!1,stopAtPositional:s=!1}={}){if(!t)throw new Yc("argument specification object is required","ARG_CONFIG_NO_SPEC");let a={_:[]},n={},c={};for(let f of Object.keys(t)){if(!f)throw new Yc("argument key cannot be an empty string","ARG_CONFIG_EMPTY_KEY");if(f[0]!=="-")throw new Yc(`argument key must start with '-' but found: '${f}'`,"ARG_CONFIG_NONOPT_KEY");if(f.length===1)throw new Yc(`argument key must have a name; singular '-' keys are not allowed: ${f}`,"ARG_CONFIG_NONAME_KEY");if(typeof t[f]=="string"){n[f]=t[f];continue}let p=t[f],h=!1;if(Array.isArray(p)&&p.length===1&&typeof p[0]=="function"){let[E]=p;p=(C,S,P=[])=>(P.push(E(C,S,P[P.length-1])),P),h=E===Boolean||E[pY]===!0}else if(typeof p=="function")h=p===Boolean||p[pY]===!0;else throw new Yc(`type missing or not a function or valid array type: ${f}`,"ARG_CONFIG_VAD_TYPE");if(f[1]!=="-"&&f.length>2)throw new Yc(`short argument keys (with a single hyphen) must have only one character: ${f}`,"ARG_CONFIG_SHORTOPT_TOOLONG");c[f]=[p,h]}for(let f=0,p=e.length;f0){a._=a._.concat(e.slice(f));break}if(h==="--"){a._=a._.concat(e.slice(f+1));break}if(h.length>1&&h[0]==="-"){let E=h[1]==="-"||h.length===2?[h]:h.slice(1).split("").map(C=>`-${C}`);for(let C=0;C1&&e[f+1][0]==="-"&&!(e[f+1].match(/^-?\d*(\.(?=\d))?\d*$/)&&(N===Number||typeof BigInt<"u"&&N===BigInt))){let W=P===R?"":` (alias for ${R})`;throw new Yc(`option requires argument: ${P}${W}`,"ARG_MISSING_REQUIRED_LONGARG")}a[R]=N(e[f+1],R,a[R]),++f}else a[R]=N(I,R,a[R])}}else a._.push(h)}return a}UD.flag=t=>(t[pY]=!0,t);UD.COUNT=UD.flag((t,e,r)=>(r||0)+1);UD.ArgError=Yc;yBe.exports=UD});var bBe=_((p$t,DBe)=>{var mY;DBe.exports=()=>(typeof mY>"u"&&(mY=Ie("zlib").brotliDecompressSync(Buffer.from("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","base64")).toString()),mY)});var TBe=_((BY,vY)=>{(function(t){BY&&typeof BY=="object"&&typeof vY<"u"?vY.exports=t():typeof define=="function"&&define.amd?define([],t):typeof window<"u"?window.isWindows=t():typeof global<"u"?global.isWindows=t():typeof self<"u"?self.isWindows=t():this.isWindows=t()})(function(){"use strict";return function(){return process&&(process.platform==="win32"||/^(msys|cygwin)$/.test(process.env.OSTYPE))}})});var OBe=_((fer,NBe)=>{"use strict";SY.ifExists=Sdt;var Dw=Ie("util"),Vc=Ie("path"),RBe=TBe(),wdt=/^#!\s*(?:\/usr\/bin\/env)?\s*([^ \t]+)(.*)$/,Bdt={createPwshFile:!0,createCmdFile:RBe(),fs:Ie("fs")},vdt=new Map([[".js","node"],[".cjs","node"],[".mjs","node"],[".cmd","cmd"],[".bat","cmd"],[".ps1","pwsh"],[".sh","sh"]]);function FBe(t){let e={...Bdt,...t},r=e.fs;return e.fs_={chmod:r.chmod?Dw.promisify(r.chmod):async()=>{},mkdir:Dw.promisify(r.mkdir),readFile:Dw.promisify(r.readFile),stat:Dw.promisify(r.stat),unlink:Dw.promisify(r.unlink),writeFile:Dw.promisify(r.writeFile)},e}async function SY(t,e,r){let s=FBe(r);await s.fs_.stat(t),await bdt(t,e,s)}function Sdt(t,e,r){return SY(t,e,r).catch(()=>{})}function Ddt(t,e){return e.fs_.unlink(t).catch(()=>{})}async function bdt(t,e,r){let s=await Tdt(t,r);return await Pdt(e,r),xdt(t,e,s,r)}function Pdt(t,e){return e.fs_.mkdir(Vc.dirname(t),{recursive:!0})}function xdt(t,e,r,s){let a=FBe(s),n=[{generator:Ndt,extension:""}];return a.createCmdFile&&n.push({generator:Fdt,extension:".cmd"}),a.createPwshFile&&n.push({generator:Odt,extension:".ps1"}),Promise.all(n.map(c=>Rdt(t,e+c.extension,r,c.generator,a)))}function kdt(t,e){return Ddt(t,e)}function Qdt(t,e){return Ldt(t,e)}async function Tdt(t,e){let a=(await e.fs_.readFile(t,"utf8")).trim().split(/\r*\n/)[0].match(wdt);if(!a){let n=Vc.extname(t).toLowerCase();return{program:vdt.get(n)||null,additionalArgs:""}}return{program:a[1],additionalArgs:a[2]}}async function Rdt(t,e,r,s,a){let n=a.preserveSymlinks?"--preserve-symlinks":"",c=[r.additionalArgs,n].filter(f=>f).join(" ");return a=Object.assign({},a,{prog:r.program,args:c}),await kdt(e,a),await a.fs_.writeFile(e,s(t,e,a),"utf8"),Qdt(e,a)}function Fdt(t,e,r){let a=Vc.relative(Vc.dirname(e),t).split("/").join("\\"),n=Vc.isAbsolute(a)?`"${a}"`:`"%~dp0\\${a}"`,c,f=r.prog,p=r.args||"",h=DY(r.nodePath).win32;f?(c=`"%~dp0\\${f}.exe"`,a=n):(f=n,p="",a="");let E=r.progArgs?`${r.progArgs.join(" ")} `:"",C=h?`@SET NODE_PATH=${h}\r +`:"";return c?C+=`@IF EXIST ${c} (\r + ${c} ${p} ${a} ${E}%*\r +) ELSE (\r + @SETLOCAL\r + @SET PATHEXT=%PATHEXT:;.JS;=;%\r + ${f} ${p} ${a} ${E}%*\r +)\r +`:C+=`@${f} ${p} ${a} ${E}%*\r +`,C}function Ndt(t,e,r){let s=Vc.relative(Vc.dirname(e),t),a=r.prog&&r.prog.split("\\").join("/"),n;s=s.split("\\").join("/");let c=Vc.isAbsolute(s)?`"${s}"`:`"$basedir/${s}"`,f=r.args||"",p=DY(r.nodePath).posix;a?(n=`"$basedir/${r.prog}"`,s=c):(a=c,f="",s="");let h=r.progArgs?`${r.progArgs.join(" ")} `:"",E=`#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')") + +case \`uname\` in + *CYGWIN*) basedir=\`cygpath -w "$basedir"\`;; +esac + +`,C=r.nodePath?`export NODE_PATH="${p}" +`:"";return n?E+=`${C}if [ -x ${n} ]; then + exec ${n} ${f} ${s} ${h}"$@" +else + exec ${a} ${f} ${s} ${h}"$@" +fi +`:E+=`${C}${a} ${f} ${s} ${h}"$@" +exit $? +`,E}function Odt(t,e,r){let s=Vc.relative(Vc.dirname(e),t),a=r.prog&&r.prog.split("\\").join("/"),n=a&&`"${a}$exe"`,c;s=s.split("\\").join("/");let f=Vc.isAbsolute(s)?`"${s}"`:`"$basedir/${s}"`,p=r.args||"",h=DY(r.nodePath),E=h.win32,C=h.posix;n?(c=`"$basedir/${r.prog}$exe"`,s=f):(n=f,p="",s="");let S=r.progArgs?`${r.progArgs.join(" ")} `:"",P=`#!/usr/bin/env pwsh +$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent + +$exe="" +${r.nodePath?`$env_node_path=$env:NODE_PATH +$env:NODE_PATH="${E}" +`:""}if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) { + # Fix case when both the Windows and Linux builds of Node + # are installed in the same directory + $exe=".exe" +}`;return r.nodePath&&(P+=` else { + $env:NODE_PATH="${C}" +}`),c?P+=` +$ret=0 +if (Test-Path ${c}) { + # Support pipeline input + if ($MyInvocation.ExpectingInput) { + $input | & ${c} ${p} ${s} ${S}$args + } else { + & ${c} ${p} ${s} ${S}$args + } + $ret=$LASTEXITCODE +} else { + # Support pipeline input + if ($MyInvocation.ExpectingInput) { + $input | & ${n} ${p} ${s} ${S}$args + } else { + & ${n} ${p} ${s} ${S}$args + } + $ret=$LASTEXITCODE +} +${r.nodePath?`$env:NODE_PATH=$env_node_path +`:""}exit $ret +`:P+=` +# Support pipeline input +if ($MyInvocation.ExpectingInput) { + $input | & ${n} ${p} ${s} ${S}$args +} else { + & ${n} ${p} ${s} ${S}$args +} +${r.nodePath?`$env:NODE_PATH=$env_node_path +`:""}exit $LASTEXITCODE +`,P}function Ldt(t,e){return e.fs_.chmod(t,493)}function DY(t){if(!t)return{win32:"",posix:""};let e=typeof t=="string"?t.split(Vc.delimiter):Array.from(t),r={};for(let s=0;s`/mnt/${f.toLowerCase()}`):e[s];r.win32=r.win32?`${r.win32};${a}`:a,r.posix=r.posix?`${r.posix}:${n}`:n,r[s]={win32:a,posix:n}}return r}NBe.exports=SY});var _Y=_((_tr,tve)=>{tve.exports=Ie("stream")});var sve=_((Htr,ive)=>{"use strict";function rve(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(t);e&&(s=s.filter(function(a){return Object.getOwnPropertyDescriptor(t,a).enumerable})),r.push.apply(r,s)}return r}function mmt(t){for(var e=1;e0?this.tail.next=s:this.head=s,this.tail=s,++this.length}},{key:"unshift",value:function(r){var s={data:r,next:this.head};this.length===0&&(this.tail=s),this.head=s,++this.length}},{key:"shift",value:function(){if(this.length!==0){var r=this.head.data;return this.length===1?this.head=this.tail=null:this.head=this.head.next,--this.length,r}}},{key:"clear",value:function(){this.head=this.tail=null,this.length=0}},{key:"join",value:function(r){if(this.length===0)return"";for(var s=this.head,a=""+s.data;s=s.next;)a+=r+s.data;return a}},{key:"concat",value:function(r){if(this.length===0)return pN.alloc(0);for(var s=pN.allocUnsafe(r>>>0),a=this.head,n=0;a;)vmt(a.data,s,n),n+=a.data.length,a=a.next;return s}},{key:"consume",value:function(r,s){var a;return rc.length?c.length:r;if(f===c.length?n+=c:n+=c.slice(0,r),r-=f,r===0){f===c.length?(++a,s.next?this.head=s.next:this.head=this.tail=null):(this.head=s,s.data=c.slice(f));break}++a}return this.length-=a,n}},{key:"_getBuffer",value:function(r){var s=pN.allocUnsafe(r),a=this.head,n=1;for(a.data.copy(s),r-=a.data.length;a=a.next;){var c=a.data,f=r>c.length?c.length:r;if(c.copy(s,s.length-r,0,f),r-=f,r===0){f===c.length?(++n,a.next?this.head=a.next:this.head=this.tail=null):(this.head=a,a.data=c.slice(f));break}++n}return this.length-=n,s}},{key:Bmt,value:function(r,s){return HY(this,mmt({},s,{depth:0,customInspect:!1}))}}]),t}()});var GY=_((jtr,ave)=>{"use strict";function Smt(t,e){var r=this,s=this._readableState&&this._readableState.destroyed,a=this._writableState&&this._writableState.destroyed;return s||a?(e?e(t):t&&(this._writableState?this._writableState.errorEmitted||(this._writableState.errorEmitted=!0,process.nextTick(jY,this,t)):process.nextTick(jY,this,t)),this):(this._readableState&&(this._readableState.destroyed=!0),this._writableState&&(this._writableState.destroyed=!0),this._destroy(t||null,function(n){!e&&n?r._writableState?r._writableState.errorEmitted?process.nextTick(hN,r):(r._writableState.errorEmitted=!0,process.nextTick(ove,r,n)):process.nextTick(ove,r,n):e?(process.nextTick(hN,r),e(n)):process.nextTick(hN,r)}),this)}function ove(t,e){jY(t,e),hN(t)}function hN(t){t._writableState&&!t._writableState.emitClose||t._readableState&&!t._readableState.emitClose||t.emit("close")}function Dmt(){this._readableState&&(this._readableState.destroyed=!1,this._readableState.reading=!1,this._readableState.ended=!1,this._readableState.endEmitted=!1),this._writableState&&(this._writableState.destroyed=!1,this._writableState.ended=!1,this._writableState.ending=!1,this._writableState.finalCalled=!1,this._writableState.prefinished=!1,this._writableState.finished=!1,this._writableState.errorEmitted=!1)}function jY(t,e){t.emit("error",e)}function bmt(t,e){var r=t._readableState,s=t._writableState;r&&r.autoDestroy||s&&s.autoDestroy?t.destroy(e):t.emit("error",e)}ave.exports={destroy:Smt,undestroy:Dmt,errorOrDestroy:bmt}});var lg=_((Gtr,uve)=>{"use strict";var cve={};function Kc(t,e,r){r||(r=Error);function s(n,c,f){return typeof e=="string"?e:e(n,c,f)}class a extends r{constructor(c,f,p){super(s(c,f,p))}}a.prototype.name=r.name,a.prototype.code=t,cve[t]=a}function lve(t,e){if(Array.isArray(t)){let r=t.length;return t=t.map(s=>String(s)),r>2?`one of ${e} ${t.slice(0,r-1).join(", ")}, or `+t[r-1]:r===2?`one of ${e} ${t[0]} or ${t[1]}`:`of ${e} ${t[0]}`}else return`of ${e} ${String(t)}`}function Pmt(t,e,r){return t.substr(!r||r<0?0:+r,e.length)===e}function xmt(t,e,r){return(r===void 0||r>t.length)&&(r=t.length),t.substring(r-e.length,r)===e}function kmt(t,e,r){return typeof r!="number"&&(r=0),r+e.length>t.length?!1:t.indexOf(e,r)!==-1}Kc("ERR_INVALID_OPT_VALUE",function(t,e){return'The value "'+e+'" is invalid for option "'+t+'"'},TypeError);Kc("ERR_INVALID_ARG_TYPE",function(t,e,r){let s;typeof e=="string"&&Pmt(e,"not ")?(s="must not be",e=e.replace(/^not /,"")):s="must be";let a;if(xmt(t," argument"))a=`The ${t} ${s} ${lve(e,"type")}`;else{let n=kmt(t,".")?"property":"argument";a=`The "${t}" ${n} ${s} ${lve(e,"type")}`}return a+=`. Received type ${typeof r}`,a},TypeError);Kc("ERR_STREAM_PUSH_AFTER_EOF","stream.push() after EOF");Kc("ERR_METHOD_NOT_IMPLEMENTED",function(t){return"The "+t+" method is not implemented"});Kc("ERR_STREAM_PREMATURE_CLOSE","Premature close");Kc("ERR_STREAM_DESTROYED",function(t){return"Cannot call "+t+" after a stream was destroyed"});Kc("ERR_MULTIPLE_CALLBACK","Callback called multiple times");Kc("ERR_STREAM_CANNOT_PIPE","Cannot pipe, not readable");Kc("ERR_STREAM_WRITE_AFTER_END","write after end");Kc("ERR_STREAM_NULL_VALUES","May not write null values to stream",TypeError);Kc("ERR_UNKNOWN_ENCODING",function(t){return"Unknown encoding: "+t},TypeError);Kc("ERR_STREAM_UNSHIFT_AFTER_END_EVENT","stream.unshift() after end event");uve.exports.codes=cve});var qY=_((qtr,fve)=>{"use strict";var Qmt=lg().codes.ERR_INVALID_OPT_VALUE;function Tmt(t,e,r){return t.highWaterMark!=null?t.highWaterMark:e?t[r]:null}function Rmt(t,e,r,s){var a=Tmt(e,s,r);if(a!=null){if(!(isFinite(a)&&Math.floor(a)===a)||a<0){var n=s?r:"highWaterMark";throw new Qmt(n,a)}return Math.floor(a)}return t.objectMode?16:16*1024}fve.exports={getHighWaterMark:Rmt}});var Ave=_((Wtr,WY)=>{typeof Object.create=="function"?WY.exports=function(e,r){r&&(e.super_=r,e.prototype=Object.create(r.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}))}:WY.exports=function(e,r){if(r){e.super_=r;var s=function(){};s.prototype=r.prototype,e.prototype=new s,e.prototype.constructor=e}}});var cg=_((Ytr,VY)=>{try{if(YY=Ie("util"),typeof YY.inherits!="function")throw"";VY.exports=YY.inherits}catch{VY.exports=Ave()}var YY});var hve=_((Vtr,pve)=>{pve.exports=Ie("util").deprecate});var zY=_((Jtr,Ive)=>{"use strict";Ive.exports=Vi;function dve(t){var e=this;this.next=null,this.entry=null,this.finish=function(){oyt(e,t)}}var Tw;Vi.WritableState=ZD;var Fmt={deprecate:hve()},mve=_Y(),dN=Ie("buffer").Buffer,Nmt=global.Uint8Array||function(){};function Omt(t){return dN.from(t)}function Lmt(t){return dN.isBuffer(t)||t instanceof Nmt}var KY=GY(),Mmt=qY(),Umt=Mmt.getHighWaterMark,ug=lg().codes,_mt=ug.ERR_INVALID_ARG_TYPE,Hmt=ug.ERR_METHOD_NOT_IMPLEMENTED,jmt=ug.ERR_MULTIPLE_CALLBACK,Gmt=ug.ERR_STREAM_CANNOT_PIPE,qmt=ug.ERR_STREAM_DESTROYED,Wmt=ug.ERR_STREAM_NULL_VALUES,Ymt=ug.ERR_STREAM_WRITE_AFTER_END,Vmt=ug.ERR_UNKNOWN_ENCODING,Rw=KY.errorOrDestroy;cg()(Vi,mve);function Jmt(){}function ZD(t,e,r){Tw=Tw||Ym(),t=t||{},typeof r!="boolean"&&(r=e instanceof Tw),this.objectMode=!!t.objectMode,r&&(this.objectMode=this.objectMode||!!t.writableObjectMode),this.highWaterMark=Umt(this,t,"writableHighWaterMark",r),this.finalCalled=!1,this.needDrain=!1,this.ending=!1,this.ended=!1,this.finished=!1,this.destroyed=!1;var s=t.decodeStrings===!1;this.decodeStrings=!s,this.defaultEncoding=t.defaultEncoding||"utf8",this.length=0,this.writing=!1,this.corked=0,this.sync=!0,this.bufferProcessing=!1,this.onwrite=function(a){tyt(e,a)},this.writecb=null,this.writelen=0,this.bufferedRequest=null,this.lastBufferedRequest=null,this.pendingcb=0,this.prefinished=!1,this.errorEmitted=!1,this.emitClose=t.emitClose!==!1,this.autoDestroy=!!t.autoDestroy,this.bufferedRequestCount=0,this.corkedRequestsFree=new dve(this)}ZD.prototype.getBuffer=function(){for(var e=this.bufferedRequest,r=[];e;)r.push(e),e=e.next;return r};(function(){try{Object.defineProperty(ZD.prototype,"buffer",{get:Fmt.deprecate(function(){return this.getBuffer()},"_writableState.buffer is deprecated. Use _writableState.getBuffer instead.","DEP0003")})}catch{}})();var gN;typeof Symbol=="function"&&Symbol.hasInstance&&typeof Function.prototype[Symbol.hasInstance]=="function"?(gN=Function.prototype[Symbol.hasInstance],Object.defineProperty(Vi,Symbol.hasInstance,{value:function(e){return gN.call(this,e)?!0:this!==Vi?!1:e&&e._writableState instanceof ZD}})):gN=function(e){return e instanceof this};function Vi(t){Tw=Tw||Ym();var e=this instanceof Tw;if(!e&&!gN.call(Vi,this))return new Vi(t);this._writableState=new ZD(t,this,e),this.writable=!0,t&&(typeof t.write=="function"&&(this._write=t.write),typeof t.writev=="function"&&(this._writev=t.writev),typeof t.destroy=="function"&&(this._destroy=t.destroy),typeof t.final=="function"&&(this._final=t.final)),mve.call(this)}Vi.prototype.pipe=function(){Rw(this,new Gmt)};function Kmt(t,e){var r=new Ymt;Rw(t,r),process.nextTick(e,r)}function zmt(t,e,r,s){var a;return r===null?a=new Wmt:typeof r!="string"&&!e.objectMode&&(a=new _mt("chunk",["string","Buffer"],r)),a?(Rw(t,a),process.nextTick(s,a),!1):!0}Vi.prototype.write=function(t,e,r){var s=this._writableState,a=!1,n=!s.objectMode&&Lmt(t);return n&&!dN.isBuffer(t)&&(t=Omt(t)),typeof e=="function"&&(r=e,e=null),n?e="buffer":e||(e=s.defaultEncoding),typeof r!="function"&&(r=Jmt),s.ending?Kmt(this,r):(n||zmt(this,s,t,r))&&(s.pendingcb++,a=Zmt(this,s,n,t,e,r)),a};Vi.prototype.cork=function(){this._writableState.corked++};Vi.prototype.uncork=function(){var t=this._writableState;t.corked&&(t.corked--,!t.writing&&!t.corked&&!t.bufferProcessing&&t.bufferedRequest&&yve(this,t))};Vi.prototype.setDefaultEncoding=function(e){if(typeof e=="string"&&(e=e.toLowerCase()),!(["hex","utf8","utf-8","ascii","binary","base64","ucs2","ucs-2","utf16le","utf-16le","raw"].indexOf((e+"").toLowerCase())>-1))throw new Vmt(e);return this._writableState.defaultEncoding=e,this};Object.defineProperty(Vi.prototype,"writableBuffer",{enumerable:!1,get:function(){return this._writableState&&this._writableState.getBuffer()}});function Xmt(t,e,r){return!t.objectMode&&t.decodeStrings!==!1&&typeof e=="string"&&(e=dN.from(e,r)),e}Object.defineProperty(Vi.prototype,"writableHighWaterMark",{enumerable:!1,get:function(){return this._writableState.highWaterMark}});function Zmt(t,e,r,s,a,n){if(!r){var c=Xmt(e,s,a);s!==c&&(r=!0,a="buffer",s=c)}var f=e.objectMode?1:s.length;e.length+=f;var p=e.length{"use strict";var ayt=Object.keys||function(t){var e=[];for(var r in t)e.push(r);return e};wve.exports=dA;var Cve=$Y(),ZY=zY();cg()(dA,Cve);for(XY=ayt(ZY.prototype),mN=0;mN{var EN=Ie("buffer"),ah=EN.Buffer;function Bve(t,e){for(var r in t)e[r]=t[r]}ah.from&&ah.alloc&&ah.allocUnsafe&&ah.allocUnsafeSlow?vve.exports=EN:(Bve(EN,eV),eV.Buffer=Fw);function Fw(t,e,r){return ah(t,e,r)}Bve(ah,Fw);Fw.from=function(t,e,r){if(typeof t=="number")throw new TypeError("Argument must not be a number");return ah(t,e,r)};Fw.alloc=function(t,e,r){if(typeof t!="number")throw new TypeError("Argument must be a number");var s=ah(t);return e!==void 0?typeof r=="string"?s.fill(e,r):s.fill(e):s.fill(0),s};Fw.allocUnsafe=function(t){if(typeof t!="number")throw new TypeError("Argument must be a number");return ah(t)};Fw.allocUnsafeSlow=function(t){if(typeof t!="number")throw new TypeError("Argument must be a number");return EN.SlowBuffer(t)}});var nV=_(bve=>{"use strict";var rV=Sve().Buffer,Dve=rV.isEncoding||function(t){switch(t=""+t,t&&t.toLowerCase()){case"hex":case"utf8":case"utf-8":case"ascii":case"binary":case"base64":case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":case"raw":return!0;default:return!1}};function uyt(t){if(!t)return"utf8";for(var e;;)switch(t){case"utf8":case"utf-8":return"utf8";case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return"utf16le";case"latin1":case"binary":return"latin1";case"base64":case"ascii":case"hex":return t;default:if(e)return;t=(""+t).toLowerCase(),e=!0}}function fyt(t){var e=uyt(t);if(typeof e!="string"&&(rV.isEncoding===Dve||!Dve(t)))throw new Error("Unknown encoding: "+t);return e||t}bve.StringDecoder=$D;function $D(t){this.encoding=fyt(t);var e;switch(this.encoding){case"utf16le":this.text=myt,this.end=yyt,e=4;break;case"utf8":this.fillLast=hyt,e=4;break;case"base64":this.text=Eyt,this.end=Iyt,e=3;break;default:this.write=Cyt,this.end=wyt;return}this.lastNeed=0,this.lastTotal=0,this.lastChar=rV.allocUnsafe(e)}$D.prototype.write=function(t){if(t.length===0)return"";var e,r;if(this.lastNeed){if(e=this.fillLast(t),e===void 0)return"";r=this.lastNeed,this.lastNeed=0}else r=0;return r>5===6?2:t>>4===14?3:t>>3===30?4:t>>6===2?-1:-2}function Ayt(t,e,r){var s=e.length-1;if(s=0?(a>0&&(t.lastNeed=a-1),a):--s=0?(a>0&&(t.lastNeed=a-2),a):--s=0?(a>0&&(a===2?a=0:t.lastNeed=a-3),a):0))}function pyt(t,e,r){if((e[0]&192)!==128)return t.lastNeed=0,"\uFFFD";if(t.lastNeed>1&&e.length>1){if((e[1]&192)!==128)return t.lastNeed=1,"\uFFFD";if(t.lastNeed>2&&e.length>2&&(e[2]&192)!==128)return t.lastNeed=2,"\uFFFD"}}function hyt(t){var e=this.lastTotal-this.lastNeed,r=pyt(this,t,e);if(r!==void 0)return r;if(this.lastNeed<=t.length)return t.copy(this.lastChar,e,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal);t.copy(this.lastChar,e,0,t.length),this.lastNeed-=t.length}function gyt(t,e){var r=Ayt(this,t,e);if(!this.lastNeed)return t.toString("utf8",e);this.lastTotal=r;var s=t.length-(r-this.lastNeed);return t.copy(this.lastChar,0,s),t.toString("utf8",e,s)}function dyt(t){var e=t&&t.length?this.write(t):"";return this.lastNeed?e+"\uFFFD":e}function myt(t,e){if((t.length-e)%2===0){var r=t.toString("utf16le",e);if(r){var s=r.charCodeAt(r.length-1);if(s>=55296&&s<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=t[t.length-2],this.lastChar[1]=t[t.length-1],r.slice(0,-1)}return r}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=t[t.length-1],t.toString("utf16le",e,t.length-1)}function yyt(t){var e=t&&t.length?this.write(t):"";if(this.lastNeed){var r=this.lastTotal-this.lastNeed;return e+this.lastChar.toString("utf16le",0,r)}return e}function Eyt(t,e){var r=(t.length-e)%3;return r===0?t.toString("base64",e):(this.lastNeed=3-r,this.lastTotal=3,r===1?this.lastChar[0]=t[t.length-1]:(this.lastChar[0]=t[t.length-2],this.lastChar[1]=t[t.length-1]),t.toString("base64",e,t.length-r))}function Iyt(t){var e=t&&t.length?this.write(t):"";return this.lastNeed?e+this.lastChar.toString("base64",0,3-this.lastNeed):e}function Cyt(t){return t.toString(this.encoding)}function wyt(t){return t&&t.length?this.write(t):""}});var IN=_((Xtr,kve)=>{"use strict";var Pve=lg().codes.ERR_STREAM_PREMATURE_CLOSE;function Byt(t){var e=!1;return function(){if(!e){e=!0;for(var r=arguments.length,s=new Array(r),a=0;a{"use strict";var CN;function fg(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Dyt=IN(),Ag=Symbol("lastResolve"),Vm=Symbol("lastReject"),eb=Symbol("error"),wN=Symbol("ended"),Jm=Symbol("lastPromise"),iV=Symbol("handlePromise"),Km=Symbol("stream");function pg(t,e){return{value:t,done:e}}function byt(t){var e=t[Ag];if(e!==null){var r=t[Km].read();r!==null&&(t[Jm]=null,t[Ag]=null,t[Vm]=null,e(pg(r,!1)))}}function Pyt(t){process.nextTick(byt,t)}function xyt(t,e){return function(r,s){t.then(function(){if(e[wN]){r(pg(void 0,!0));return}e[iV](r,s)},s)}}var kyt=Object.getPrototypeOf(function(){}),Qyt=Object.setPrototypeOf((CN={get stream(){return this[Km]},next:function(){var e=this,r=this[eb];if(r!==null)return Promise.reject(r);if(this[wN])return Promise.resolve(pg(void 0,!0));if(this[Km].destroyed)return new Promise(function(c,f){process.nextTick(function(){e[eb]?f(e[eb]):c(pg(void 0,!0))})});var s=this[Jm],a;if(s)a=new Promise(xyt(s,this));else{var n=this[Km].read();if(n!==null)return Promise.resolve(pg(n,!1));a=new Promise(this[iV])}return this[Jm]=a,a}},fg(CN,Symbol.asyncIterator,function(){return this}),fg(CN,"return",function(){var e=this;return new Promise(function(r,s){e[Km].destroy(null,function(a){if(a){s(a);return}r(pg(void 0,!0))})})}),CN),kyt),Tyt=function(e){var r,s=Object.create(Qyt,(r={},fg(r,Km,{value:e,writable:!0}),fg(r,Ag,{value:null,writable:!0}),fg(r,Vm,{value:null,writable:!0}),fg(r,eb,{value:null,writable:!0}),fg(r,wN,{value:e._readableState.endEmitted,writable:!0}),fg(r,iV,{value:function(n,c){var f=s[Km].read();f?(s[Jm]=null,s[Ag]=null,s[Vm]=null,n(pg(f,!1))):(s[Ag]=n,s[Vm]=c)},writable:!0}),r));return s[Jm]=null,Dyt(e,function(a){if(a&&a.code!=="ERR_STREAM_PREMATURE_CLOSE"){var n=s[Vm];n!==null&&(s[Jm]=null,s[Ag]=null,s[Vm]=null,n(a)),s[eb]=a;return}var c=s[Ag];c!==null&&(s[Jm]=null,s[Ag]=null,s[Vm]=null,c(pg(void 0,!0))),s[wN]=!0}),e.on("readable",Pyt.bind(null,s)),s};Qve.exports=Tyt});var Ove=_(($tr,Nve)=>{"use strict";function Rve(t,e,r,s,a,n,c){try{var f=t[n](c),p=f.value}catch(h){r(h);return}f.done?e(p):Promise.resolve(p).then(s,a)}function Ryt(t){return function(){var e=this,r=arguments;return new Promise(function(s,a){var n=t.apply(e,r);function c(p){Rve(n,s,a,c,f,"next",p)}function f(p){Rve(n,s,a,c,f,"throw",p)}c(void 0)})}}function Fve(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(t);e&&(s=s.filter(function(a){return Object.getOwnPropertyDescriptor(t,a).enumerable})),r.push.apply(r,s)}return r}function Fyt(t){for(var e=1;e{"use strict";Yve.exports=Pn;var Nw;Pn.ReadableState=_ve;var trr=Ie("events").EventEmitter,Uve=function(e,r){return e.listeners(r).length},rb=_Y(),BN=Ie("buffer").Buffer,Myt=global.Uint8Array||function(){};function Uyt(t){return BN.from(t)}function _yt(t){return BN.isBuffer(t)||t instanceof Myt}var sV=Ie("util"),cn;sV&&sV.debuglog?cn=sV.debuglog("stream"):cn=function(){};var Hyt=sve(),AV=GY(),jyt=qY(),Gyt=jyt.getHighWaterMark,vN=lg().codes,qyt=vN.ERR_INVALID_ARG_TYPE,Wyt=vN.ERR_STREAM_PUSH_AFTER_EOF,Yyt=vN.ERR_METHOD_NOT_IMPLEMENTED,Vyt=vN.ERR_STREAM_UNSHIFT_AFTER_END_EVENT,Ow,oV,aV;cg()(Pn,rb);var tb=AV.errorOrDestroy,lV=["error","close","destroy","pause","resume"];function Jyt(t,e,r){if(typeof t.prependListener=="function")return t.prependListener(e,r);!t._events||!t._events[e]?t.on(e,r):Array.isArray(t._events[e])?t._events[e].unshift(r):t._events[e]=[r,t._events[e]]}function _ve(t,e,r){Nw=Nw||Ym(),t=t||{},typeof r!="boolean"&&(r=e instanceof Nw),this.objectMode=!!t.objectMode,r&&(this.objectMode=this.objectMode||!!t.readableObjectMode),this.highWaterMark=Gyt(this,t,"readableHighWaterMark",r),this.buffer=new Hyt,this.length=0,this.pipes=null,this.pipesCount=0,this.flowing=null,this.ended=!1,this.endEmitted=!1,this.reading=!1,this.sync=!0,this.needReadable=!1,this.emittedReadable=!1,this.readableListening=!1,this.resumeScheduled=!1,this.paused=!0,this.emitClose=t.emitClose!==!1,this.autoDestroy=!!t.autoDestroy,this.destroyed=!1,this.defaultEncoding=t.defaultEncoding||"utf8",this.awaitDrain=0,this.readingMore=!1,this.decoder=null,this.encoding=null,t.encoding&&(Ow||(Ow=nV().StringDecoder),this.decoder=new Ow(t.encoding),this.encoding=t.encoding)}function Pn(t){if(Nw=Nw||Ym(),!(this instanceof Pn))return new Pn(t);var e=this instanceof Nw;this._readableState=new _ve(t,this,e),this.readable=!0,t&&(typeof t.read=="function"&&(this._read=t.read),typeof t.destroy=="function"&&(this._destroy=t.destroy)),rb.call(this)}Object.defineProperty(Pn.prototype,"destroyed",{enumerable:!1,get:function(){return this._readableState===void 0?!1:this._readableState.destroyed},set:function(e){this._readableState&&(this._readableState.destroyed=e)}});Pn.prototype.destroy=AV.destroy;Pn.prototype._undestroy=AV.undestroy;Pn.prototype._destroy=function(t,e){e(t)};Pn.prototype.push=function(t,e){var r=this._readableState,s;return r.objectMode?s=!0:typeof t=="string"&&(e=e||r.defaultEncoding,e!==r.encoding&&(t=BN.from(t,e),e=""),s=!0),Hve(this,t,e,!1,s)};Pn.prototype.unshift=function(t){return Hve(this,t,null,!0,!1)};function Hve(t,e,r,s,a){cn("readableAddChunk",e);var n=t._readableState;if(e===null)n.reading=!1,Xyt(t,n);else{var c;if(a||(c=Kyt(n,e)),c)tb(t,c);else if(n.objectMode||e&&e.length>0)if(typeof e!="string"&&!n.objectMode&&Object.getPrototypeOf(e)!==BN.prototype&&(e=Uyt(e)),s)n.endEmitted?tb(t,new Vyt):cV(t,n,e,!0);else if(n.ended)tb(t,new Wyt);else{if(n.destroyed)return!1;n.reading=!1,n.decoder&&!r?(e=n.decoder.write(e),n.objectMode||e.length!==0?cV(t,n,e,!1):fV(t,n)):cV(t,n,e,!1)}else s||(n.reading=!1,fV(t,n))}return!n.ended&&(n.length=Lve?t=Lve:(t--,t|=t>>>1,t|=t>>>2,t|=t>>>4,t|=t>>>8,t|=t>>>16,t++),t}function Mve(t,e){return t<=0||e.length===0&&e.ended?0:e.objectMode?1:t!==t?e.flowing&&e.length?e.buffer.head.data.length:e.length:(t>e.highWaterMark&&(e.highWaterMark=zyt(t)),t<=e.length?t:e.ended?e.length:(e.needReadable=!0,0))}Pn.prototype.read=function(t){cn("read",t),t=parseInt(t,10);var e=this._readableState,r=t;if(t!==0&&(e.emittedReadable=!1),t===0&&e.needReadable&&((e.highWaterMark!==0?e.length>=e.highWaterMark:e.length>0)||e.ended))return cn("read: emitReadable",e.length,e.ended),e.length===0&&e.ended?uV(this):SN(this),null;if(t=Mve(t,e),t===0&&e.ended)return e.length===0&&uV(this),null;var s=e.needReadable;cn("need readable",s),(e.length===0||e.length-t0?a=qve(t,e):a=null,a===null?(e.needReadable=e.length<=e.highWaterMark,t=0):(e.length-=t,e.awaitDrain=0),e.length===0&&(e.ended||(e.needReadable=!0),r!==t&&e.ended&&uV(this)),a!==null&&this.emit("data",a),a};function Xyt(t,e){if(cn("onEofChunk"),!e.ended){if(e.decoder){var r=e.decoder.end();r&&r.length&&(e.buffer.push(r),e.length+=e.objectMode?1:r.length)}e.ended=!0,e.sync?SN(t):(e.needReadable=!1,e.emittedReadable||(e.emittedReadable=!0,jve(t)))}}function SN(t){var e=t._readableState;cn("emitReadable",e.needReadable,e.emittedReadable),e.needReadable=!1,e.emittedReadable||(cn("emitReadable",e.flowing),e.emittedReadable=!0,process.nextTick(jve,t))}function jve(t){var e=t._readableState;cn("emitReadable_",e.destroyed,e.length,e.ended),!e.destroyed&&(e.length||e.ended)&&(t.emit("readable"),e.emittedReadable=!1),e.needReadable=!e.flowing&&!e.ended&&e.length<=e.highWaterMark,pV(t)}function fV(t,e){e.readingMore||(e.readingMore=!0,process.nextTick(Zyt,t,e))}function Zyt(t,e){for(;!e.reading&&!e.ended&&(e.length1&&Wve(s.pipes,t)!==-1)&&!h&&(cn("false write response, pause",s.awaitDrain),s.awaitDrain++),r.pause())}function S(N){cn("onerror",N),R(),t.removeListener("error",S),Uve(t,"error")===0&&tb(t,N)}Jyt(t,"error",S);function P(){t.removeListener("finish",I),R()}t.once("close",P);function I(){cn("onfinish"),t.removeListener("close",P),R()}t.once("finish",I);function R(){cn("unpipe"),r.unpipe(t)}return t.emit("pipe",r),s.flowing||(cn("pipe resume"),r.resume()),t};function $yt(t){return function(){var r=t._readableState;cn("pipeOnDrain",r.awaitDrain),r.awaitDrain&&r.awaitDrain--,r.awaitDrain===0&&Uve(t,"data")&&(r.flowing=!0,pV(t))}}Pn.prototype.unpipe=function(t){var e=this._readableState,r={hasUnpiped:!1};if(e.pipesCount===0)return this;if(e.pipesCount===1)return t&&t!==e.pipes?this:(t||(t=e.pipes),e.pipes=null,e.pipesCount=0,e.flowing=!1,t&&t.emit("unpipe",this,r),this);if(!t){var s=e.pipes,a=e.pipesCount;e.pipes=null,e.pipesCount=0,e.flowing=!1;for(var n=0;n0,s.flowing!==!1&&this.resume()):t==="readable"&&!s.endEmitted&&!s.readableListening&&(s.readableListening=s.needReadable=!0,s.flowing=!1,s.emittedReadable=!1,cn("on readable",s.length,s.reading),s.length?SN(this):s.reading||process.nextTick(eEt,this)),r};Pn.prototype.addListener=Pn.prototype.on;Pn.prototype.removeListener=function(t,e){var r=rb.prototype.removeListener.call(this,t,e);return t==="readable"&&process.nextTick(Gve,this),r};Pn.prototype.removeAllListeners=function(t){var e=rb.prototype.removeAllListeners.apply(this,arguments);return(t==="readable"||t===void 0)&&process.nextTick(Gve,this),e};function Gve(t){var e=t._readableState;e.readableListening=t.listenerCount("readable")>0,e.resumeScheduled&&!e.paused?e.flowing=!0:t.listenerCount("data")>0&&t.resume()}function eEt(t){cn("readable nexttick read 0"),t.read(0)}Pn.prototype.resume=function(){var t=this._readableState;return t.flowing||(cn("resume"),t.flowing=!t.readableListening,tEt(this,t)),t.paused=!1,this};function tEt(t,e){e.resumeScheduled||(e.resumeScheduled=!0,process.nextTick(rEt,t,e))}function rEt(t,e){cn("resume",e.reading),e.reading||t.read(0),e.resumeScheduled=!1,t.emit("resume"),pV(t),e.flowing&&!e.reading&&t.read(0)}Pn.prototype.pause=function(){return cn("call pause flowing=%j",this._readableState.flowing),this._readableState.flowing!==!1&&(cn("pause"),this._readableState.flowing=!1,this.emit("pause")),this._readableState.paused=!0,this};function pV(t){var e=t._readableState;for(cn("flow",e.flowing);e.flowing&&t.read()!==null;);}Pn.prototype.wrap=function(t){var e=this,r=this._readableState,s=!1;t.on("end",function(){if(cn("wrapped end"),r.decoder&&!r.ended){var c=r.decoder.end();c&&c.length&&e.push(c)}e.push(null)}),t.on("data",function(c){if(cn("wrapped data"),r.decoder&&(c=r.decoder.write(c)),!(r.objectMode&&c==null)&&!(!r.objectMode&&(!c||!c.length))){var f=e.push(c);f||(s=!0,t.pause())}});for(var a in t)this[a]===void 0&&typeof t[a]=="function"&&(this[a]=function(f){return function(){return t[f].apply(t,arguments)}}(a));for(var n=0;n=e.length?(e.decoder?r=e.buffer.join(""):e.buffer.length===1?r=e.buffer.first():r=e.buffer.concat(e.length),e.buffer.clear()):r=e.buffer.consume(t,e.decoder),r}function uV(t){var e=t._readableState;cn("endReadable",e.endEmitted),e.endEmitted||(e.ended=!0,process.nextTick(nEt,e,t))}function nEt(t,e){if(cn("endReadableNT",t.endEmitted,t.length),!t.endEmitted&&t.length===0&&(t.endEmitted=!0,e.readable=!1,e.emit("end"),t.autoDestroy)){var r=e._writableState;(!r||r.autoDestroy&&r.finished)&&e.destroy()}}typeof Symbol=="function"&&(Pn.from=function(t,e){return aV===void 0&&(aV=Ove()),aV(Pn,t,e)});function Wve(t,e){for(var r=0,s=t.length;r{"use strict";Jve.exports=lh;var DN=lg().codes,iEt=DN.ERR_METHOD_NOT_IMPLEMENTED,sEt=DN.ERR_MULTIPLE_CALLBACK,oEt=DN.ERR_TRANSFORM_ALREADY_TRANSFORMING,aEt=DN.ERR_TRANSFORM_WITH_LENGTH_0,bN=Ym();cg()(lh,bN);function lEt(t,e){var r=this._transformState;r.transforming=!1;var s=r.writecb;if(s===null)return this.emit("error",new sEt);r.writechunk=null,r.writecb=null,e!=null&&this.push(e),s(t);var a=this._readableState;a.reading=!1,(a.needReadable||a.length{"use strict";zve.exports=nb;var Kve=hV();cg()(nb,Kve);function nb(t){if(!(this instanceof nb))return new nb(t);Kve.call(this,t)}nb.prototype._transform=function(t,e,r){r(null,t)}});var rSe=_((srr,tSe)=>{"use strict";var gV;function uEt(t){var e=!1;return function(){e||(e=!0,t.apply(void 0,arguments))}}var eSe=lg().codes,fEt=eSe.ERR_MISSING_ARGS,AEt=eSe.ERR_STREAM_DESTROYED;function Zve(t){if(t)throw t}function pEt(t){return t.setHeader&&typeof t.abort=="function"}function hEt(t,e,r,s){s=uEt(s);var a=!1;t.on("close",function(){a=!0}),gV===void 0&&(gV=IN()),gV(t,{readable:e,writable:r},function(c){if(c)return s(c);a=!0,s()});var n=!1;return function(c){if(!a&&!n){if(n=!0,pEt(t))return t.abort();if(typeof t.destroy=="function")return t.destroy();s(c||new AEt("pipe"))}}}function $ve(t){t()}function gEt(t,e){return t.pipe(e)}function dEt(t){return!t.length||typeof t[t.length-1]!="function"?Zve:t.pop()}function mEt(){for(var t=arguments.length,e=new Array(t),r=0;r0;return hEt(c,p,h,function(E){a||(a=E),E&&n.forEach($ve),!p&&(n.forEach($ve),s(a))})});return e.reduce(gEt)}tSe.exports=mEt});var Lw=_((zc,sb)=>{var ib=Ie("stream");process.env.READABLE_STREAM==="disable"&&ib?(sb.exports=ib.Readable,Object.assign(sb.exports,ib),sb.exports.Stream=ib):(zc=sb.exports=$Y(),zc.Stream=ib||zc,zc.Readable=zc,zc.Writable=zY(),zc.Duplex=Ym(),zc.Transform=hV(),zc.PassThrough=Xve(),zc.finished=IN(),zc.pipeline=rSe())});var sSe=_((orr,iSe)=>{"use strict";var{Buffer:cf}=Ie("buffer"),nSe=Symbol.for("BufferList");function Ci(t){if(!(this instanceof Ci))return new Ci(t);Ci._init.call(this,t)}Ci._init=function(e){Object.defineProperty(this,nSe,{value:!0}),this._bufs=[],this.length=0,e&&this.append(e)};Ci.prototype._new=function(e){return new Ci(e)};Ci.prototype._offset=function(e){if(e===0)return[0,0];let r=0;for(let s=0;sthis.length||e<0)return;let r=this._offset(e);return this._bufs[r[0]][r[1]]};Ci.prototype.slice=function(e,r){return typeof e=="number"&&e<0&&(e+=this.length),typeof r=="number"&&r<0&&(r+=this.length),this.copy(null,0,e,r)};Ci.prototype.copy=function(e,r,s,a){if((typeof s!="number"||s<0)&&(s=0),(typeof a!="number"||a>this.length)&&(a=this.length),s>=this.length||a<=0)return e||cf.alloc(0);let n=!!e,c=this._offset(s),f=a-s,p=f,h=n&&r||0,E=c[1];if(s===0&&a===this.length){if(!n)return this._bufs.length===1?this._bufs[0]:cf.concat(this._bufs,this.length);for(let C=0;CS)this._bufs[C].copy(e,h,E),h+=S;else{this._bufs[C].copy(e,h,E,E+p),h+=S;break}p-=S,E&&(E=0)}return e.length>h?e.slice(0,h):e};Ci.prototype.shallowSlice=function(e,r){if(e=e||0,r=typeof r!="number"?this.length:r,e<0&&(e+=this.length),r<0&&(r+=this.length),e===r)return this._new();let s=this._offset(e),a=this._offset(r),n=this._bufs.slice(s[0],a[0]+1);return a[1]===0?n.pop():n[n.length-1]=n[n.length-1].slice(0,a[1]),s[1]!==0&&(n[0]=n[0].slice(s[1])),this._new(n)};Ci.prototype.toString=function(e,r,s){return this.slice(r,s).toString(e)};Ci.prototype.consume=function(e){if(e=Math.trunc(e),Number.isNaN(e)||e<=0)return this;for(;this._bufs.length;)if(e>=this._bufs[0].length)e-=this._bufs[0].length,this.length-=this._bufs[0].length,this._bufs.shift();else{this._bufs[0]=this._bufs[0].slice(e),this.length-=e;break}return this};Ci.prototype.duplicate=function(){let e=this._new();for(let r=0;rthis.length?this.length:e;let s=this._offset(e),a=s[0],n=s[1];for(;a=t.length){let p=c.indexOf(t,n);if(p!==-1)return this._reverseOffset([a,p]);n=c.length-t.length+1}else{let p=this._reverseOffset([a,n]);if(this._match(p,t))return p;n++}n=0}return-1};Ci.prototype._match=function(t,e){if(this.length-t{"use strict";var dV=Lw().Duplex,yEt=cg(),ob=sSe();function ra(t){if(!(this instanceof ra))return new ra(t);if(typeof t=="function"){this._callback=t;let e=function(s){this._callback&&(this._callback(s),this._callback=null)}.bind(this);this.on("pipe",function(s){s.on("error",e)}),this.on("unpipe",function(s){s.removeListener("error",e)}),t=null}ob._init.call(this,t),dV.call(this)}yEt(ra,dV);Object.assign(ra.prototype,ob.prototype);ra.prototype._new=function(e){return new ra(e)};ra.prototype._write=function(e,r,s){this._appendBuffer(e),typeof s=="function"&&s()};ra.prototype._read=function(e){if(!this.length)return this.push(null);e=Math.min(e,this.length),this.push(this.slice(0,e)),this.consume(e)};ra.prototype.end=function(e){dV.prototype.end.call(this,e),this._callback&&(this._callback(null,this.slice()),this._callback=null)};ra.prototype._destroy=function(e,r){this._bufs.length=0,this.length=0,r(e)};ra.prototype._isBufferList=function(e){return e instanceof ra||e instanceof ob||ra.isBufferList(e)};ra.isBufferList=ob.isBufferList;PN.exports=ra;PN.exports.BufferListStream=ra;PN.exports.BufferList=ob});var EV=_(Uw=>{var EEt=Buffer.alloc,IEt="0000000000000000000",CEt="7777777777777777777",aSe=48,lSe=Buffer.from("ustar\0","binary"),wEt=Buffer.from("00","binary"),BEt=Buffer.from("ustar ","binary"),vEt=Buffer.from(" \0","binary"),SEt=parseInt("7777",8),ab=257,yV=263,DEt=function(t,e,r){return typeof t!="number"?r:(t=~~t,t>=e?e:t>=0||(t+=e,t>=0)?t:0)},bEt=function(t){switch(t){case 0:return"file";case 1:return"link";case 2:return"symlink";case 3:return"character-device";case 4:return"block-device";case 5:return"directory";case 6:return"fifo";case 7:return"contiguous-file";case 72:return"pax-header";case 55:return"pax-global-header";case 27:return"gnu-long-link-path";case 28:case 30:return"gnu-long-path"}return null},PEt=function(t){switch(t){case"file":return 0;case"link":return 1;case"symlink":return 2;case"character-device":return 3;case"block-device":return 4;case"directory":return 5;case"fifo":return 6;case"contiguous-file":return 7;case"pax-header":return 72}return 0},cSe=function(t,e,r,s){for(;re?CEt.slice(0,e)+" ":IEt.slice(0,e-t.length)+t+" "};function xEt(t){var e;if(t[0]===128)e=!0;else if(t[0]===255)e=!1;else return null;for(var r=[],s=t.length-1;s>0;s--){var a=t[s];e?r.push(a):r.push(255-a)}var n=0,c=r.length;for(s=0;s=Math.pow(10,r)&&r++,e+r+t};Uw.decodeLongPath=function(t,e){return Mw(t,0,t.length,e)};Uw.encodePax=function(t){var e="";t.name&&(e+=mV(" path="+t.name+` +`)),t.linkname&&(e+=mV(" linkpath="+t.linkname+` +`));var r=t.pax;if(r)for(var s in r)e+=mV(" "+s+"="+r[s]+` +`);return Buffer.from(e)};Uw.decodePax=function(t){for(var e={};t.length;){for(var r=0;r100;){var a=r.indexOf("/");if(a===-1)return null;s+=s?"/"+r.slice(0,a):r.slice(0,a),r=r.slice(a+1)}return Buffer.byteLength(r)>100||Buffer.byteLength(s)>155||t.linkname&&Buffer.byteLength(t.linkname)>100?null:(e.write(r),e.write(hg(t.mode&SEt,6),100),e.write(hg(t.uid,6),108),e.write(hg(t.gid,6),116),e.write(hg(t.size,11),124),e.write(hg(t.mtime.getTime()/1e3|0,11),136),e[156]=aSe+PEt(t.type),t.linkname&&e.write(t.linkname,157),lSe.copy(e,ab),wEt.copy(e,yV),t.uname&&e.write(t.uname,265),t.gname&&e.write(t.gname,297),e.write(hg(t.devmajor||0,6),329),e.write(hg(t.devminor||0,6),337),s&&e.write(s,345),e.write(hg(uSe(e),6),148),e)};Uw.decode=function(t,e,r){var s=t[156]===0?0:t[156]-aSe,a=Mw(t,0,100,e),n=gg(t,100,8),c=gg(t,108,8),f=gg(t,116,8),p=gg(t,124,12),h=gg(t,136,12),E=bEt(s),C=t[157]===0?null:Mw(t,157,100,e),S=Mw(t,265,32),P=Mw(t,297,32),I=gg(t,329,8),R=gg(t,337,8),N=uSe(t);if(N===8*32)return null;if(N!==gg(t,148,8))throw new Error("Invalid tar header. Maybe the tar is corrupted or it needs to be gunzipped?");if(lSe.compare(t,ab,ab+6)===0)t[345]&&(a=Mw(t,345,155,e)+"/"+a);else if(!(BEt.compare(t,ab,ab+6)===0&&vEt.compare(t,yV,yV+2)===0)){if(!r)throw new Error("Invalid tar header: unknown format.")}return s===0&&a&&a[a.length-1]==="/"&&(s=5),{name:a,mode:n,uid:c,gid:f,size:p,mtime:new Date(1e3*h),type:E,linkname:C,uname:S,gname:P,devmajor:I,devminor:R}}});var mSe=_((crr,dSe)=>{var ASe=Ie("util"),kEt=oSe(),lb=EV(),pSe=Lw().Writable,hSe=Lw().PassThrough,gSe=function(){},fSe=function(t){return t&=511,t&&512-t},QEt=function(t,e){var r=new xN(t,e);return r.end(),r},TEt=function(t,e){return e.path&&(t.name=e.path),e.linkpath&&(t.linkname=e.linkpath),e.size&&(t.size=parseInt(e.size,10)),t.pax=e,t},xN=function(t,e){this._parent=t,this.offset=e,hSe.call(this,{autoDestroy:!1})};ASe.inherits(xN,hSe);xN.prototype.destroy=function(t){this._parent.destroy(t)};var ch=function(t){if(!(this instanceof ch))return new ch(t);pSe.call(this,t),t=t||{},this._offset=0,this._buffer=kEt(),this._missing=0,this._partial=!1,this._onparse=gSe,this._header=null,this._stream=null,this._overflow=null,this._cb=null,this._locked=!1,this._destroyed=!1,this._pax=null,this._paxGlobal=null,this._gnuLongPath=null,this._gnuLongLinkPath=null;var e=this,r=e._buffer,s=function(){e._continue()},a=function(S){if(e._locked=!1,S)return e.destroy(S);e._stream||s()},n=function(){e._stream=null;var S=fSe(e._header.size);S?e._parse(S,c):e._parse(512,C),e._locked||s()},c=function(){e._buffer.consume(fSe(e._header.size)),e._parse(512,C),s()},f=function(){var S=e._header.size;e._paxGlobal=lb.decodePax(r.slice(0,S)),r.consume(S),n()},p=function(){var S=e._header.size;e._pax=lb.decodePax(r.slice(0,S)),e._paxGlobal&&(e._pax=Object.assign({},e._paxGlobal,e._pax)),r.consume(S),n()},h=function(){var S=e._header.size;this._gnuLongPath=lb.decodeLongPath(r.slice(0,S),t.filenameEncoding),r.consume(S),n()},E=function(){var S=e._header.size;this._gnuLongLinkPath=lb.decodeLongPath(r.slice(0,S),t.filenameEncoding),r.consume(S),n()},C=function(){var S=e._offset,P;try{P=e._header=lb.decode(r.slice(0,512),t.filenameEncoding,t.allowUnknownFormat)}catch(I){e.emit("error",I)}if(r.consume(512),!P){e._parse(512,C),s();return}if(P.type==="gnu-long-path"){e._parse(P.size,h),s();return}if(P.type==="gnu-long-link-path"){e._parse(P.size,E),s();return}if(P.type==="pax-global-header"){e._parse(P.size,f),s();return}if(P.type==="pax-header"){e._parse(P.size,p),s();return}if(e._gnuLongPath&&(P.name=e._gnuLongPath,e._gnuLongPath=null),e._gnuLongLinkPath&&(P.linkname=e._gnuLongLinkPath,e._gnuLongLinkPath=null),e._pax&&(e._header=P=TEt(P,e._pax),e._pax=null),e._locked=!0,!P.size||P.type==="directory"){e._parse(512,C),e.emit("entry",P,QEt(e,S),a);return}e._stream=new xN(e,S),e.emit("entry",P,e._stream,a),e._parse(P.size,n),s()};this._onheader=C,this._parse(512,C)};ASe.inherits(ch,pSe);ch.prototype.destroy=function(t){this._destroyed||(this._destroyed=!0,t&&this.emit("error",t),this.emit("close"),this._stream&&this._stream.emit("close"))};ch.prototype._parse=function(t,e){this._destroyed||(this._offset+=t,this._missing=t,e===this._onheader&&(this._partial=!1),this._onparse=e)};ch.prototype._continue=function(){if(!this._destroyed){var t=this._cb;this._cb=gSe,this._overflow?this._write(this._overflow,void 0,t):t()}};ch.prototype._write=function(t,e,r){if(!this._destroyed){var s=this._stream,a=this._buffer,n=this._missing;if(t.length&&(this._partial=!0),t.lengthn&&(c=t.slice(n),t=t.slice(0,n)),s?s.end(t):a.append(t),this._overflow=c,this._onparse()}};ch.prototype._final=function(t){if(this._partial)return this.destroy(new Error("Unexpected end of data"));t()};dSe.exports=ch});var ESe=_((urr,ySe)=>{ySe.exports=Ie("fs").constants||Ie("constants")});var vSe=_((frr,BSe)=>{var _w=ESe(),ISe=cH(),QN=cg(),REt=Buffer.alloc,CSe=Lw().Readable,Hw=Lw().Writable,FEt=Ie("string_decoder").StringDecoder,kN=EV(),NEt=parseInt("755",8),OEt=parseInt("644",8),wSe=REt(1024),CV=function(){},IV=function(t,e){e&=511,e&&t.push(wSe.slice(0,512-e))};function LEt(t){switch(t&_w.S_IFMT){case _w.S_IFBLK:return"block-device";case _w.S_IFCHR:return"character-device";case _w.S_IFDIR:return"directory";case _w.S_IFIFO:return"fifo";case _w.S_IFLNK:return"symlink"}return"file"}var TN=function(t){Hw.call(this),this.written=0,this._to=t,this._destroyed=!1};QN(TN,Hw);TN.prototype._write=function(t,e,r){if(this.written+=t.length,this._to.push(t))return r();this._to._drain=r};TN.prototype.destroy=function(){this._destroyed||(this._destroyed=!0,this.emit("close"))};var RN=function(){Hw.call(this),this.linkname="",this._decoder=new FEt("utf-8"),this._destroyed=!1};QN(RN,Hw);RN.prototype._write=function(t,e,r){this.linkname+=this._decoder.write(t),r()};RN.prototype.destroy=function(){this._destroyed||(this._destroyed=!0,this.emit("close"))};var ub=function(){Hw.call(this),this._destroyed=!1};QN(ub,Hw);ub.prototype._write=function(t,e,r){r(new Error("No body allowed for this entry"))};ub.prototype.destroy=function(){this._destroyed||(this._destroyed=!0,this.emit("close"))};var mA=function(t){if(!(this instanceof mA))return new mA(t);CSe.call(this,t),this._drain=CV,this._finalized=!1,this._finalizing=!1,this._destroyed=!1,this._stream=null};QN(mA,CSe);mA.prototype.entry=function(t,e,r){if(this._stream)throw new Error("already piping an entry");if(!(this._finalized||this._destroyed)){typeof e=="function"&&(r=e,e=null),r||(r=CV);var s=this;if((!t.size||t.type==="symlink")&&(t.size=0),t.type||(t.type=LEt(t.mode)),t.mode||(t.mode=t.type==="directory"?NEt:OEt),t.uid||(t.uid=0),t.gid||(t.gid=0),t.mtime||(t.mtime=new Date),typeof e=="string"&&(e=Buffer.from(e)),Buffer.isBuffer(e)){t.size=e.length,this._encode(t);var a=this.push(e);return IV(s,t.size),a?process.nextTick(r):this._drain=r,new ub}if(t.type==="symlink"&&!t.linkname){var n=new RN;return ISe(n,function(f){if(f)return s.destroy(),r(f);t.linkname=n.linkname,s._encode(t),r()}),n}if(this._encode(t),t.type!=="file"&&t.type!=="contiguous-file")return process.nextTick(r),new ub;var c=new TN(this);return this._stream=c,ISe(c,function(f){if(s._stream=null,f)return s.destroy(),r(f);if(c.written!==t.size)return s.destroy(),r(new Error("size mismatch"));IV(s,t.size),s._finalizing&&s.finalize(),r()}),c}};mA.prototype.finalize=function(){if(this._stream){this._finalizing=!0;return}this._finalized||(this._finalized=!0,this.push(wSe),this.push(null))};mA.prototype.destroy=function(t){this._destroyed||(this._destroyed=!0,t&&this.emit("error",t),this.emit("close"),this._stream&&this._stream.destroy&&this._stream.destroy())};mA.prototype._encode=function(t){if(!t.pax){var e=kN.encode(t);if(e){this.push(e);return}}this._encodePax(t)};mA.prototype._encodePax=function(t){var e=kN.encodePax({name:t.name,linkname:t.linkname,pax:t.pax}),r={name:"PaxHeader",mode:t.mode,uid:t.uid,gid:t.gid,size:e.length,mtime:t.mtime,type:"pax-header",linkname:t.linkname&&"PaxHeader",uname:t.uname,gname:t.gname,devmajor:t.devmajor,devminor:t.devminor};this.push(kN.encode(r)),this.push(e),IV(this,e.length),r.size=t.size,r.type=t.type,this.push(kN.encode(r))};mA.prototype._read=function(t){var e=this._drain;this._drain=CV,e()};BSe.exports=mA});var SSe=_(wV=>{wV.extract=mSe();wV.pack=vSe()});var MSe=_(Ta=>{"use strict";var zEt=Ta&&Ta.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(Ta,"__esModule",{value:!0});Ta.Minipass=Ta.isWritable=Ta.isReadable=Ta.isStream=void 0;var RSe=typeof process=="object"&&process?process:{stdout:null,stderr:null},FV=Ie("node:events"),LSe=zEt(Ie("node:stream")),XEt=Ie("node:string_decoder"),ZEt=t=>!!t&&typeof t=="object"&&(t instanceof jN||t instanceof LSe.default||(0,Ta.isReadable)(t)||(0,Ta.isWritable)(t));Ta.isStream=ZEt;var $Et=t=>!!t&&typeof t=="object"&&t instanceof FV.EventEmitter&&typeof t.pipe=="function"&&t.pipe!==LSe.default.Writable.prototype.pipe;Ta.isReadable=$Et;var eIt=t=>!!t&&typeof t=="object"&&t instanceof FV.EventEmitter&&typeof t.write=="function"&&typeof t.end=="function";Ta.isWritable=eIt;var uh=Symbol("EOF"),fh=Symbol("maybeEmitEnd"),dg=Symbol("emittedEnd"),ON=Symbol("emittingEnd"),fb=Symbol("emittedError"),LN=Symbol("closed"),FSe=Symbol("read"),MN=Symbol("flush"),NSe=Symbol("flushChunk"),uf=Symbol("encoding"),Gw=Symbol("decoder"),Ks=Symbol("flowing"),Ab=Symbol("paused"),qw=Symbol("resume"),zs=Symbol("buffer"),Qa=Symbol("pipes"),Xs=Symbol("bufferLength"),PV=Symbol("bufferPush"),UN=Symbol("bufferShift"),na=Symbol("objectMode"),ts=Symbol("destroyed"),xV=Symbol("error"),kV=Symbol("emitData"),OSe=Symbol("emitEnd"),QV=Symbol("emitEnd2"),EA=Symbol("async"),TV=Symbol("abort"),_N=Symbol("aborted"),pb=Symbol("signal"),zm=Symbol("dataListeners"),rc=Symbol("discarded"),hb=t=>Promise.resolve().then(t),tIt=t=>t(),rIt=t=>t==="end"||t==="finish"||t==="prefinish",nIt=t=>t instanceof ArrayBuffer||!!t&&typeof t=="object"&&t.constructor&&t.constructor.name==="ArrayBuffer"&&t.byteLength>=0,iIt=t=>!Buffer.isBuffer(t)&&ArrayBuffer.isView(t),HN=class{src;dest;opts;ondrain;constructor(e,r,s){this.src=e,this.dest=r,this.opts=s,this.ondrain=()=>e[qw](),this.dest.on("drain",this.ondrain)}unpipe(){this.dest.removeListener("drain",this.ondrain)}proxyErrors(e){}end(){this.unpipe(),this.opts.end&&this.dest.end()}},RV=class extends HN{unpipe(){this.src.removeListener("error",this.proxyErrors),super.unpipe()}constructor(e,r,s){super(e,r,s),this.proxyErrors=a=>r.emit("error",a),e.on("error",this.proxyErrors)}},sIt=t=>!!t.objectMode,oIt=t=>!t.objectMode&&!!t.encoding&&t.encoding!=="buffer",jN=class extends FV.EventEmitter{[Ks]=!1;[Ab]=!1;[Qa]=[];[zs]=[];[na];[uf];[EA];[Gw];[uh]=!1;[dg]=!1;[ON]=!1;[LN]=!1;[fb]=null;[Xs]=0;[ts]=!1;[pb];[_N]=!1;[zm]=0;[rc]=!1;writable=!0;readable=!0;constructor(...e){let r=e[0]||{};if(super(),r.objectMode&&typeof r.encoding=="string")throw new TypeError("Encoding and objectMode may not be used together");sIt(r)?(this[na]=!0,this[uf]=null):oIt(r)?(this[uf]=r.encoding,this[na]=!1):(this[na]=!1,this[uf]=null),this[EA]=!!r.async,this[Gw]=this[uf]?new XEt.StringDecoder(this[uf]):null,r&&r.debugExposeBuffer===!0&&Object.defineProperty(this,"buffer",{get:()=>this[zs]}),r&&r.debugExposePipes===!0&&Object.defineProperty(this,"pipes",{get:()=>this[Qa]});let{signal:s}=r;s&&(this[pb]=s,s.aborted?this[TV]():s.addEventListener("abort",()=>this[TV]()))}get bufferLength(){return this[Xs]}get encoding(){return this[uf]}set encoding(e){throw new Error("Encoding must be set at instantiation time")}setEncoding(e){throw new Error("Encoding must be set at instantiation time")}get objectMode(){return this[na]}set objectMode(e){throw new Error("objectMode must be set at instantiation time")}get async(){return this[EA]}set async(e){this[EA]=this[EA]||!!e}[TV](){this[_N]=!0,this.emit("abort",this[pb]?.reason),this.destroy(this[pb]?.reason)}get aborted(){return this[_N]}set aborted(e){}write(e,r,s){if(this[_N])return!1;if(this[uh])throw new Error("write after end");if(this[ts])return this.emit("error",Object.assign(new Error("Cannot call write after a stream was destroyed"),{code:"ERR_STREAM_DESTROYED"})),!0;typeof r=="function"&&(s=r,r="utf8"),r||(r="utf8");let a=this[EA]?hb:tIt;if(!this[na]&&!Buffer.isBuffer(e)){if(iIt(e))e=Buffer.from(e.buffer,e.byteOffset,e.byteLength);else if(nIt(e))e=Buffer.from(e);else if(typeof e!="string")throw new Error("Non-contiguous data written to non-objectMode stream")}return this[na]?(this[Ks]&&this[Xs]!==0&&this[MN](!0),this[Ks]?this.emit("data",e):this[PV](e),this[Xs]!==0&&this.emit("readable"),s&&a(s),this[Ks]):e.length?(typeof e=="string"&&!(r===this[uf]&&!this[Gw]?.lastNeed)&&(e=Buffer.from(e,r)),Buffer.isBuffer(e)&&this[uf]&&(e=this[Gw].write(e)),this[Ks]&&this[Xs]!==0&&this[MN](!0),this[Ks]?this.emit("data",e):this[PV](e),this[Xs]!==0&&this.emit("readable"),s&&a(s),this[Ks]):(this[Xs]!==0&&this.emit("readable"),s&&a(s),this[Ks])}read(e){if(this[ts])return null;if(this[rc]=!1,this[Xs]===0||e===0||e&&e>this[Xs])return this[fh](),null;this[na]&&(e=null),this[zs].length>1&&!this[na]&&(this[zs]=[this[uf]?this[zs].join(""):Buffer.concat(this[zs],this[Xs])]);let r=this[FSe](e||null,this[zs][0]);return this[fh](),r}[FSe](e,r){if(this[na])this[UN]();else{let s=r;e===s.length||e===null?this[UN]():typeof s=="string"?(this[zs][0]=s.slice(e),r=s.slice(0,e),this[Xs]-=e):(this[zs][0]=s.subarray(e),r=s.subarray(0,e),this[Xs]-=e)}return this.emit("data",r),!this[zs].length&&!this[uh]&&this.emit("drain"),r}end(e,r,s){return typeof e=="function"&&(s=e,e=void 0),typeof r=="function"&&(s=r,r="utf8"),e!==void 0&&this.write(e,r),s&&this.once("end",s),this[uh]=!0,this.writable=!1,(this[Ks]||!this[Ab])&&this[fh](),this}[qw](){this[ts]||(!this[zm]&&!this[Qa].length&&(this[rc]=!0),this[Ab]=!1,this[Ks]=!0,this.emit("resume"),this[zs].length?this[MN]():this[uh]?this[fh]():this.emit("drain"))}resume(){return this[qw]()}pause(){this[Ks]=!1,this[Ab]=!0,this[rc]=!1}get destroyed(){return this[ts]}get flowing(){return this[Ks]}get paused(){return this[Ab]}[PV](e){this[na]?this[Xs]+=1:this[Xs]+=e.length,this[zs].push(e)}[UN](){return this[na]?this[Xs]-=1:this[Xs]-=this[zs][0].length,this[zs].shift()}[MN](e=!1){do;while(this[NSe](this[UN]())&&this[zs].length);!e&&!this[zs].length&&!this[uh]&&this.emit("drain")}[NSe](e){return this.emit("data",e),this[Ks]}pipe(e,r){if(this[ts])return e;this[rc]=!1;let s=this[dg];return r=r||{},e===RSe.stdout||e===RSe.stderr?r.end=!1:r.end=r.end!==!1,r.proxyErrors=!!r.proxyErrors,s?r.end&&e.end():(this[Qa].push(r.proxyErrors?new RV(this,e,r):new HN(this,e,r)),this[EA]?hb(()=>this[qw]()):this[qw]()),e}unpipe(e){let r=this[Qa].find(s=>s.dest===e);r&&(this[Qa].length===1?(this[Ks]&&this[zm]===0&&(this[Ks]=!1),this[Qa]=[]):this[Qa].splice(this[Qa].indexOf(r),1),r.unpipe())}addListener(e,r){return this.on(e,r)}on(e,r){let s=super.on(e,r);if(e==="data")this[rc]=!1,this[zm]++,!this[Qa].length&&!this[Ks]&&this[qw]();else if(e==="readable"&&this[Xs]!==0)super.emit("readable");else if(rIt(e)&&this[dg])super.emit(e),this.removeAllListeners(e);else if(e==="error"&&this[fb]){let a=r;this[EA]?hb(()=>a.call(this,this[fb])):a.call(this,this[fb])}return s}removeListener(e,r){return this.off(e,r)}off(e,r){let s=super.off(e,r);return e==="data"&&(this[zm]=this.listeners("data").length,this[zm]===0&&!this[rc]&&!this[Qa].length&&(this[Ks]=!1)),s}removeAllListeners(e){let r=super.removeAllListeners(e);return(e==="data"||e===void 0)&&(this[zm]=0,!this[rc]&&!this[Qa].length&&(this[Ks]=!1)),r}get emittedEnd(){return this[dg]}[fh](){!this[ON]&&!this[dg]&&!this[ts]&&this[zs].length===0&&this[uh]&&(this[ON]=!0,this.emit("end"),this.emit("prefinish"),this.emit("finish"),this[LN]&&this.emit("close"),this[ON]=!1)}emit(e,...r){let s=r[0];if(e!=="error"&&e!=="close"&&e!==ts&&this[ts])return!1;if(e==="data")return!this[na]&&!s?!1:this[EA]?(hb(()=>this[kV](s)),!0):this[kV](s);if(e==="end")return this[OSe]();if(e==="close"){if(this[LN]=!0,!this[dg]&&!this[ts])return!1;let n=super.emit("close");return this.removeAllListeners("close"),n}else if(e==="error"){this[fb]=s,super.emit(xV,s);let n=!this[pb]||this.listeners("error").length?super.emit("error",s):!1;return this[fh](),n}else if(e==="resume"){let n=super.emit("resume");return this[fh](),n}else if(e==="finish"||e==="prefinish"){let n=super.emit(e);return this.removeAllListeners(e),n}let a=super.emit(e,...r);return this[fh](),a}[kV](e){for(let s of this[Qa])s.dest.write(e)===!1&&this.pause();let r=this[rc]?!1:super.emit("data",e);return this[fh](),r}[OSe](){return this[dg]?!1:(this[dg]=!0,this.readable=!1,this[EA]?(hb(()=>this[QV]()),!0):this[QV]())}[QV](){if(this[Gw]){let r=this[Gw].end();if(r){for(let s of this[Qa])s.dest.write(r);this[rc]||super.emit("data",r)}}for(let r of this[Qa])r.end();let e=super.emit("end");return this.removeAllListeners("end"),e}async collect(){let e=Object.assign([],{dataLength:0});this[na]||(e.dataLength=0);let r=this.promise();return this.on("data",s=>{e.push(s),this[na]||(e.dataLength+=s.length)}),await r,e}async concat(){if(this[na])throw new Error("cannot concat in objectMode");let e=await this.collect();return this[uf]?e.join(""):Buffer.concat(e,e.dataLength)}async promise(){return new Promise((e,r)=>{this.on(ts,()=>r(new Error("stream destroyed"))),this.on("error",s=>r(s)),this.on("end",()=>e())})}[Symbol.asyncIterator](){this[rc]=!1;let e=!1,r=async()=>(this.pause(),e=!0,{value:void 0,done:!0});return{next:()=>{if(e)return r();let a=this.read();if(a!==null)return Promise.resolve({done:!1,value:a});if(this[uh])return r();let n,c,f=C=>{this.off("data",p),this.off("end",h),this.off(ts,E),r(),c(C)},p=C=>{this.off("error",f),this.off("end",h),this.off(ts,E),this.pause(),n({value:C,done:!!this[uh]})},h=()=>{this.off("error",f),this.off("data",p),this.off(ts,E),r(),n({done:!0,value:void 0})},E=()=>f(new Error("stream destroyed"));return new Promise((C,S)=>{c=S,n=C,this.once(ts,E),this.once("error",f),this.once("end",h),this.once("data",p)})},throw:r,return:r,[Symbol.asyncIterator](){return this}}}[Symbol.iterator](){this[rc]=!1;let e=!1,r=()=>(this.pause(),this.off(xV,r),this.off(ts,r),this.off("end",r),e=!0,{done:!0,value:void 0}),s=()=>{if(e)return r();let a=this.read();return a===null?r():{done:!1,value:a}};return this.once("end",r),this.once(xV,r),this.once(ts,r),{next:s,throw:r,return:r,[Symbol.iterator](){return this}}}destroy(e){if(this[ts])return e?this.emit("error",e):this.emit(ts),this;this[ts]=!0,this[rc]=!0,this[zs].length=0,this[Xs]=0;let r=this;return typeof r.close=="function"&&!this[LN]&&r.close(),e?this.emit("error",e):this.emit(ts),this}static get isStream(){return Ta.isStream}};Ta.Minipass=jN});var HSe=_((Trr,IA)=>{"use strict";var db=Ie("crypto"),{Minipass:aIt}=MSe(),OV=["sha512","sha384","sha256"],MV=["sha512"],lIt=/^[a-z0-9+/]+(?:=?=?)$/i,cIt=/^([a-z0-9]+)-([^?]+)([?\S*]*)$/,uIt=/^([a-z0-9]+)-([A-Za-z0-9+/=]{44,88})(\?[\x21-\x7E]*)?$/,fIt=/^[\x21-\x7E]+$/,mb=t=>t?.length?`?${t.join("?")}`:"",LV=class extends aIt{#t;#r;#i;constructor(e){super(),this.size=0,this.opts=e,this.#e(),e?.algorithms?this.algorithms=[...e.algorithms]:this.algorithms=[...MV],this.algorithm!==null&&!this.algorithms.includes(this.algorithm)&&this.algorithms.push(this.algorithm),this.hashes=this.algorithms.map(db.createHash)}#e(){this.sri=this.opts?.integrity?nc(this.opts?.integrity,this.opts):null,this.expectedSize=this.opts?.size,this.sri?this.sri.isHash?(this.goodSri=!0,this.algorithm=this.sri.algorithm):(this.goodSri=!this.sri.isEmpty(),this.algorithm=this.sri.pickAlgorithm(this.opts)):this.algorithm=null,this.digests=this.goodSri?this.sri[this.algorithm]:null,this.optString=mb(this.opts?.options)}on(e,r){return e==="size"&&this.#r?r(this.#r):e==="integrity"&&this.#t?r(this.#t):e==="verified"&&this.#i?r(this.#i):super.on(e,r)}emit(e,r){return e==="end"&&this.#n(),super.emit(e,r)}write(e){return this.size+=e.length,this.hashes.forEach(r=>r.update(e)),super.write(e)}#n(){this.goodSri||this.#e();let e=nc(this.hashes.map((s,a)=>`${this.algorithms[a]}-${s.digest("base64")}${this.optString}`).join(" "),this.opts),r=this.goodSri&&e.match(this.sri,this.opts);if(typeof this.expectedSize=="number"&&this.size!==this.expectedSize){let s=new Error(`stream size mismatch when checking ${this.sri}. + Wanted: ${this.expectedSize} + Found: ${this.size}`);s.code="EBADSIZE",s.found=this.size,s.expected=this.expectedSize,s.sri=this.sri,this.emit("error",s)}else if(this.sri&&!r){let s=new Error(`${this.sri} integrity checksum failed when using ${this.algorithm}: wanted ${this.digests} but got ${e}. (${this.size} bytes)`);s.code="EINTEGRITY",s.found=e,s.expected=this.digests,s.algorithm=this.algorithm,s.sri=this.sri,this.emit("error",s)}else this.#r=this.size,this.emit("size",this.size),this.#t=e,this.emit("integrity",e),r&&(this.#i=r,this.emit("verified",r))}},Ah=class{get isHash(){return!0}constructor(e,r){let s=r?.strict;this.source=e.trim(),this.digest="",this.algorithm="",this.options=[];let a=this.source.match(s?uIt:cIt);if(!a||s&&!OV.includes(a[1]))return;this.algorithm=a[1],this.digest=a[2];let n=a[3];n&&(this.options=n.slice(1).split("?"))}hexDigest(){return this.digest&&Buffer.from(this.digest,"base64").toString("hex")}toJSON(){return this.toString()}match(e,r){let s=nc(e,r);if(!s)return!1;if(s.isIntegrity){let a=s.pickAlgorithm(r,[this.algorithm]);if(!a)return!1;let n=s[a].find(c=>c.digest===this.digest);return n||!1}return s.digest===this.digest?s:!1}toString(e){return e?.strict&&!(OV.includes(this.algorithm)&&this.digest.match(lIt)&&this.options.every(r=>r.match(fIt)))?"":`${this.algorithm}-${this.digest}${mb(this.options)}`}};function USe(t,e,r,s){let a=t!=="",n=!1,c="",f=s.length-1;for(let h=0;hs[a].find(c=>n.digest===c.digest)))throw new Error("hashes do not match, cannot update integrity")}else this[a]=s[a]}match(e,r){let s=nc(e,r);if(!s)return!1;let a=s.pickAlgorithm(r,Object.keys(this));return!!a&&this[a]&&s[a]&&this[a].find(n=>s[a].find(c=>n.digest===c.digest))||!1}pickAlgorithm(e,r){let s=e?.pickAlgorithm||EIt,a=Object.keys(this).filter(n=>r?.length?r.includes(n):!0);return a.length?a.reduce((n,c)=>s(n,c)||n):null}};IA.exports.parse=nc;function nc(t,e){if(!t)return null;if(typeof t=="string")return NV(t,e);if(t.algorithm&&t.digest){let r=new Xm;return r[t.algorithm]=[t],NV(gb(r,e),e)}else return NV(gb(t,e),e)}function NV(t,e){if(e?.single)return new Ah(t,e);let r=t.trim().split(/\s+/).reduce((s,a)=>{let n=new Ah(a,e);if(n.algorithm&&n.digest){let c=n.algorithm;s[c]||(s[c]=[]),s[c].push(n)}return s},new Xm);return r.isEmpty()?null:r}IA.exports.stringify=gb;function gb(t,e){return t.algorithm&&t.digest?Ah.prototype.toString.call(t,e):typeof t=="string"?gb(nc(t,e),e):Xm.prototype.toString.call(t,e)}IA.exports.fromHex=AIt;function AIt(t,e,r){let s=mb(r?.options);return nc(`${e}-${Buffer.from(t,"hex").toString("base64")}${s}`,r)}IA.exports.fromData=pIt;function pIt(t,e){let r=e?.algorithms||[...MV],s=mb(e?.options);return r.reduce((a,n)=>{let c=db.createHash(n).update(t).digest("base64"),f=new Ah(`${n}-${c}${s}`,e);if(f.algorithm&&f.digest){let p=f.algorithm;a[p]||(a[p]=[]),a[p].push(f)}return a},new Xm)}IA.exports.fromStream=hIt;function hIt(t,e){let r=UV(e);return new Promise((s,a)=>{t.pipe(r),t.on("error",a),r.on("error",a);let n;r.on("integrity",c=>{n=c}),r.on("end",()=>s(n)),r.resume()})}IA.exports.checkData=gIt;function gIt(t,e,r){if(e=nc(e,r),!e||!Object.keys(e).length){if(r?.error)throw Object.assign(new Error("No valid integrity hashes to check against"),{code:"EINTEGRITY"});return!1}let s=e.pickAlgorithm(r),a=db.createHash(s).update(t).digest("base64"),n=nc({algorithm:s,digest:a}),c=n.match(e,r);if(r=r||{},c||!r.error)return c;if(typeof r.size=="number"&&t.length!==r.size){let f=new Error(`data size mismatch when checking ${e}. + Wanted: ${r.size} + Found: ${t.length}`);throw f.code="EBADSIZE",f.found=t.length,f.expected=r.size,f.sri=e,f}else{let f=new Error(`Integrity checksum failed when using ${s}: Wanted ${e}, but got ${n}. (${t.length} bytes)`);throw f.code="EINTEGRITY",f.found=n,f.expected=e,f.algorithm=s,f.sri=e,f}}IA.exports.checkStream=dIt;function dIt(t,e,r){if(r=r||Object.create(null),r.integrity=e,e=nc(e,r),!e||!Object.keys(e).length)return Promise.reject(Object.assign(new Error("No valid integrity hashes to check against"),{code:"EINTEGRITY"}));let s=UV(r);return new Promise((a,n)=>{t.pipe(s),t.on("error",n),s.on("error",n);let c;s.on("verified",f=>{c=f}),s.on("end",()=>a(c)),s.resume()})}IA.exports.integrityStream=UV;function UV(t=Object.create(null)){return new LV(t)}IA.exports.create=mIt;function mIt(t){let e=t?.algorithms||[...MV],r=mb(t?.options),s=e.map(db.createHash);return{update:function(a,n){return s.forEach(c=>c.update(a,n)),this},digest:function(){return e.reduce((n,c)=>{let f=s.shift().digest("base64"),p=new Ah(`${c}-${f}${r}`,t);if(p.algorithm&&p.digest){let h=p.algorithm;n[h]||(n[h]=[]),n[h].push(p)}return n},new Xm)}}}var yIt=db.getHashes(),_Se=["md5","whirlpool","sha1","sha224","sha256","sha384","sha512","sha3","sha3-256","sha3-384","sha3-512","sha3_256","sha3_384","sha3_512"].filter(t=>yIt.includes(t));function EIt(t,e){return _Se.indexOf(t.toLowerCase())>=_Se.indexOf(e.toLowerCase())?t:e}});var _V=_(mg=>{"use strict";Object.defineProperty(mg,"__esModule",{value:!0});mg.Signature=mg.Envelope=void 0;mg.Envelope={fromJSON(t){return{payload:GN(t.payload)?Buffer.from(jSe(t.payload)):Buffer.alloc(0),payloadType:GN(t.payloadType)?globalThis.String(t.payloadType):"",signatures:globalThis.Array.isArray(t?.signatures)?t.signatures.map(e=>mg.Signature.fromJSON(e)):[]}},toJSON(t){let e={};return t.payload.length!==0&&(e.payload=GSe(t.payload)),t.payloadType!==""&&(e.payloadType=t.payloadType),t.signatures?.length&&(e.signatures=t.signatures.map(r=>mg.Signature.toJSON(r))),e}};mg.Signature={fromJSON(t){return{sig:GN(t.sig)?Buffer.from(jSe(t.sig)):Buffer.alloc(0),keyid:GN(t.keyid)?globalThis.String(t.keyid):""}},toJSON(t){let e={};return t.sig.length!==0&&(e.sig=GSe(t.sig)),t.keyid!==""&&(e.keyid=t.keyid),e}};function jSe(t){return Uint8Array.from(globalThis.Buffer.from(t,"base64"))}function GSe(t){return globalThis.Buffer.from(t).toString("base64")}function GN(t){return t!=null}});var WSe=_(qN=>{"use strict";Object.defineProperty(qN,"__esModule",{value:!0});qN.Timestamp=void 0;qN.Timestamp={fromJSON(t){return{seconds:qSe(t.seconds)?globalThis.String(t.seconds):"0",nanos:qSe(t.nanos)?globalThis.Number(t.nanos):0}},toJSON(t){let e={};return t.seconds!=="0"&&(e.seconds=t.seconds),t.nanos!==0&&(e.nanos=Math.round(t.nanos)),e}};function qSe(t){return t!=null}});var Ww=_(Ur=>{"use strict";Object.defineProperty(Ur,"__esModule",{value:!0});Ur.TimeRange=Ur.X509CertificateChain=Ur.SubjectAlternativeName=Ur.X509Certificate=Ur.DistinguishedName=Ur.ObjectIdentifierValuePair=Ur.ObjectIdentifier=Ur.PublicKeyIdentifier=Ur.PublicKey=Ur.RFC3161SignedTimestamp=Ur.LogId=Ur.MessageSignature=Ur.HashOutput=Ur.SubjectAlternativeNameType=Ur.PublicKeyDetails=Ur.HashAlgorithm=void 0;Ur.hashAlgorithmFromJSON=VSe;Ur.hashAlgorithmToJSON=JSe;Ur.publicKeyDetailsFromJSON=KSe;Ur.publicKeyDetailsToJSON=zSe;Ur.subjectAlternativeNameTypeFromJSON=XSe;Ur.subjectAlternativeNameTypeToJSON=ZSe;var IIt=WSe(),yl;(function(t){t[t.HASH_ALGORITHM_UNSPECIFIED=0]="HASH_ALGORITHM_UNSPECIFIED",t[t.SHA2_256=1]="SHA2_256",t[t.SHA2_384=2]="SHA2_384",t[t.SHA2_512=3]="SHA2_512",t[t.SHA3_256=4]="SHA3_256",t[t.SHA3_384=5]="SHA3_384"})(yl||(Ur.HashAlgorithm=yl={}));function VSe(t){switch(t){case 0:case"HASH_ALGORITHM_UNSPECIFIED":return yl.HASH_ALGORITHM_UNSPECIFIED;case 1:case"SHA2_256":return yl.SHA2_256;case 2:case"SHA2_384":return yl.SHA2_384;case 3:case"SHA2_512":return yl.SHA2_512;case 4:case"SHA3_256":return yl.SHA3_256;case 5:case"SHA3_384":return yl.SHA3_384;default:throw new globalThis.Error("Unrecognized enum value "+t+" for enum HashAlgorithm")}}function JSe(t){switch(t){case yl.HASH_ALGORITHM_UNSPECIFIED:return"HASH_ALGORITHM_UNSPECIFIED";case yl.SHA2_256:return"SHA2_256";case yl.SHA2_384:return"SHA2_384";case yl.SHA2_512:return"SHA2_512";case yl.SHA3_256:return"SHA3_256";case yl.SHA3_384:return"SHA3_384";default:throw new globalThis.Error("Unrecognized enum value "+t+" for enum HashAlgorithm")}}var sn;(function(t){t[t.PUBLIC_KEY_DETAILS_UNSPECIFIED=0]="PUBLIC_KEY_DETAILS_UNSPECIFIED",t[t.PKCS1_RSA_PKCS1V5=1]="PKCS1_RSA_PKCS1V5",t[t.PKCS1_RSA_PSS=2]="PKCS1_RSA_PSS",t[t.PKIX_RSA_PKCS1V5=3]="PKIX_RSA_PKCS1V5",t[t.PKIX_RSA_PSS=4]="PKIX_RSA_PSS",t[t.PKIX_RSA_PKCS1V15_2048_SHA256=9]="PKIX_RSA_PKCS1V15_2048_SHA256",t[t.PKIX_RSA_PKCS1V15_3072_SHA256=10]="PKIX_RSA_PKCS1V15_3072_SHA256",t[t.PKIX_RSA_PKCS1V15_4096_SHA256=11]="PKIX_RSA_PKCS1V15_4096_SHA256",t[t.PKIX_RSA_PSS_2048_SHA256=16]="PKIX_RSA_PSS_2048_SHA256",t[t.PKIX_RSA_PSS_3072_SHA256=17]="PKIX_RSA_PSS_3072_SHA256",t[t.PKIX_RSA_PSS_4096_SHA256=18]="PKIX_RSA_PSS_4096_SHA256",t[t.PKIX_ECDSA_P256_HMAC_SHA_256=6]="PKIX_ECDSA_P256_HMAC_SHA_256",t[t.PKIX_ECDSA_P256_SHA_256=5]="PKIX_ECDSA_P256_SHA_256",t[t.PKIX_ECDSA_P384_SHA_384=12]="PKIX_ECDSA_P384_SHA_384",t[t.PKIX_ECDSA_P521_SHA_512=13]="PKIX_ECDSA_P521_SHA_512",t[t.PKIX_ED25519=7]="PKIX_ED25519",t[t.PKIX_ED25519_PH=8]="PKIX_ED25519_PH",t[t.LMS_SHA256=14]="LMS_SHA256",t[t.LMOTS_SHA256=15]="LMOTS_SHA256"})(sn||(Ur.PublicKeyDetails=sn={}));function KSe(t){switch(t){case 0:case"PUBLIC_KEY_DETAILS_UNSPECIFIED":return sn.PUBLIC_KEY_DETAILS_UNSPECIFIED;case 1:case"PKCS1_RSA_PKCS1V5":return sn.PKCS1_RSA_PKCS1V5;case 2:case"PKCS1_RSA_PSS":return sn.PKCS1_RSA_PSS;case 3:case"PKIX_RSA_PKCS1V5":return sn.PKIX_RSA_PKCS1V5;case 4:case"PKIX_RSA_PSS":return sn.PKIX_RSA_PSS;case 9:case"PKIX_RSA_PKCS1V15_2048_SHA256":return sn.PKIX_RSA_PKCS1V15_2048_SHA256;case 10:case"PKIX_RSA_PKCS1V15_3072_SHA256":return sn.PKIX_RSA_PKCS1V15_3072_SHA256;case 11:case"PKIX_RSA_PKCS1V15_4096_SHA256":return sn.PKIX_RSA_PKCS1V15_4096_SHA256;case 16:case"PKIX_RSA_PSS_2048_SHA256":return sn.PKIX_RSA_PSS_2048_SHA256;case 17:case"PKIX_RSA_PSS_3072_SHA256":return sn.PKIX_RSA_PSS_3072_SHA256;case 18:case"PKIX_RSA_PSS_4096_SHA256":return sn.PKIX_RSA_PSS_4096_SHA256;case 6:case"PKIX_ECDSA_P256_HMAC_SHA_256":return sn.PKIX_ECDSA_P256_HMAC_SHA_256;case 5:case"PKIX_ECDSA_P256_SHA_256":return sn.PKIX_ECDSA_P256_SHA_256;case 12:case"PKIX_ECDSA_P384_SHA_384":return sn.PKIX_ECDSA_P384_SHA_384;case 13:case"PKIX_ECDSA_P521_SHA_512":return sn.PKIX_ECDSA_P521_SHA_512;case 7:case"PKIX_ED25519":return sn.PKIX_ED25519;case 8:case"PKIX_ED25519_PH":return sn.PKIX_ED25519_PH;case 14:case"LMS_SHA256":return sn.LMS_SHA256;case 15:case"LMOTS_SHA256":return sn.LMOTS_SHA256;default:throw new globalThis.Error("Unrecognized enum value "+t+" for enum PublicKeyDetails")}}function zSe(t){switch(t){case sn.PUBLIC_KEY_DETAILS_UNSPECIFIED:return"PUBLIC_KEY_DETAILS_UNSPECIFIED";case sn.PKCS1_RSA_PKCS1V5:return"PKCS1_RSA_PKCS1V5";case sn.PKCS1_RSA_PSS:return"PKCS1_RSA_PSS";case sn.PKIX_RSA_PKCS1V5:return"PKIX_RSA_PKCS1V5";case sn.PKIX_RSA_PSS:return"PKIX_RSA_PSS";case sn.PKIX_RSA_PKCS1V15_2048_SHA256:return"PKIX_RSA_PKCS1V15_2048_SHA256";case sn.PKIX_RSA_PKCS1V15_3072_SHA256:return"PKIX_RSA_PKCS1V15_3072_SHA256";case sn.PKIX_RSA_PKCS1V15_4096_SHA256:return"PKIX_RSA_PKCS1V15_4096_SHA256";case sn.PKIX_RSA_PSS_2048_SHA256:return"PKIX_RSA_PSS_2048_SHA256";case sn.PKIX_RSA_PSS_3072_SHA256:return"PKIX_RSA_PSS_3072_SHA256";case sn.PKIX_RSA_PSS_4096_SHA256:return"PKIX_RSA_PSS_4096_SHA256";case sn.PKIX_ECDSA_P256_HMAC_SHA_256:return"PKIX_ECDSA_P256_HMAC_SHA_256";case sn.PKIX_ECDSA_P256_SHA_256:return"PKIX_ECDSA_P256_SHA_256";case sn.PKIX_ECDSA_P384_SHA_384:return"PKIX_ECDSA_P384_SHA_384";case sn.PKIX_ECDSA_P521_SHA_512:return"PKIX_ECDSA_P521_SHA_512";case sn.PKIX_ED25519:return"PKIX_ED25519";case sn.PKIX_ED25519_PH:return"PKIX_ED25519_PH";case sn.LMS_SHA256:return"LMS_SHA256";case sn.LMOTS_SHA256:return"LMOTS_SHA256";default:throw new globalThis.Error("Unrecognized enum value "+t+" for enum PublicKeyDetails")}}var CA;(function(t){t[t.SUBJECT_ALTERNATIVE_NAME_TYPE_UNSPECIFIED=0]="SUBJECT_ALTERNATIVE_NAME_TYPE_UNSPECIFIED",t[t.EMAIL=1]="EMAIL",t[t.URI=2]="URI",t[t.OTHER_NAME=3]="OTHER_NAME"})(CA||(Ur.SubjectAlternativeNameType=CA={}));function XSe(t){switch(t){case 0:case"SUBJECT_ALTERNATIVE_NAME_TYPE_UNSPECIFIED":return CA.SUBJECT_ALTERNATIVE_NAME_TYPE_UNSPECIFIED;case 1:case"EMAIL":return CA.EMAIL;case 2:case"URI":return CA.URI;case 3:case"OTHER_NAME":return CA.OTHER_NAME;default:throw new globalThis.Error("Unrecognized enum value "+t+" for enum SubjectAlternativeNameType")}}function ZSe(t){switch(t){case CA.SUBJECT_ALTERNATIVE_NAME_TYPE_UNSPECIFIED:return"SUBJECT_ALTERNATIVE_NAME_TYPE_UNSPECIFIED";case CA.EMAIL:return"EMAIL";case CA.URI:return"URI";case CA.OTHER_NAME:return"OTHER_NAME";default:throw new globalThis.Error("Unrecognized enum value "+t+" for enum SubjectAlternativeNameType")}}Ur.HashOutput={fromJSON(t){return{algorithm:ds(t.algorithm)?VSe(t.algorithm):0,digest:ds(t.digest)?Buffer.from(Zm(t.digest)):Buffer.alloc(0)}},toJSON(t){let e={};return t.algorithm!==0&&(e.algorithm=JSe(t.algorithm)),t.digest.length!==0&&(e.digest=$m(t.digest)),e}};Ur.MessageSignature={fromJSON(t){return{messageDigest:ds(t.messageDigest)?Ur.HashOutput.fromJSON(t.messageDigest):void 0,signature:ds(t.signature)?Buffer.from(Zm(t.signature)):Buffer.alloc(0)}},toJSON(t){let e={};return t.messageDigest!==void 0&&(e.messageDigest=Ur.HashOutput.toJSON(t.messageDigest)),t.signature.length!==0&&(e.signature=$m(t.signature)),e}};Ur.LogId={fromJSON(t){return{keyId:ds(t.keyId)?Buffer.from(Zm(t.keyId)):Buffer.alloc(0)}},toJSON(t){let e={};return t.keyId.length!==0&&(e.keyId=$m(t.keyId)),e}};Ur.RFC3161SignedTimestamp={fromJSON(t){return{signedTimestamp:ds(t.signedTimestamp)?Buffer.from(Zm(t.signedTimestamp)):Buffer.alloc(0)}},toJSON(t){let e={};return t.signedTimestamp.length!==0&&(e.signedTimestamp=$m(t.signedTimestamp)),e}};Ur.PublicKey={fromJSON(t){return{rawBytes:ds(t.rawBytes)?Buffer.from(Zm(t.rawBytes)):void 0,keyDetails:ds(t.keyDetails)?KSe(t.keyDetails):0,validFor:ds(t.validFor)?Ur.TimeRange.fromJSON(t.validFor):void 0}},toJSON(t){let e={};return t.rawBytes!==void 0&&(e.rawBytes=$m(t.rawBytes)),t.keyDetails!==0&&(e.keyDetails=zSe(t.keyDetails)),t.validFor!==void 0&&(e.validFor=Ur.TimeRange.toJSON(t.validFor)),e}};Ur.PublicKeyIdentifier={fromJSON(t){return{hint:ds(t.hint)?globalThis.String(t.hint):""}},toJSON(t){let e={};return t.hint!==""&&(e.hint=t.hint),e}};Ur.ObjectIdentifier={fromJSON(t){return{id:globalThis.Array.isArray(t?.id)?t.id.map(e=>globalThis.Number(e)):[]}},toJSON(t){let e={};return t.id?.length&&(e.id=t.id.map(r=>Math.round(r))),e}};Ur.ObjectIdentifierValuePair={fromJSON(t){return{oid:ds(t.oid)?Ur.ObjectIdentifier.fromJSON(t.oid):void 0,value:ds(t.value)?Buffer.from(Zm(t.value)):Buffer.alloc(0)}},toJSON(t){let e={};return t.oid!==void 0&&(e.oid=Ur.ObjectIdentifier.toJSON(t.oid)),t.value.length!==0&&(e.value=$m(t.value)),e}};Ur.DistinguishedName={fromJSON(t){return{organization:ds(t.organization)?globalThis.String(t.organization):"",commonName:ds(t.commonName)?globalThis.String(t.commonName):""}},toJSON(t){let e={};return t.organization!==""&&(e.organization=t.organization),t.commonName!==""&&(e.commonName=t.commonName),e}};Ur.X509Certificate={fromJSON(t){return{rawBytes:ds(t.rawBytes)?Buffer.from(Zm(t.rawBytes)):Buffer.alloc(0)}},toJSON(t){let e={};return t.rawBytes.length!==0&&(e.rawBytes=$m(t.rawBytes)),e}};Ur.SubjectAlternativeName={fromJSON(t){return{type:ds(t.type)?XSe(t.type):0,identity:ds(t.regexp)?{$case:"regexp",regexp:globalThis.String(t.regexp)}:ds(t.value)?{$case:"value",value:globalThis.String(t.value)}:void 0}},toJSON(t){let e={};return t.type!==0&&(e.type=ZSe(t.type)),t.identity?.$case==="regexp"?e.regexp=t.identity.regexp:t.identity?.$case==="value"&&(e.value=t.identity.value),e}};Ur.X509CertificateChain={fromJSON(t){return{certificates:globalThis.Array.isArray(t?.certificates)?t.certificates.map(e=>Ur.X509Certificate.fromJSON(e)):[]}},toJSON(t){let e={};return t.certificates?.length&&(e.certificates=t.certificates.map(r=>Ur.X509Certificate.toJSON(r))),e}};Ur.TimeRange={fromJSON(t){return{start:ds(t.start)?YSe(t.start):void 0,end:ds(t.end)?YSe(t.end):void 0}},toJSON(t){let e={};return t.start!==void 0&&(e.start=t.start.toISOString()),t.end!==void 0&&(e.end=t.end.toISOString()),e}};function Zm(t){return Uint8Array.from(globalThis.Buffer.from(t,"base64"))}function $m(t){return globalThis.Buffer.from(t).toString("base64")}function CIt(t){let e=(globalThis.Number(t.seconds)||0)*1e3;return e+=(t.nanos||0)/1e6,new globalThis.Date(e)}function YSe(t){return t instanceof globalThis.Date?t:typeof t=="string"?new globalThis.Date(t):CIt(IIt.Timestamp.fromJSON(t))}function ds(t){return t!=null}});var HV=_(ms=>{"use strict";Object.defineProperty(ms,"__esModule",{value:!0});ms.TransparencyLogEntry=ms.InclusionPromise=ms.InclusionProof=ms.Checkpoint=ms.KindVersion=void 0;var $Se=Ww();ms.KindVersion={fromJSON(t){return{kind:Ra(t.kind)?globalThis.String(t.kind):"",version:Ra(t.version)?globalThis.String(t.version):""}},toJSON(t){let e={};return t.kind!==""&&(e.kind=t.kind),t.version!==""&&(e.version=t.version),e}};ms.Checkpoint={fromJSON(t){return{envelope:Ra(t.envelope)?globalThis.String(t.envelope):""}},toJSON(t){let e={};return t.envelope!==""&&(e.envelope=t.envelope),e}};ms.InclusionProof={fromJSON(t){return{logIndex:Ra(t.logIndex)?globalThis.String(t.logIndex):"0",rootHash:Ra(t.rootHash)?Buffer.from(WN(t.rootHash)):Buffer.alloc(0),treeSize:Ra(t.treeSize)?globalThis.String(t.treeSize):"0",hashes:globalThis.Array.isArray(t?.hashes)?t.hashes.map(e=>Buffer.from(WN(e))):[],checkpoint:Ra(t.checkpoint)?ms.Checkpoint.fromJSON(t.checkpoint):void 0}},toJSON(t){let e={};return t.logIndex!=="0"&&(e.logIndex=t.logIndex),t.rootHash.length!==0&&(e.rootHash=YN(t.rootHash)),t.treeSize!=="0"&&(e.treeSize=t.treeSize),t.hashes?.length&&(e.hashes=t.hashes.map(r=>YN(r))),t.checkpoint!==void 0&&(e.checkpoint=ms.Checkpoint.toJSON(t.checkpoint)),e}};ms.InclusionPromise={fromJSON(t){return{signedEntryTimestamp:Ra(t.signedEntryTimestamp)?Buffer.from(WN(t.signedEntryTimestamp)):Buffer.alloc(0)}},toJSON(t){let e={};return t.signedEntryTimestamp.length!==0&&(e.signedEntryTimestamp=YN(t.signedEntryTimestamp)),e}};ms.TransparencyLogEntry={fromJSON(t){return{logIndex:Ra(t.logIndex)?globalThis.String(t.logIndex):"0",logId:Ra(t.logId)?$Se.LogId.fromJSON(t.logId):void 0,kindVersion:Ra(t.kindVersion)?ms.KindVersion.fromJSON(t.kindVersion):void 0,integratedTime:Ra(t.integratedTime)?globalThis.String(t.integratedTime):"0",inclusionPromise:Ra(t.inclusionPromise)?ms.InclusionPromise.fromJSON(t.inclusionPromise):void 0,inclusionProof:Ra(t.inclusionProof)?ms.InclusionProof.fromJSON(t.inclusionProof):void 0,canonicalizedBody:Ra(t.canonicalizedBody)?Buffer.from(WN(t.canonicalizedBody)):Buffer.alloc(0)}},toJSON(t){let e={};return t.logIndex!=="0"&&(e.logIndex=t.logIndex),t.logId!==void 0&&(e.logId=$Se.LogId.toJSON(t.logId)),t.kindVersion!==void 0&&(e.kindVersion=ms.KindVersion.toJSON(t.kindVersion)),t.integratedTime!=="0"&&(e.integratedTime=t.integratedTime),t.inclusionPromise!==void 0&&(e.inclusionPromise=ms.InclusionPromise.toJSON(t.inclusionPromise)),t.inclusionProof!==void 0&&(e.inclusionProof=ms.InclusionProof.toJSON(t.inclusionProof)),t.canonicalizedBody.length!==0&&(e.canonicalizedBody=YN(t.canonicalizedBody)),e}};function WN(t){return Uint8Array.from(globalThis.Buffer.from(t,"base64"))}function YN(t){return globalThis.Buffer.from(t).toString("base64")}function Ra(t){return t!=null}});var jV=_(Xc=>{"use strict";Object.defineProperty(Xc,"__esModule",{value:!0});Xc.Bundle=Xc.VerificationMaterial=Xc.TimestampVerificationData=void 0;var eDe=_V(),wA=Ww(),tDe=HV();Xc.TimestampVerificationData={fromJSON(t){return{rfc3161Timestamps:globalThis.Array.isArray(t?.rfc3161Timestamps)?t.rfc3161Timestamps.map(e=>wA.RFC3161SignedTimestamp.fromJSON(e)):[]}},toJSON(t){let e={};return t.rfc3161Timestamps?.length&&(e.rfc3161Timestamps=t.rfc3161Timestamps.map(r=>wA.RFC3161SignedTimestamp.toJSON(r))),e}};Xc.VerificationMaterial={fromJSON(t){return{content:yg(t.publicKey)?{$case:"publicKey",publicKey:wA.PublicKeyIdentifier.fromJSON(t.publicKey)}:yg(t.x509CertificateChain)?{$case:"x509CertificateChain",x509CertificateChain:wA.X509CertificateChain.fromJSON(t.x509CertificateChain)}:yg(t.certificate)?{$case:"certificate",certificate:wA.X509Certificate.fromJSON(t.certificate)}:void 0,tlogEntries:globalThis.Array.isArray(t?.tlogEntries)?t.tlogEntries.map(e=>tDe.TransparencyLogEntry.fromJSON(e)):[],timestampVerificationData:yg(t.timestampVerificationData)?Xc.TimestampVerificationData.fromJSON(t.timestampVerificationData):void 0}},toJSON(t){let e={};return t.content?.$case==="publicKey"?e.publicKey=wA.PublicKeyIdentifier.toJSON(t.content.publicKey):t.content?.$case==="x509CertificateChain"?e.x509CertificateChain=wA.X509CertificateChain.toJSON(t.content.x509CertificateChain):t.content?.$case==="certificate"&&(e.certificate=wA.X509Certificate.toJSON(t.content.certificate)),t.tlogEntries?.length&&(e.tlogEntries=t.tlogEntries.map(r=>tDe.TransparencyLogEntry.toJSON(r))),t.timestampVerificationData!==void 0&&(e.timestampVerificationData=Xc.TimestampVerificationData.toJSON(t.timestampVerificationData)),e}};Xc.Bundle={fromJSON(t){return{mediaType:yg(t.mediaType)?globalThis.String(t.mediaType):"",verificationMaterial:yg(t.verificationMaterial)?Xc.VerificationMaterial.fromJSON(t.verificationMaterial):void 0,content:yg(t.messageSignature)?{$case:"messageSignature",messageSignature:wA.MessageSignature.fromJSON(t.messageSignature)}:yg(t.dsseEnvelope)?{$case:"dsseEnvelope",dsseEnvelope:eDe.Envelope.fromJSON(t.dsseEnvelope)}:void 0}},toJSON(t){let e={};return t.mediaType!==""&&(e.mediaType=t.mediaType),t.verificationMaterial!==void 0&&(e.verificationMaterial=Xc.VerificationMaterial.toJSON(t.verificationMaterial)),t.content?.$case==="messageSignature"?e.messageSignature=wA.MessageSignature.toJSON(t.content.messageSignature):t.content?.$case==="dsseEnvelope"&&(e.dsseEnvelope=eDe.Envelope.toJSON(t.content.dsseEnvelope)),e}};function yg(t){return t!=null}});var GV=_(Ri=>{"use strict";Object.defineProperty(Ri,"__esModule",{value:!0});Ri.ClientTrustConfig=Ri.SigningConfig=Ri.TrustedRoot=Ri.CertificateAuthority=Ri.TransparencyLogInstance=void 0;var El=Ww();Ri.TransparencyLogInstance={fromJSON(t){return{baseUrl:ia(t.baseUrl)?globalThis.String(t.baseUrl):"",hashAlgorithm:ia(t.hashAlgorithm)?(0,El.hashAlgorithmFromJSON)(t.hashAlgorithm):0,publicKey:ia(t.publicKey)?El.PublicKey.fromJSON(t.publicKey):void 0,logId:ia(t.logId)?El.LogId.fromJSON(t.logId):void 0,checkpointKeyId:ia(t.checkpointKeyId)?El.LogId.fromJSON(t.checkpointKeyId):void 0}},toJSON(t){let e={};return t.baseUrl!==""&&(e.baseUrl=t.baseUrl),t.hashAlgorithm!==0&&(e.hashAlgorithm=(0,El.hashAlgorithmToJSON)(t.hashAlgorithm)),t.publicKey!==void 0&&(e.publicKey=El.PublicKey.toJSON(t.publicKey)),t.logId!==void 0&&(e.logId=El.LogId.toJSON(t.logId)),t.checkpointKeyId!==void 0&&(e.checkpointKeyId=El.LogId.toJSON(t.checkpointKeyId)),e}};Ri.CertificateAuthority={fromJSON(t){return{subject:ia(t.subject)?El.DistinguishedName.fromJSON(t.subject):void 0,uri:ia(t.uri)?globalThis.String(t.uri):"",certChain:ia(t.certChain)?El.X509CertificateChain.fromJSON(t.certChain):void 0,validFor:ia(t.validFor)?El.TimeRange.fromJSON(t.validFor):void 0}},toJSON(t){let e={};return t.subject!==void 0&&(e.subject=El.DistinguishedName.toJSON(t.subject)),t.uri!==""&&(e.uri=t.uri),t.certChain!==void 0&&(e.certChain=El.X509CertificateChain.toJSON(t.certChain)),t.validFor!==void 0&&(e.validFor=El.TimeRange.toJSON(t.validFor)),e}};Ri.TrustedRoot={fromJSON(t){return{mediaType:ia(t.mediaType)?globalThis.String(t.mediaType):"",tlogs:globalThis.Array.isArray(t?.tlogs)?t.tlogs.map(e=>Ri.TransparencyLogInstance.fromJSON(e)):[],certificateAuthorities:globalThis.Array.isArray(t?.certificateAuthorities)?t.certificateAuthorities.map(e=>Ri.CertificateAuthority.fromJSON(e)):[],ctlogs:globalThis.Array.isArray(t?.ctlogs)?t.ctlogs.map(e=>Ri.TransparencyLogInstance.fromJSON(e)):[],timestampAuthorities:globalThis.Array.isArray(t?.timestampAuthorities)?t.timestampAuthorities.map(e=>Ri.CertificateAuthority.fromJSON(e)):[]}},toJSON(t){let e={};return t.mediaType!==""&&(e.mediaType=t.mediaType),t.tlogs?.length&&(e.tlogs=t.tlogs.map(r=>Ri.TransparencyLogInstance.toJSON(r))),t.certificateAuthorities?.length&&(e.certificateAuthorities=t.certificateAuthorities.map(r=>Ri.CertificateAuthority.toJSON(r))),t.ctlogs?.length&&(e.ctlogs=t.ctlogs.map(r=>Ri.TransparencyLogInstance.toJSON(r))),t.timestampAuthorities?.length&&(e.timestampAuthorities=t.timestampAuthorities.map(r=>Ri.CertificateAuthority.toJSON(r))),e}};Ri.SigningConfig={fromJSON(t){return{mediaType:ia(t.mediaType)?globalThis.String(t.mediaType):"",caUrl:ia(t.caUrl)?globalThis.String(t.caUrl):"",oidcUrl:ia(t.oidcUrl)?globalThis.String(t.oidcUrl):"",tlogUrls:globalThis.Array.isArray(t?.tlogUrls)?t.tlogUrls.map(e=>globalThis.String(e)):[],tsaUrls:globalThis.Array.isArray(t?.tsaUrls)?t.tsaUrls.map(e=>globalThis.String(e)):[]}},toJSON(t){let e={};return t.mediaType!==""&&(e.mediaType=t.mediaType),t.caUrl!==""&&(e.caUrl=t.caUrl),t.oidcUrl!==""&&(e.oidcUrl=t.oidcUrl),t.tlogUrls?.length&&(e.tlogUrls=t.tlogUrls),t.tsaUrls?.length&&(e.tsaUrls=t.tsaUrls),e}};Ri.ClientTrustConfig={fromJSON(t){return{mediaType:ia(t.mediaType)?globalThis.String(t.mediaType):"",trustedRoot:ia(t.trustedRoot)?Ri.TrustedRoot.fromJSON(t.trustedRoot):void 0,signingConfig:ia(t.signingConfig)?Ri.SigningConfig.fromJSON(t.signingConfig):void 0}},toJSON(t){let e={};return t.mediaType!==""&&(e.mediaType=t.mediaType),t.trustedRoot!==void 0&&(e.trustedRoot=Ri.TrustedRoot.toJSON(t.trustedRoot)),t.signingConfig!==void 0&&(e.signingConfig=Ri.SigningConfig.toJSON(t.signingConfig)),e}};function ia(t){return t!=null}});var iDe=_(Vr=>{"use strict";Object.defineProperty(Vr,"__esModule",{value:!0});Vr.Input=Vr.Artifact=Vr.ArtifactVerificationOptions_ObserverTimestampOptions=Vr.ArtifactVerificationOptions_TlogIntegratedTimestampOptions=Vr.ArtifactVerificationOptions_TimestampAuthorityOptions=Vr.ArtifactVerificationOptions_CtlogOptions=Vr.ArtifactVerificationOptions_TlogOptions=Vr.ArtifactVerificationOptions=Vr.PublicKeyIdentities=Vr.CertificateIdentities=Vr.CertificateIdentity=void 0;var rDe=jV(),Eg=Ww(),nDe=GV();Vr.CertificateIdentity={fromJSON(t){return{issuer:gi(t.issuer)?globalThis.String(t.issuer):"",san:gi(t.san)?Eg.SubjectAlternativeName.fromJSON(t.san):void 0,oids:globalThis.Array.isArray(t?.oids)?t.oids.map(e=>Eg.ObjectIdentifierValuePair.fromJSON(e)):[]}},toJSON(t){let e={};return t.issuer!==""&&(e.issuer=t.issuer),t.san!==void 0&&(e.san=Eg.SubjectAlternativeName.toJSON(t.san)),t.oids?.length&&(e.oids=t.oids.map(r=>Eg.ObjectIdentifierValuePair.toJSON(r))),e}};Vr.CertificateIdentities={fromJSON(t){return{identities:globalThis.Array.isArray(t?.identities)?t.identities.map(e=>Vr.CertificateIdentity.fromJSON(e)):[]}},toJSON(t){let e={};return t.identities?.length&&(e.identities=t.identities.map(r=>Vr.CertificateIdentity.toJSON(r))),e}};Vr.PublicKeyIdentities={fromJSON(t){return{publicKeys:globalThis.Array.isArray(t?.publicKeys)?t.publicKeys.map(e=>Eg.PublicKey.fromJSON(e)):[]}},toJSON(t){let e={};return t.publicKeys?.length&&(e.publicKeys=t.publicKeys.map(r=>Eg.PublicKey.toJSON(r))),e}};Vr.ArtifactVerificationOptions={fromJSON(t){return{signers:gi(t.certificateIdentities)?{$case:"certificateIdentities",certificateIdentities:Vr.CertificateIdentities.fromJSON(t.certificateIdentities)}:gi(t.publicKeys)?{$case:"publicKeys",publicKeys:Vr.PublicKeyIdentities.fromJSON(t.publicKeys)}:void 0,tlogOptions:gi(t.tlogOptions)?Vr.ArtifactVerificationOptions_TlogOptions.fromJSON(t.tlogOptions):void 0,ctlogOptions:gi(t.ctlogOptions)?Vr.ArtifactVerificationOptions_CtlogOptions.fromJSON(t.ctlogOptions):void 0,tsaOptions:gi(t.tsaOptions)?Vr.ArtifactVerificationOptions_TimestampAuthorityOptions.fromJSON(t.tsaOptions):void 0,integratedTsOptions:gi(t.integratedTsOptions)?Vr.ArtifactVerificationOptions_TlogIntegratedTimestampOptions.fromJSON(t.integratedTsOptions):void 0,observerOptions:gi(t.observerOptions)?Vr.ArtifactVerificationOptions_ObserverTimestampOptions.fromJSON(t.observerOptions):void 0}},toJSON(t){let e={};return t.signers?.$case==="certificateIdentities"?e.certificateIdentities=Vr.CertificateIdentities.toJSON(t.signers.certificateIdentities):t.signers?.$case==="publicKeys"&&(e.publicKeys=Vr.PublicKeyIdentities.toJSON(t.signers.publicKeys)),t.tlogOptions!==void 0&&(e.tlogOptions=Vr.ArtifactVerificationOptions_TlogOptions.toJSON(t.tlogOptions)),t.ctlogOptions!==void 0&&(e.ctlogOptions=Vr.ArtifactVerificationOptions_CtlogOptions.toJSON(t.ctlogOptions)),t.tsaOptions!==void 0&&(e.tsaOptions=Vr.ArtifactVerificationOptions_TimestampAuthorityOptions.toJSON(t.tsaOptions)),t.integratedTsOptions!==void 0&&(e.integratedTsOptions=Vr.ArtifactVerificationOptions_TlogIntegratedTimestampOptions.toJSON(t.integratedTsOptions)),t.observerOptions!==void 0&&(e.observerOptions=Vr.ArtifactVerificationOptions_ObserverTimestampOptions.toJSON(t.observerOptions)),e}};Vr.ArtifactVerificationOptions_TlogOptions={fromJSON(t){return{threshold:gi(t.threshold)?globalThis.Number(t.threshold):0,performOnlineVerification:gi(t.performOnlineVerification)?globalThis.Boolean(t.performOnlineVerification):!1,disable:gi(t.disable)?globalThis.Boolean(t.disable):!1}},toJSON(t){let e={};return t.threshold!==0&&(e.threshold=Math.round(t.threshold)),t.performOnlineVerification!==!1&&(e.performOnlineVerification=t.performOnlineVerification),t.disable!==!1&&(e.disable=t.disable),e}};Vr.ArtifactVerificationOptions_CtlogOptions={fromJSON(t){return{threshold:gi(t.threshold)?globalThis.Number(t.threshold):0,disable:gi(t.disable)?globalThis.Boolean(t.disable):!1}},toJSON(t){let e={};return t.threshold!==0&&(e.threshold=Math.round(t.threshold)),t.disable!==!1&&(e.disable=t.disable),e}};Vr.ArtifactVerificationOptions_TimestampAuthorityOptions={fromJSON(t){return{threshold:gi(t.threshold)?globalThis.Number(t.threshold):0,disable:gi(t.disable)?globalThis.Boolean(t.disable):!1}},toJSON(t){let e={};return t.threshold!==0&&(e.threshold=Math.round(t.threshold)),t.disable!==!1&&(e.disable=t.disable),e}};Vr.ArtifactVerificationOptions_TlogIntegratedTimestampOptions={fromJSON(t){return{threshold:gi(t.threshold)?globalThis.Number(t.threshold):0,disable:gi(t.disable)?globalThis.Boolean(t.disable):!1}},toJSON(t){let e={};return t.threshold!==0&&(e.threshold=Math.round(t.threshold)),t.disable!==!1&&(e.disable=t.disable),e}};Vr.ArtifactVerificationOptions_ObserverTimestampOptions={fromJSON(t){return{threshold:gi(t.threshold)?globalThis.Number(t.threshold):0,disable:gi(t.disable)?globalThis.Boolean(t.disable):!1}},toJSON(t){let e={};return t.threshold!==0&&(e.threshold=Math.round(t.threshold)),t.disable!==!1&&(e.disable=t.disable),e}};Vr.Artifact={fromJSON(t){return{data:gi(t.artifactUri)?{$case:"artifactUri",artifactUri:globalThis.String(t.artifactUri)}:gi(t.artifact)?{$case:"artifact",artifact:Buffer.from(wIt(t.artifact))}:gi(t.artifactDigest)?{$case:"artifactDigest",artifactDigest:Eg.HashOutput.fromJSON(t.artifactDigest)}:void 0}},toJSON(t){let e={};return t.data?.$case==="artifactUri"?e.artifactUri=t.data.artifactUri:t.data?.$case==="artifact"?e.artifact=BIt(t.data.artifact):t.data?.$case==="artifactDigest"&&(e.artifactDigest=Eg.HashOutput.toJSON(t.data.artifactDigest)),e}};Vr.Input={fromJSON(t){return{artifactTrustRoot:gi(t.artifactTrustRoot)?nDe.TrustedRoot.fromJSON(t.artifactTrustRoot):void 0,artifactVerificationOptions:gi(t.artifactVerificationOptions)?Vr.ArtifactVerificationOptions.fromJSON(t.artifactVerificationOptions):void 0,bundle:gi(t.bundle)?rDe.Bundle.fromJSON(t.bundle):void 0,artifact:gi(t.artifact)?Vr.Artifact.fromJSON(t.artifact):void 0}},toJSON(t){let e={};return t.artifactTrustRoot!==void 0&&(e.artifactTrustRoot=nDe.TrustedRoot.toJSON(t.artifactTrustRoot)),t.artifactVerificationOptions!==void 0&&(e.artifactVerificationOptions=Vr.ArtifactVerificationOptions.toJSON(t.artifactVerificationOptions)),t.bundle!==void 0&&(e.bundle=rDe.Bundle.toJSON(t.bundle)),t.artifact!==void 0&&(e.artifact=Vr.Artifact.toJSON(t.artifact)),e}};function wIt(t){return Uint8Array.from(globalThis.Buffer.from(t,"base64"))}function BIt(t){return globalThis.Buffer.from(t).toString("base64")}function gi(t){return t!=null}});var yb=_(Zc=>{"use strict";var vIt=Zc&&Zc.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r);var a=Object.getOwnPropertyDescriptor(e,r);(!a||("get"in a?!e.__esModule:a.writable||a.configurable))&&(a={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(t,s,a)}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),Yw=Zc&&Zc.__exportStar||function(t,e){for(var r in t)r!=="default"&&!Object.prototype.hasOwnProperty.call(e,r)&&vIt(e,t,r)};Object.defineProperty(Zc,"__esModule",{value:!0});Yw(_V(),Zc);Yw(jV(),Zc);Yw(Ww(),Zc);Yw(HV(),Zc);Yw(GV(),Zc);Yw(iDe(),Zc)});var VN=_(Il=>{"use strict";Object.defineProperty(Il,"__esModule",{value:!0});Il.BUNDLE_V03_MEDIA_TYPE=Il.BUNDLE_V03_LEGACY_MEDIA_TYPE=Il.BUNDLE_V02_MEDIA_TYPE=Il.BUNDLE_V01_MEDIA_TYPE=void 0;Il.isBundleWithCertificateChain=SIt;Il.isBundleWithPublicKey=DIt;Il.isBundleWithMessageSignature=bIt;Il.isBundleWithDsseEnvelope=PIt;Il.BUNDLE_V01_MEDIA_TYPE="application/vnd.dev.sigstore.bundle+json;version=0.1";Il.BUNDLE_V02_MEDIA_TYPE="application/vnd.dev.sigstore.bundle+json;version=0.2";Il.BUNDLE_V03_LEGACY_MEDIA_TYPE="application/vnd.dev.sigstore.bundle+json;version=0.3";Il.BUNDLE_V03_MEDIA_TYPE="application/vnd.dev.sigstore.bundle.v0.3+json";function SIt(t){return t.verificationMaterial.content.$case==="x509CertificateChain"}function DIt(t){return t.verificationMaterial.content.$case==="publicKey"}function bIt(t){return t.content.$case==="messageSignature"}function PIt(t){return t.content.$case==="dsseEnvelope"}});var oDe=_(KN=>{"use strict";Object.defineProperty(KN,"__esModule",{value:!0});KN.toMessageSignatureBundle=kIt;KN.toDSSEBundle=QIt;var xIt=yb(),JN=VN();function kIt(t){return{mediaType:t.certificateChain?JN.BUNDLE_V02_MEDIA_TYPE:JN.BUNDLE_V03_MEDIA_TYPE,content:{$case:"messageSignature",messageSignature:{messageDigest:{algorithm:xIt.HashAlgorithm.SHA2_256,digest:t.digest},signature:t.signature}},verificationMaterial:sDe(t)}}function QIt(t){return{mediaType:t.certificateChain?JN.BUNDLE_V02_MEDIA_TYPE:JN.BUNDLE_V03_MEDIA_TYPE,content:{$case:"dsseEnvelope",dsseEnvelope:TIt(t)},verificationMaterial:sDe(t)}}function TIt(t){return{payloadType:t.artifactType,payload:t.artifact,signatures:[RIt(t)]}}function RIt(t){return{keyid:t.keyHint||"",sig:t.signature}}function sDe(t){return{content:FIt(t),tlogEntries:[],timestampVerificationData:{rfc3161Timestamps:[]}}}function FIt(t){return t.certificate?t.certificateChain?{$case:"x509CertificateChain",x509CertificateChain:{certificates:[{rawBytes:t.certificate}]}}:{$case:"certificate",certificate:{rawBytes:t.certificate}}:{$case:"publicKey",publicKey:{hint:t.keyHint||""}}}});var WV=_(zN=>{"use strict";Object.defineProperty(zN,"__esModule",{value:!0});zN.ValidationError=void 0;var qV=class extends Error{constructor(e,r){super(e),this.fields=r}};zN.ValidationError=qV});var YV=_(ey=>{"use strict";Object.defineProperty(ey,"__esModule",{value:!0});ey.assertBundle=NIt;ey.assertBundleV01=aDe;ey.isBundleV01=OIt;ey.assertBundleV02=LIt;ey.assertBundleLatest=MIt;var XN=WV();function NIt(t){let e=ZN(t);if(e.length>0)throw new XN.ValidationError("invalid bundle",e)}function aDe(t){let e=[];if(e.push(...ZN(t)),e.push(...UIt(t)),e.length>0)throw new XN.ValidationError("invalid v0.1 bundle",e)}function OIt(t){try{return aDe(t),!0}catch{return!1}}function LIt(t){let e=[];if(e.push(...ZN(t)),e.push(...lDe(t)),e.length>0)throw new XN.ValidationError("invalid v0.2 bundle",e)}function MIt(t){let e=[];if(e.push(...ZN(t)),e.push(...lDe(t)),e.push(..._It(t)),e.length>0)throw new XN.ValidationError("invalid bundle",e)}function ZN(t){let e=[];if((t.mediaType===void 0||!t.mediaType.match(/^application\/vnd\.dev\.sigstore\.bundle\+json;version=\d\.\d/)&&!t.mediaType.match(/^application\/vnd\.dev\.sigstore\.bundle\.v\d\.\d\+json/))&&e.push("mediaType"),t.content===void 0)e.push("content");else switch(t.content.$case){case"messageSignature":t.content.messageSignature.messageDigest===void 0?e.push("content.messageSignature.messageDigest"):t.content.messageSignature.messageDigest.digest.length===0&&e.push("content.messageSignature.messageDigest.digest"),t.content.messageSignature.signature.length===0&&e.push("content.messageSignature.signature");break;case"dsseEnvelope":t.content.dsseEnvelope.payload.length===0&&e.push("content.dsseEnvelope.payload"),t.content.dsseEnvelope.signatures.length!==1?e.push("content.dsseEnvelope.signatures"):t.content.dsseEnvelope.signatures[0].sig.length===0&&e.push("content.dsseEnvelope.signatures[0].sig");break}if(t.verificationMaterial===void 0)e.push("verificationMaterial");else{if(t.verificationMaterial.content===void 0)e.push("verificationMaterial.content");else switch(t.verificationMaterial.content.$case){case"x509CertificateChain":t.verificationMaterial.content.x509CertificateChain.certificates.length===0&&e.push("verificationMaterial.content.x509CertificateChain.certificates"),t.verificationMaterial.content.x509CertificateChain.certificates.forEach((r,s)=>{r.rawBytes.length===0&&e.push(`verificationMaterial.content.x509CertificateChain.certificates[${s}].rawBytes`)});break;case"certificate":t.verificationMaterial.content.certificate.rawBytes.length===0&&e.push("verificationMaterial.content.certificate.rawBytes");break}t.verificationMaterial.tlogEntries===void 0?e.push("verificationMaterial.tlogEntries"):t.verificationMaterial.tlogEntries.length>0&&t.verificationMaterial.tlogEntries.forEach((r,s)=>{r.logId===void 0&&e.push(`verificationMaterial.tlogEntries[${s}].logId`),r.kindVersion===void 0&&e.push(`verificationMaterial.tlogEntries[${s}].kindVersion`)})}return e}function UIt(t){let e=[];return t.verificationMaterial&&t.verificationMaterial.tlogEntries?.length>0&&t.verificationMaterial.tlogEntries.forEach((r,s)=>{r.inclusionPromise===void 0&&e.push(`verificationMaterial.tlogEntries[${s}].inclusionPromise`)}),e}function lDe(t){let e=[];return t.verificationMaterial&&t.verificationMaterial.tlogEntries?.length>0&&t.verificationMaterial.tlogEntries.forEach((r,s)=>{r.inclusionProof===void 0?e.push(`verificationMaterial.tlogEntries[${s}].inclusionProof`):r.inclusionProof.checkpoint===void 0&&e.push(`verificationMaterial.tlogEntries[${s}].inclusionProof.checkpoint`)}),e}function _It(t){let e=[];return t.verificationMaterial?.content?.$case==="x509CertificateChain"&&e.push("verificationMaterial.content.$case"),e}});var uDe=_(BA=>{"use strict";Object.defineProperty(BA,"__esModule",{value:!0});BA.envelopeToJSON=BA.envelopeFromJSON=BA.bundleToJSON=BA.bundleFromJSON=void 0;var $N=yb(),cDe=VN(),VV=YV(),HIt=t=>{let e=$N.Bundle.fromJSON(t);switch(e.mediaType){case cDe.BUNDLE_V01_MEDIA_TYPE:(0,VV.assertBundleV01)(e);break;case cDe.BUNDLE_V02_MEDIA_TYPE:(0,VV.assertBundleV02)(e);break;default:(0,VV.assertBundleLatest)(e);break}return e};BA.bundleFromJSON=HIt;var jIt=t=>$N.Bundle.toJSON(t);BA.bundleToJSON=jIt;var GIt=t=>$N.Envelope.fromJSON(t);BA.envelopeFromJSON=GIt;var qIt=t=>$N.Envelope.toJSON(t);BA.envelopeToJSON=qIt});var Ib=_(Xr=>{"use strict";Object.defineProperty(Xr,"__esModule",{value:!0});Xr.isBundleV01=Xr.assertBundleV02=Xr.assertBundleV01=Xr.assertBundleLatest=Xr.assertBundle=Xr.envelopeToJSON=Xr.envelopeFromJSON=Xr.bundleToJSON=Xr.bundleFromJSON=Xr.ValidationError=Xr.isBundleWithPublicKey=Xr.isBundleWithMessageSignature=Xr.isBundleWithDsseEnvelope=Xr.isBundleWithCertificateChain=Xr.BUNDLE_V03_MEDIA_TYPE=Xr.BUNDLE_V03_LEGACY_MEDIA_TYPE=Xr.BUNDLE_V02_MEDIA_TYPE=Xr.BUNDLE_V01_MEDIA_TYPE=Xr.toMessageSignatureBundle=Xr.toDSSEBundle=void 0;var fDe=oDe();Object.defineProperty(Xr,"toDSSEBundle",{enumerable:!0,get:function(){return fDe.toDSSEBundle}});Object.defineProperty(Xr,"toMessageSignatureBundle",{enumerable:!0,get:function(){return fDe.toMessageSignatureBundle}});var Ig=VN();Object.defineProperty(Xr,"BUNDLE_V01_MEDIA_TYPE",{enumerable:!0,get:function(){return Ig.BUNDLE_V01_MEDIA_TYPE}});Object.defineProperty(Xr,"BUNDLE_V02_MEDIA_TYPE",{enumerable:!0,get:function(){return Ig.BUNDLE_V02_MEDIA_TYPE}});Object.defineProperty(Xr,"BUNDLE_V03_LEGACY_MEDIA_TYPE",{enumerable:!0,get:function(){return Ig.BUNDLE_V03_LEGACY_MEDIA_TYPE}});Object.defineProperty(Xr,"BUNDLE_V03_MEDIA_TYPE",{enumerable:!0,get:function(){return Ig.BUNDLE_V03_MEDIA_TYPE}});Object.defineProperty(Xr,"isBundleWithCertificateChain",{enumerable:!0,get:function(){return Ig.isBundleWithCertificateChain}});Object.defineProperty(Xr,"isBundleWithDsseEnvelope",{enumerable:!0,get:function(){return Ig.isBundleWithDsseEnvelope}});Object.defineProperty(Xr,"isBundleWithMessageSignature",{enumerable:!0,get:function(){return Ig.isBundleWithMessageSignature}});Object.defineProperty(Xr,"isBundleWithPublicKey",{enumerable:!0,get:function(){return Ig.isBundleWithPublicKey}});var WIt=WV();Object.defineProperty(Xr,"ValidationError",{enumerable:!0,get:function(){return WIt.ValidationError}});var eO=uDe();Object.defineProperty(Xr,"bundleFromJSON",{enumerable:!0,get:function(){return eO.bundleFromJSON}});Object.defineProperty(Xr,"bundleToJSON",{enumerable:!0,get:function(){return eO.bundleToJSON}});Object.defineProperty(Xr,"envelopeFromJSON",{enumerable:!0,get:function(){return eO.envelopeFromJSON}});Object.defineProperty(Xr,"envelopeToJSON",{enumerable:!0,get:function(){return eO.envelopeToJSON}});var Eb=YV();Object.defineProperty(Xr,"assertBundle",{enumerable:!0,get:function(){return Eb.assertBundle}});Object.defineProperty(Xr,"assertBundleLatest",{enumerable:!0,get:function(){return Eb.assertBundleLatest}});Object.defineProperty(Xr,"assertBundleV01",{enumerable:!0,get:function(){return Eb.assertBundleV01}});Object.defineProperty(Xr,"assertBundleV02",{enumerable:!0,get:function(){return Eb.assertBundleV02}});Object.defineProperty(Xr,"isBundleV01",{enumerable:!0,get:function(){return Eb.isBundleV01}})});var Cb=_(rO=>{"use strict";Object.defineProperty(rO,"__esModule",{value:!0});rO.ByteStream=void 0;var JV=class extends Error{},tO=class t{constructor(e){this.start=0,e?(this.buf=e,this.view=Buffer.from(e)):(this.buf=new ArrayBuffer(0),this.view=Buffer.from(this.buf))}get buffer(){return this.view.subarray(0,this.start)}get length(){return this.view.byteLength}get position(){return this.start}seek(e){this.start=e}slice(e,r){let s=e+r;if(s>this.length)throw new JV("request past end of buffer");return this.view.subarray(e,s)}appendChar(e){this.ensureCapacity(1),this.view[this.start]=e,this.start+=1}appendUint16(e){this.ensureCapacity(2);let r=new Uint16Array([e]),s=new Uint8Array(r.buffer);this.view[this.start]=s[1],this.view[this.start+1]=s[0],this.start+=2}appendUint24(e){this.ensureCapacity(3);let r=new Uint32Array([e]),s=new Uint8Array(r.buffer);this.view[this.start]=s[2],this.view[this.start+1]=s[1],this.view[this.start+2]=s[0],this.start+=3}appendView(e){this.ensureCapacity(e.length),this.view.set(e,this.start),this.start+=e.length}getBlock(e){if(e<=0)return Buffer.alloc(0);if(this.start+e>this.view.length)throw new Error("request past end of buffer");let r=this.view.subarray(this.start,this.start+e);return this.start+=e,r}getUint8(){return this.getBlock(1)[0]}getUint16(){let e=this.getBlock(2);return e[0]<<8|e[1]}ensureCapacity(e){if(this.start+e>this.view.byteLength){let r=t.BLOCK_SIZE+(e>t.BLOCK_SIZE?e:0);this.realloc(this.view.byteLength+r)}}realloc(e){let r=new ArrayBuffer(e),s=Buffer.from(r);s.set(this.view),this.buf=r,this.view=s}};rO.ByteStream=tO;tO.BLOCK_SIZE=1024});var nO=_(Vw=>{"use strict";Object.defineProperty(Vw,"__esModule",{value:!0});Vw.ASN1TypeError=Vw.ASN1ParseError=void 0;var KV=class extends Error{};Vw.ASN1ParseError=KV;var zV=class extends Error{};Vw.ASN1TypeError=zV});var pDe=_(iO=>{"use strict";Object.defineProperty(iO,"__esModule",{value:!0});iO.decodeLength=YIt;iO.encodeLength=VIt;var ADe=nO();function YIt(t){let e=t.getUint8();if(!(e&128))return e;let r=e&127;if(r>6)throw new ADe.ASN1ParseError("length exceeds 6 byte limit");let s=0;for(let a=0;a0n;)r.unshift(Number(e&255n)),e=e>>8n;return Buffer.from([128|r.length,...r])}});var gDe=_(Cg=>{"use strict";Object.defineProperty(Cg,"__esModule",{value:!0});Cg.parseInteger=zIt;Cg.parseStringASCII=hDe;Cg.parseTime=XIt;Cg.parseOID=ZIt;Cg.parseBoolean=$It;Cg.parseBitString=eCt;var JIt=/^(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(\.\d{3})?Z$/,KIt=/^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(\.\d{3})?Z$/;function zIt(t){let e=0,r=t.length,s=t[e],a=s>127,n=a?255:0;for(;s==n&&++e=50?1900:2e3,s[1]=a.toString()}return new Date(`${s[1]}-${s[2]}-${s[3]}T${s[4]}:${s[5]}:${s[6]}Z`)}function ZIt(t){let e=0,r=t.length,s=t[e++],a=Math.floor(s/40),n=s%40,c=`${a}.${n}`,f=0;for(;e=f;--p)a.push(c>>p&1)}return a}});var mDe=_(sO=>{"use strict";Object.defineProperty(sO,"__esModule",{value:!0});sO.ASN1Tag=void 0;var dDe=nO(),ty={BOOLEAN:1,INTEGER:2,BIT_STRING:3,OCTET_STRING:4,OBJECT_IDENTIFIER:6,SEQUENCE:16,SET:17,PRINTABLE_STRING:19,UTC_TIME:23,GENERALIZED_TIME:24},XV={UNIVERSAL:0,APPLICATION:1,CONTEXT_SPECIFIC:2,PRIVATE:3},ZV=class{constructor(e){if(this.number=e&31,this.constructed=(e&32)===32,this.class=e>>6,this.number===31)throw new dDe.ASN1ParseError("long form tags not supported");if(this.class===XV.UNIVERSAL&&this.number===0)throw new dDe.ASN1ParseError("unsupported tag 0x00")}isUniversal(){return this.class===XV.UNIVERSAL}isContextSpecific(e){let r=this.class===XV.CONTEXT_SPECIFIC;return e!==void 0?r&&this.number===e:r}isBoolean(){return this.isUniversal()&&this.number===ty.BOOLEAN}isInteger(){return this.isUniversal()&&this.number===ty.INTEGER}isBitString(){return this.isUniversal()&&this.number===ty.BIT_STRING}isOctetString(){return this.isUniversal()&&this.number===ty.OCTET_STRING}isOID(){return this.isUniversal()&&this.number===ty.OBJECT_IDENTIFIER}isUTCTime(){return this.isUniversal()&&this.number===ty.UTC_TIME}isGeneralizedTime(){return this.isUniversal()&&this.number===ty.GENERALIZED_TIME}toDER(){return this.number|(this.constructed?32:0)|this.class<<6}};sO.ASN1Tag=ZV});var CDe=_(aO=>{"use strict";Object.defineProperty(aO,"__esModule",{value:!0});aO.ASN1Obj=void 0;var $V=Cb(),ry=nO(),EDe=pDe(),Jw=gDe(),tCt=mDe(),oO=class{constructor(e,r,s){this.tag=e,this.value=r,this.subs=s}static parseBuffer(e){return IDe(new $V.ByteStream(e))}toDER(){let e=new $V.ByteStream;if(this.subs.length>0)for(let a of this.subs)e.appendView(a.toDER());else e.appendView(this.value);let r=e.buffer,s=new $V.ByteStream;return s.appendChar(this.tag.toDER()),s.appendView((0,EDe.encodeLength)(r.length)),s.appendView(r),s.buffer}toBoolean(){if(!this.tag.isBoolean())throw new ry.ASN1TypeError("not a boolean");return(0,Jw.parseBoolean)(this.value)}toInteger(){if(!this.tag.isInteger())throw new ry.ASN1TypeError("not an integer");return(0,Jw.parseInteger)(this.value)}toOID(){if(!this.tag.isOID())throw new ry.ASN1TypeError("not an OID");return(0,Jw.parseOID)(this.value)}toDate(){switch(!0){case this.tag.isUTCTime():return(0,Jw.parseTime)(this.value,!0);case this.tag.isGeneralizedTime():return(0,Jw.parseTime)(this.value,!1);default:throw new ry.ASN1TypeError("not a date")}}toBitString(){if(!this.tag.isBitString())throw new ry.ASN1TypeError("not a bit string");return(0,Jw.parseBitString)(this.value)}};aO.ASN1Obj=oO;function IDe(t){let e=new tCt.ASN1Tag(t.getUint8()),r=(0,EDe.decodeLength)(t),s=t.slice(t.position,r),a=t.position,n=[];if(e.constructed)n=yDe(t,r);else if(e.isOctetString())try{n=yDe(t,r)}catch{}return n.length===0&&t.seek(a+r),new oO(e,s,n)}function yDe(t,e){let r=t.position+e;if(r>t.length)throw new ry.ASN1ParseError("invalid length");let s=[];for(;t.position{"use strict";Object.defineProperty(lO,"__esModule",{value:!0});lO.ASN1Obj=void 0;var rCt=CDe();Object.defineProperty(lO,"ASN1Obj",{enumerable:!0,get:function(){return rCt.ASN1Obj}})});var Kw=_(wg=>{"use strict";var nCt=wg&&wg.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(wg,"__esModule",{value:!0});wg.createPublicKey=iCt;wg.digest=sCt;wg.verify=oCt;wg.bufferEqual=aCt;var wb=nCt(Ie("crypto"));function iCt(t,e="spki"){return typeof t=="string"?wb.default.createPublicKey(t):wb.default.createPublicKey({key:t,format:"der",type:e})}function sCt(t,...e){let r=wb.default.createHash(t);for(let s of e)r.update(s);return r.digest()}function oCt(t,e,r,s){try{return wb.default.verify(s,t,e,r)}catch{return!1}}function aCt(t,e){try{return wb.default.timingSafeEqual(t,e)}catch{return!1}}});var wDe=_(e7=>{"use strict";Object.defineProperty(e7,"__esModule",{value:!0});e7.preAuthEncoding=cCt;var lCt="DSSEv1";function cCt(t,e){let r=[lCt,t.length,t,e.length,""].join(" ");return Buffer.concat([Buffer.from(r,"ascii"),e])}});var SDe=_(uO=>{"use strict";Object.defineProperty(uO,"__esModule",{value:!0});uO.base64Encode=uCt;uO.base64Decode=fCt;var BDe="base64",vDe="utf-8";function uCt(t){return Buffer.from(t,vDe).toString(BDe)}function fCt(t){return Buffer.from(t,BDe).toString(vDe)}});var DDe=_(r7=>{"use strict";Object.defineProperty(r7,"__esModule",{value:!0});r7.canonicalize=t7;function t7(t){let e="";if(t===null||typeof t!="object"||t.toJSON!=null)e+=JSON.stringify(t);else if(Array.isArray(t)){e+="[";let r=!0;t.forEach(s=>{r||(e+=","),r=!1,e+=t7(s)}),e+="]"}else{e+="{";let r=!0;Object.keys(t).sort().forEach(s=>{r||(e+=","),r=!1,e+=JSON.stringify(s),e+=":",e+=t7(t[s])}),e+="}"}return e}});var n7=_(fO=>{"use strict";Object.defineProperty(fO,"__esModule",{value:!0});fO.toDER=hCt;fO.fromDER=gCt;var ACt=/-----BEGIN (.*)-----/,pCt=/-----END (.*)-----/;function hCt(t){let e="";return t.split(` +`).forEach(r=>{r.match(ACt)||r.match(pCt)||(e+=r)}),Buffer.from(e,"base64")}function gCt(t,e="CERTIFICATE"){let s=t.toString("base64").match(/.{1,64}/g)||"";return[`-----BEGIN ${e}-----`,...s,`-----END ${e}-----`].join(` +`).concat(` +`)}});var AO=_(zw=>{"use strict";Object.defineProperty(zw,"__esModule",{value:!0});zw.SHA2_HASH_ALGOS=zw.ECDSA_SIGNATURE_ALGOS=void 0;zw.ECDSA_SIGNATURE_ALGOS={"1.2.840.10045.4.3.1":"sha224","1.2.840.10045.4.3.2":"sha256","1.2.840.10045.4.3.3":"sha384","1.2.840.10045.4.3.4":"sha512"};zw.SHA2_HASH_ALGOS={"2.16.840.1.101.3.4.2.1":"sha256","2.16.840.1.101.3.4.2.2":"sha384","2.16.840.1.101.3.4.2.3":"sha512"}});var s7=_(pO=>{"use strict";Object.defineProperty(pO,"__esModule",{value:!0});pO.RFC3161TimestampVerificationError=void 0;var i7=class extends Error{};pO.RFC3161TimestampVerificationError=i7});var PDe=_(vA=>{"use strict";var dCt=vA&&vA.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r);var a=Object.getOwnPropertyDescriptor(e,r);(!a||("get"in a?!e.__esModule:a.writable||a.configurable))&&(a={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(t,s,a)}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),mCt=vA&&vA.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),yCt=vA&&vA.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!=="default"&&Object.prototype.hasOwnProperty.call(t,r)&&dCt(e,t,r);return mCt(e,t),e};Object.defineProperty(vA,"__esModule",{value:!0});vA.TSTInfo=void 0;var bDe=yCt(Kw()),ECt=AO(),ICt=s7(),o7=class{constructor(e){this.root=e}get version(){return this.root.subs[0].toInteger()}get genTime(){return this.root.subs[4].toDate()}get messageImprintHashAlgorithm(){let e=this.messageImprintObj.subs[0].subs[0].toOID();return ECt.SHA2_HASH_ALGOS[e]}get messageImprintHashedMessage(){return this.messageImprintObj.subs[1].value}get raw(){return this.root.toDER()}verify(e){let r=bDe.digest(this.messageImprintHashAlgorithm,e);if(!bDe.bufferEqual(r,this.messageImprintHashedMessage))throw new ICt.RFC3161TimestampVerificationError("message imprint does not match artifact")}get messageImprintObj(){return this.root.subs[2]}};vA.TSTInfo=o7});var kDe=_(SA=>{"use strict";var CCt=SA&&SA.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r);var a=Object.getOwnPropertyDescriptor(e,r);(!a||("get"in a?!e.__esModule:a.writable||a.configurable))&&(a={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(t,s,a)}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),wCt=SA&&SA.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),BCt=SA&&SA.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!=="default"&&Object.prototype.hasOwnProperty.call(t,r)&&CCt(e,t,r);return wCt(e,t),e};Object.defineProperty(SA,"__esModule",{value:!0});SA.RFC3161Timestamp=void 0;var vCt=cO(),a7=BCt(Kw()),xDe=AO(),Bb=s7(),SCt=PDe(),DCt="1.2.840.113549.1.7.2",bCt="1.2.840.113549.1.9.16.1.4",PCt="1.2.840.113549.1.9.4",l7=class t{constructor(e){this.root=e}static parse(e){let r=vCt.ASN1Obj.parseBuffer(e);return new t(r)}get status(){return this.pkiStatusInfoObj.subs[0].toInteger()}get contentType(){return this.contentTypeObj.toOID()}get eContentType(){return this.eContentTypeObj.toOID()}get signingTime(){return this.tstInfo.genTime}get signerIssuer(){return this.signerSidObj.subs[0].value}get signerSerialNumber(){return this.signerSidObj.subs[1].value}get signerDigestAlgorithm(){let e=this.signerDigestAlgorithmObj.subs[0].toOID();return xDe.SHA2_HASH_ALGOS[e]}get signatureAlgorithm(){let e=this.signatureAlgorithmObj.subs[0].toOID();return xDe.ECDSA_SIGNATURE_ALGOS[e]}get signatureValue(){return this.signatureValueObj.value}get tstInfo(){return new SCt.TSTInfo(this.eContentObj.subs[0].subs[0])}verify(e,r){if(!this.timeStampTokenObj)throw new Bb.RFC3161TimestampVerificationError("timeStampToken is missing");if(this.contentType!==DCt)throw new Bb.RFC3161TimestampVerificationError(`incorrect content type: ${this.contentType}`);if(this.eContentType!==bCt)throw new Bb.RFC3161TimestampVerificationError(`incorrect encapsulated content type: ${this.eContentType}`);this.tstInfo.verify(e),this.verifyMessageDigest(),this.verifySignature(r)}verifyMessageDigest(){let e=a7.digest(this.signerDigestAlgorithm,this.tstInfo.raw),r=this.messageDigestAttributeObj.subs[1].subs[0].value;if(!a7.bufferEqual(e,r))throw new Bb.RFC3161TimestampVerificationError("signed data does not match tstInfo")}verifySignature(e){let r=this.signedAttrsObj.toDER();if(r[0]=49,!a7.verify(r,e,this.signatureValue,this.signatureAlgorithm))throw new Bb.RFC3161TimestampVerificationError("signature verification failed")}get pkiStatusInfoObj(){return this.root.subs[0]}get timeStampTokenObj(){return this.root.subs[1]}get contentTypeObj(){return this.timeStampTokenObj.subs[0]}get signedDataObj(){return this.timeStampTokenObj.subs.find(r=>r.tag.isContextSpecific(0)).subs[0]}get encapContentInfoObj(){return this.signedDataObj.subs[2]}get signerInfosObj(){let e=this.signedDataObj;return e.subs[e.subs.length-1]}get signerInfoObj(){return this.signerInfosObj.subs[0]}get eContentTypeObj(){return this.encapContentInfoObj.subs[0]}get eContentObj(){return this.encapContentInfoObj.subs[1]}get signedAttrsObj(){return this.signerInfoObj.subs.find(r=>r.tag.isContextSpecific(0))}get messageDigestAttributeObj(){return this.signedAttrsObj.subs.find(r=>r.subs[0].tag.isOID()&&r.subs[0].toOID()===PCt)}get signerSidObj(){return this.signerInfoObj.subs[1]}get signerDigestAlgorithmObj(){return this.signerInfoObj.subs[2]}get signatureAlgorithmObj(){return this.signerInfoObj.subs[4]}get signatureValueObj(){return this.signerInfoObj.subs[5]}};SA.RFC3161Timestamp=l7});var QDe=_(hO=>{"use strict";Object.defineProperty(hO,"__esModule",{value:!0});hO.RFC3161Timestamp=void 0;var xCt=kDe();Object.defineProperty(hO,"RFC3161Timestamp",{enumerable:!0,get:function(){return xCt.RFC3161Timestamp}})});var RDe=_(DA=>{"use strict";var kCt=DA&&DA.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r);var a=Object.getOwnPropertyDescriptor(e,r);(!a||("get"in a?!e.__esModule:a.writable||a.configurable))&&(a={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(t,s,a)}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),QCt=DA&&DA.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),TCt=DA&&DA.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!=="default"&&Object.prototype.hasOwnProperty.call(t,r)&&kCt(e,t,r);return QCt(e,t),e};Object.defineProperty(DA,"__esModule",{value:!0});DA.SignedCertificateTimestamp=void 0;var RCt=TCt(Kw()),TDe=Cb(),c7=class t{constructor(e){this.version=e.version,this.logID=e.logID,this.timestamp=e.timestamp,this.extensions=e.extensions,this.hashAlgorithm=e.hashAlgorithm,this.signatureAlgorithm=e.signatureAlgorithm,this.signature=e.signature}get datetime(){return new Date(Number(this.timestamp.readBigInt64BE()))}get algorithm(){switch(this.hashAlgorithm){case 0:return"none";case 1:return"md5";case 2:return"sha1";case 3:return"sha224";case 4:return"sha256";case 5:return"sha384";case 6:return"sha512";default:return"unknown"}}verify(e,r){let s=new TDe.ByteStream;return s.appendChar(this.version),s.appendChar(0),s.appendView(this.timestamp),s.appendUint16(1),s.appendView(e),s.appendUint16(this.extensions.byteLength),this.extensions.byteLength>0&&s.appendView(this.extensions),RCt.verify(s.buffer,r,this.signature,this.algorithm)}static parse(e){let r=new TDe.ByteStream(e),s=r.getUint8(),a=r.getBlock(32),n=r.getBlock(8),c=r.getUint16(),f=r.getBlock(c),p=r.getUint8(),h=r.getUint8(),E=r.getUint16(),C=r.getBlock(E);if(r.position!==e.length)throw new Error("SCT buffer length mismatch");return new t({version:s,logID:a,timestamp:n,extensions:f,hashAlgorithm:p,signatureAlgorithm:h,signature:C})}};DA.SignedCertificateTimestamp=c7});var d7=_(sa=>{"use strict";Object.defineProperty(sa,"__esModule",{value:!0});sa.X509SCTExtension=sa.X509SubjectKeyIDExtension=sa.X509AuthorityKeyIDExtension=sa.X509SubjectAlternativeNameExtension=sa.X509KeyUsageExtension=sa.X509BasicConstraintsExtension=sa.X509Extension=void 0;var FCt=Cb(),NCt=RDe(),ph=class{constructor(e){this.root=e}get oid(){return this.root.subs[0].toOID()}get critical(){return this.root.subs.length===3?this.root.subs[1].toBoolean():!1}get value(){return this.extnValueObj.value}get valueObj(){return this.extnValueObj}get extnValueObj(){return this.root.subs[this.root.subs.length-1]}};sa.X509Extension=ph;var u7=class extends ph{get isCA(){return this.sequence.subs[0]?.toBoolean()??!1}get pathLenConstraint(){return this.sequence.subs.length>1?this.sequence.subs[1].toInteger():void 0}get sequence(){return this.extnValueObj.subs[0]}};sa.X509BasicConstraintsExtension=u7;var f7=class extends ph{get digitalSignature(){return this.bitString[0]===1}get keyCertSign(){return this.bitString[5]===1}get crlSign(){return this.bitString[6]===1}get bitString(){return this.extnValueObj.subs[0].toBitString()}};sa.X509KeyUsageExtension=f7;var A7=class extends ph{get rfc822Name(){return this.findGeneralName(1)?.value.toString("ascii")}get uri(){return this.findGeneralName(6)?.value.toString("ascii")}otherName(e){let r=this.findGeneralName(0);return r===void 0||r.subs[0].toOID()!==e?void 0:r.subs[1].subs[0].value.toString("ascii")}findGeneralName(e){return this.generalNames.find(r=>r.tag.isContextSpecific(e))}get generalNames(){return this.extnValueObj.subs[0].subs}};sa.X509SubjectAlternativeNameExtension=A7;var p7=class extends ph{get keyIdentifier(){return this.findSequenceMember(0)?.value}findSequenceMember(e){return this.sequence.subs.find(r=>r.tag.isContextSpecific(e))}get sequence(){return this.extnValueObj.subs[0]}};sa.X509AuthorityKeyIDExtension=p7;var h7=class extends ph{get keyIdentifier(){return this.extnValueObj.subs[0].value}};sa.X509SubjectKeyIDExtension=h7;var g7=class extends ph{constructor(e){super(e)}get signedCertificateTimestamps(){let e=this.extnValueObj.subs[0].value,r=new FCt.ByteStream(e),s=r.getUint16()+2,a=[];for(;r.position{"use strict";var OCt=ic&&ic.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r);var a=Object.getOwnPropertyDescriptor(e,r);(!a||("get"in a?!e.__esModule:a.writable||a.configurable))&&(a={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(t,s,a)}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),LCt=ic&&ic.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),NDe=ic&&ic.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!=="default"&&Object.prototype.hasOwnProperty.call(t,r)&&OCt(e,t,r);return LCt(e,t),e};Object.defineProperty(ic,"__esModule",{value:!0});ic.X509Certificate=ic.EXTENSION_OID_SCT=void 0;var MCt=cO(),FDe=NDe(Kw()),UCt=AO(),_Ct=NDe(n7()),ny=d7(),HCt="2.5.29.14",jCt="2.5.29.15",GCt="2.5.29.17",qCt="2.5.29.19",WCt="2.5.29.35";ic.EXTENSION_OID_SCT="1.3.6.1.4.1.11129.2.4.2";var m7=class t{constructor(e){this.root=e}static parse(e){let r=typeof e=="string"?_Ct.toDER(e):e,s=MCt.ASN1Obj.parseBuffer(r);return new t(s)}get tbsCertificate(){return this.tbsCertificateObj}get version(){return`v${(this.versionObj.subs[0].toInteger()+BigInt(1)).toString()}`}get serialNumber(){return this.serialNumberObj.value}get notBefore(){return this.validityObj.subs[0].toDate()}get notAfter(){return this.validityObj.subs[1].toDate()}get issuer(){return this.issuerObj.value}get subject(){return this.subjectObj.value}get publicKey(){return this.subjectPublicKeyInfoObj.toDER()}get signatureAlgorithm(){let e=this.signatureAlgorithmObj.subs[0].toOID();return UCt.ECDSA_SIGNATURE_ALGOS[e]}get signatureValue(){return this.signatureValueObj.value.subarray(1)}get subjectAltName(){let e=this.extSubjectAltName;return e?.uri||e?.rfc822Name}get extensions(){return this.extensionsObj?.subs[0]?.subs||[]}get extKeyUsage(){let e=this.findExtension(jCt);return e?new ny.X509KeyUsageExtension(e):void 0}get extBasicConstraints(){let e=this.findExtension(qCt);return e?new ny.X509BasicConstraintsExtension(e):void 0}get extSubjectAltName(){let e=this.findExtension(GCt);return e?new ny.X509SubjectAlternativeNameExtension(e):void 0}get extAuthorityKeyID(){let e=this.findExtension(WCt);return e?new ny.X509AuthorityKeyIDExtension(e):void 0}get extSubjectKeyID(){let e=this.findExtension(HCt);return e?new ny.X509SubjectKeyIDExtension(e):void 0}get extSCT(){let e=this.findExtension(ic.EXTENSION_OID_SCT);return e?new ny.X509SCTExtension(e):void 0}get isCA(){let e=this.extBasicConstraints?.isCA||!1;return this.extKeyUsage?e&&this.extKeyUsage.keyCertSign:e}extension(e){let r=this.findExtension(e);return r?new ny.X509Extension(r):void 0}verify(e){let r=e?.publicKey||this.publicKey,s=FDe.createPublicKey(r);return FDe.verify(this.tbsCertificate.toDER(),s,this.signatureValue,this.signatureAlgorithm)}validForDate(e){return this.notBefore<=e&&e<=this.notAfter}equals(e){return this.root.toDER().equals(e.root.toDER())}clone(){let e=this.root.toDER(),r=Buffer.alloc(e.length);return e.copy(r),t.parse(r)}findExtension(e){return this.extensions.find(r=>r.subs[0].toOID()===e)}get tbsCertificateObj(){return this.root.subs[0]}get signatureAlgorithmObj(){return this.root.subs[1]}get signatureValueObj(){return this.root.subs[2]}get versionObj(){return this.tbsCertificateObj.subs[0]}get serialNumberObj(){return this.tbsCertificateObj.subs[1]}get issuerObj(){return this.tbsCertificateObj.subs[3]}get validityObj(){return this.tbsCertificateObj.subs[4]}get subjectObj(){return this.tbsCertificateObj.subs[5]}get subjectPublicKeyInfoObj(){return this.tbsCertificateObj.subs[6]}get extensionsObj(){return this.tbsCertificateObj.subs.find(e=>e.tag.isContextSpecific(3))}};ic.X509Certificate=m7});var MDe=_(Bg=>{"use strict";Object.defineProperty(Bg,"__esModule",{value:!0});Bg.X509SCTExtension=Bg.X509Certificate=Bg.EXTENSION_OID_SCT=void 0;var LDe=ODe();Object.defineProperty(Bg,"EXTENSION_OID_SCT",{enumerable:!0,get:function(){return LDe.EXTENSION_OID_SCT}});Object.defineProperty(Bg,"X509Certificate",{enumerable:!0,get:function(){return LDe.X509Certificate}});var YCt=d7();Object.defineProperty(Bg,"X509SCTExtension",{enumerable:!0,get:function(){return YCt.X509SCTExtension}})});var Cl=_(Jn=>{"use strict";var VCt=Jn&&Jn.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r);var a=Object.getOwnPropertyDescriptor(e,r);(!a||("get"in a?!e.__esModule:a.writable||a.configurable))&&(a={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(t,s,a)}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),JCt=Jn&&Jn.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),vb=Jn&&Jn.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!=="default"&&Object.prototype.hasOwnProperty.call(t,r)&&VCt(e,t,r);return JCt(e,t),e};Object.defineProperty(Jn,"__esModule",{value:!0});Jn.X509SCTExtension=Jn.X509Certificate=Jn.EXTENSION_OID_SCT=Jn.ByteStream=Jn.RFC3161Timestamp=Jn.pem=Jn.json=Jn.encoding=Jn.dsse=Jn.crypto=Jn.ASN1Obj=void 0;var KCt=cO();Object.defineProperty(Jn,"ASN1Obj",{enumerable:!0,get:function(){return KCt.ASN1Obj}});Jn.crypto=vb(Kw());Jn.dsse=vb(wDe());Jn.encoding=vb(SDe());Jn.json=vb(DDe());Jn.pem=vb(n7());var zCt=QDe();Object.defineProperty(Jn,"RFC3161Timestamp",{enumerable:!0,get:function(){return zCt.RFC3161Timestamp}});var XCt=Cb();Object.defineProperty(Jn,"ByteStream",{enumerable:!0,get:function(){return XCt.ByteStream}});var y7=MDe();Object.defineProperty(Jn,"EXTENSION_OID_SCT",{enumerable:!0,get:function(){return y7.EXTENSION_OID_SCT}});Object.defineProperty(Jn,"X509Certificate",{enumerable:!0,get:function(){return y7.X509Certificate}});Object.defineProperty(Jn,"X509SCTExtension",{enumerable:!0,get:function(){return y7.X509SCTExtension}})});var UDe=_(E7=>{"use strict";Object.defineProperty(E7,"__esModule",{value:!0});E7.extractJWTSubject=$Ct;var ZCt=Cl();function $Ct(t){let e=t.split(".",3),r=JSON.parse(ZCt.encoding.base64Decode(e[1]));switch(r.iss){case"https://accounts.google.com":case"https://oauth2.sigstore.dev/auth":return r.email;default:return r.sub}}});var _De=_((dnr,ewt)=>{ewt.exports={name:"@sigstore/sign",version:"3.1.0",description:"Sigstore signing library",main:"dist/index.js",types:"dist/index.d.ts",scripts:{clean:"shx rm -rf dist *.tsbuildinfo",build:"tsc --build",test:"jest"},files:["dist"],author:"bdehamer@github.com",license:"Apache-2.0",repository:{type:"git",url:"git+https://github.com/sigstore/sigstore-js.git"},bugs:{url:"https://github.com/sigstore/sigstore-js/issues"},homepage:"https://github.com/sigstore/sigstore-js/tree/main/packages/sign#readme",publishConfig:{provenance:!0},devDependencies:{"@sigstore/jest":"^0.0.0","@sigstore/mock":"^0.10.0","@sigstore/rekor-types":"^3.0.0","@types/make-fetch-happen":"^10.0.4","@types/promise-retry":"^1.1.6"},dependencies:{"@sigstore/bundle":"^3.1.0","@sigstore/core":"^2.0.0","@sigstore/protobuf-specs":"^0.4.0","make-fetch-happen":"^14.0.2","proc-log":"^5.0.0","promise-retry":"^2.0.1"},engines:{node:"^18.17.0 || >=20.5.0"}}});var jDe=_(Xw=>{"use strict";var twt=Xw&&Xw.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(Xw,"__esModule",{value:!0});Xw.getUserAgent=void 0;var HDe=twt(Ie("os")),rwt=()=>{let t=_De().version,e=process.version,r=HDe.default.platform(),s=HDe.default.arch();return`sigstore-js/${t} (Node ${e}) (${r}/${s})`};Xw.getUserAgent=rwt});var vg=_(Ji=>{"use strict";var nwt=Ji&&Ji.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r);var a=Object.getOwnPropertyDescriptor(e,r);(!a||("get"in a?!e.__esModule:a.writable||a.configurable))&&(a={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(t,s,a)}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),iwt=Ji&&Ji.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),GDe=Ji&&Ji.__importStar||function(){var t=function(e){return t=Object.getOwnPropertyNames||function(r){var s=[];for(var a in r)Object.prototype.hasOwnProperty.call(r,a)&&(s[s.length]=a);return s},t(e)};return function(e){if(e&&e.__esModule)return e;var r={};if(e!=null)for(var s=t(e),a=0;a{"use strict";Object.defineProperty(gO,"__esModule",{value:!0});gO.BaseBundleBuilder=void 0;var I7=class{constructor(e){this.signer=e.signer,this.witnesses=e.witnesses}async create(e){let r=await this.prepare(e).then(f=>this.signer.sign(f)),s=await this.package(e,r),a=await Promise.all(this.witnesses.map(f=>f.testify(s.content,swt(r.key)))),n=[],c=[];return a.forEach(({tlogEntries:f,rfc3161Timestamps:p})=>{n.push(...f??[]),c.push(...p??[])}),s.verificationMaterial.tlogEntries=n,s.verificationMaterial.timestampVerificationData={rfc3161Timestamps:c},s}async prepare(e){return e.data}};gO.BaseBundleBuilder=I7;function swt(t){switch(t.$case){case"publicKey":return t.publicKey;case"x509Certificate":return t.certificate}}});var B7=_(bA=>{"use strict";var owt=bA&&bA.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r);var a=Object.getOwnPropertyDescriptor(e,r);(!a||("get"in a?!e.__esModule:a.writable||a.configurable))&&(a={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(t,s,a)}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),awt=bA&&bA.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),lwt=bA&&bA.__importStar||function(){var t=function(e){return t=Object.getOwnPropertyNames||function(r){var s=[];for(var a in r)Object.prototype.hasOwnProperty.call(r,a)&&(s[s.length]=a);return s},t(e)};return function(e){if(e&&e.__esModule)return e;var r={};if(e!=null)for(var s=t(e),a=0;a{"use strict";Object.defineProperty(dO,"__esModule",{value:!0});dO.DSSEBundleBuilder=void 0;var fwt=vg(),Awt=C7(),pwt=B7(),v7=class extends Awt.BaseBundleBuilder{constructor(e){super(e),this.certificateChain=e.certificateChain??!1}async prepare(e){let r=WDe(e);return fwt.dsse.preAuthEncoding(r.type,r.data)}async package(e,r){return(0,pwt.toDSSEBundle)(WDe(e),r,this.certificateChain)}};dO.DSSEBundleBuilder=v7;function WDe(t){return{...t,type:t.type??""}}});var VDe=_(mO=>{"use strict";Object.defineProperty(mO,"__esModule",{value:!0});mO.MessageSignatureBundleBuilder=void 0;var hwt=C7(),gwt=B7(),S7=class extends hwt.BaseBundleBuilder{constructor(e){super(e)}async package(e,r){return(0,gwt.toMessageSignatureBundle)(e,r)}};mO.MessageSignatureBundleBuilder=S7});var JDe=_(Zw=>{"use strict";Object.defineProperty(Zw,"__esModule",{value:!0});Zw.MessageSignatureBundleBuilder=Zw.DSSEBundleBuilder=void 0;var dwt=YDe();Object.defineProperty(Zw,"DSSEBundleBuilder",{enumerable:!0,get:function(){return dwt.DSSEBundleBuilder}});var mwt=VDe();Object.defineProperty(Zw,"MessageSignatureBundleBuilder",{enumerable:!0,get:function(){return mwt.MessageSignatureBundleBuilder}})});var EO=_(yO=>{"use strict";Object.defineProperty(yO,"__esModule",{value:!0});yO.HTTPError=void 0;var D7=class extends Error{constructor({status:e,message:r,location:s}){super(`(${e}) ${r}`),this.statusCode=e,this.location=s}};yO.HTTPError=D7});var $w=_(Db=>{"use strict";Object.defineProperty(Db,"__esModule",{value:!0});Db.InternalError=void 0;Db.internalError=Ewt;var ywt=EO(),IO=class extends Error{constructor({code:e,message:r,cause:s}){super(r),this.name=this.constructor.name,this.cause=s,this.code=e}};Db.InternalError=IO;function Ewt(t,e,r){throw t instanceof ywt.HTTPError&&(r+=` - ${t.message}`),new IO({code:e,message:r,cause:t})}});var CO=_((Dnr,KDe)=>{KDe.exports=fetch});var zDe=_(e1=>{"use strict";var Iwt=e1&&e1.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e1,"__esModule",{value:!0});e1.CIContextProvider=void 0;var Cwt=Iwt(CO()),wwt=[Bwt,vwt],b7=class{constructor(e="sigstore"){this.audience=e}async getToken(){return Promise.any(wwt.map(e=>e(this.audience))).catch(()=>Promise.reject("CI: no tokens available"))}};e1.CIContextProvider=b7;async function Bwt(t){if(!process.env.ACTIONS_ID_TOKEN_REQUEST_URL||!process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN)return Promise.reject("no token available");let e=new URL(process.env.ACTIONS_ID_TOKEN_REQUEST_URL);return e.searchParams.append("audience",t),(await(0,Cwt.default)(e.href,{retry:2,headers:{Accept:"application/json",Authorization:`Bearer ${process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN}`}})).json().then(s=>s.value)}async function vwt(){return process.env.SIGSTORE_ID_TOKEN?process.env.SIGSTORE_ID_TOKEN:Promise.reject("no token available")}});var XDe=_(wO=>{"use strict";Object.defineProperty(wO,"__esModule",{value:!0});wO.CIContextProvider=void 0;var Swt=zDe();Object.defineProperty(wO,"CIContextProvider",{enumerable:!0,get:function(){return Swt.CIContextProvider}})});var $De=_((xnr,ZDe)=>{var Dwt=Symbol("proc-log.meta");ZDe.exports={META:Dwt,output:{LEVELS:["standard","error","buffer","flush"],KEYS:{standard:"standard",error:"error",buffer:"buffer",flush:"flush"},standard:function(...t){return process.emit("output","standard",...t)},error:function(...t){return process.emit("output","error",...t)},buffer:function(...t){return process.emit("output","buffer",...t)},flush:function(...t){return process.emit("output","flush",...t)}},log:{LEVELS:["notice","error","warn","info","verbose","http","silly","timing","pause","resume"],KEYS:{notice:"notice",error:"error",warn:"warn",info:"info",verbose:"verbose",http:"http",silly:"silly",timing:"timing",pause:"pause",resume:"resume"},error:function(...t){return process.emit("log","error",...t)},notice:function(...t){return process.emit("log","notice",...t)},warn:function(...t){return process.emit("log","warn",...t)},info:function(...t){return process.emit("log","info",...t)},verbose:function(...t){return process.emit("log","verbose",...t)},http:function(...t){return process.emit("log","http",...t)},silly:function(...t){return process.emit("log","silly",...t)},timing:function(...t){return process.emit("log","timing",...t)},pause:function(){return process.emit("log","pause")},resume:function(){return process.emit("log","resume")}},time:{LEVELS:["start","end"],KEYS:{start:"start",end:"end"},start:function(t,e){process.emit("time","start",t);function r(){return process.emit("time","end",t)}if(typeof e=="function"){let s=e();return s&&s.finally?s.finally(r):(r(),s)}return r},end:function(t){return process.emit("time","end",t)}},input:{LEVELS:["start","end","read"],KEYS:{start:"start",end:"end",read:"read"},start:function(t){process.emit("input","start");function e(){return process.emit("input","end")}if(typeof t=="function"){let r=t();return r&&r.finally?r.finally(e):(e(),r)}return e},end:function(){return process.emit("input","end")},read:function(...t){let e,r,s=new Promise((a,n)=>{e=a,r=n});return process.emit("input","read",e,r,...t),s}}}});var rbe=_((knr,tbe)=>{"use strict";function ebe(t,e){for(let r in e)Object.defineProperty(t,r,{value:e[r],enumerable:!0,configurable:!0});return t}function bwt(t,e,r){if(!t||typeof t=="string")throw new TypeError("Please pass an Error to err-code");r||(r={}),typeof e=="object"&&(r=e,e=void 0),e!=null&&(r.code=e);try{return ebe(t,r)}catch{r.message=t.message,r.stack=t.stack;let a=function(){};return a.prototype=Object.create(Object.getPrototypeOf(t)),ebe(new a,r)}}tbe.exports=bwt});var ibe=_((Qnr,nbe)=>{function $c(t,e){typeof e=="boolean"&&(e={forever:e}),this._originalTimeouts=JSON.parse(JSON.stringify(t)),this._timeouts=t,this._options=e||{},this._maxRetryTime=e&&e.maxRetryTime||1/0,this._fn=null,this._errors=[],this._attempts=1,this._operationTimeout=null,this._operationTimeoutCb=null,this._timeout=null,this._operationStart=null,this._options.forever&&(this._cachedTimeouts=this._timeouts.slice(0))}nbe.exports=$c;$c.prototype.reset=function(){this._attempts=1,this._timeouts=this._originalTimeouts};$c.prototype.stop=function(){this._timeout&&clearTimeout(this._timeout),this._timeouts=[],this._cachedTimeouts=null};$c.prototype.retry=function(t){if(this._timeout&&clearTimeout(this._timeout),!t)return!1;var e=new Date().getTime();if(t&&e-this._operationStart>=this._maxRetryTime)return this._errors.unshift(new Error("RetryOperation timeout occurred")),!1;this._errors.push(t);var r=this._timeouts.shift();if(r===void 0)if(this._cachedTimeouts)this._errors.splice(this._errors.length-1,this._errors.length),this._timeouts=this._cachedTimeouts.slice(0),r=this._timeouts.shift();else return!1;var s=this,a=setTimeout(function(){s._attempts++,s._operationTimeoutCb&&(s._timeout=setTimeout(function(){s._operationTimeoutCb(s._attempts)},s._operationTimeout),s._options.unref&&s._timeout.unref()),s._fn(s._attempts)},r);return this._options.unref&&a.unref(),!0};$c.prototype.attempt=function(t,e){this._fn=t,e&&(e.timeout&&(this._operationTimeout=e.timeout),e.cb&&(this._operationTimeoutCb=e.cb));var r=this;this._operationTimeoutCb&&(this._timeout=setTimeout(function(){r._operationTimeoutCb()},r._operationTimeout)),this._operationStart=new Date().getTime(),this._fn(this._attempts)};$c.prototype.try=function(t){console.log("Using RetryOperation.try() is deprecated"),this.attempt(t)};$c.prototype.start=function(t){console.log("Using RetryOperation.start() is deprecated"),this.attempt(t)};$c.prototype.start=$c.prototype.try;$c.prototype.errors=function(){return this._errors};$c.prototype.attempts=function(){return this._attempts};$c.prototype.mainError=function(){if(this._errors.length===0)return null;for(var t={},e=null,r=0,s=0;s=r&&(e=a,r=c)}return e}});var sbe=_(iy=>{var Pwt=ibe();iy.operation=function(t){var e=iy.timeouts(t);return new Pwt(e,{forever:t&&t.forever,unref:t&&t.unref,maxRetryTime:t&&t.maxRetryTime})};iy.timeouts=function(t){if(t instanceof Array)return[].concat(t);var e={retries:10,factor:2,minTimeout:1*1e3,maxTimeout:1/0,randomize:!1};for(var r in t)e[r]=t[r];if(e.minTimeout>e.maxTimeout)throw new Error("minTimeout is greater than maxTimeout");for(var s=[],a=0;a{obe.exports=sbe()});var ube=_((Fnr,cbe)=>{"use strict";var xwt=rbe(),kwt=abe(),Qwt=Object.prototype.hasOwnProperty;function lbe(t){return t&&t.code==="EPROMISERETRY"&&Qwt.call(t,"retried")}function Twt(t,e){var r,s;return typeof t=="object"&&typeof e=="function"&&(r=e,e=t,t=r),s=kwt.operation(e),new Promise(function(a,n){s.attempt(function(c){Promise.resolve().then(function(){return t(function(f){throw lbe(f)&&(f=f.retried),xwt(new Error("Retrying"),"EPROMISERETRY",{retried:f})},c)}).then(a,function(f){lbe(f)&&(f=f.retried,s.retry(f||new Error))||n(f)})})})}cbe.exports=Twt});var BO=_(bb=>{"use strict";var Abe=bb&&bb.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(bb,"__esModule",{value:!0});bb.fetchWithRetry=qwt;var Rwt=Ie("http2"),Fwt=Abe(CO()),fbe=$De(),Nwt=Abe(ube()),Owt=vg(),Lwt=EO(),{HTTP2_HEADER_LOCATION:Mwt,HTTP2_HEADER_CONTENT_TYPE:Uwt,HTTP2_HEADER_USER_AGENT:_wt,HTTP_STATUS_INTERNAL_SERVER_ERROR:Hwt,HTTP_STATUS_TOO_MANY_REQUESTS:jwt,HTTP_STATUS_REQUEST_TIMEOUT:Gwt}=Rwt.constants;async function qwt(t,e){return(0,Nwt.default)(async(r,s)=>{let a=e.method||"POST",n={[_wt]:Owt.ua.getUserAgent(),...e.headers},c=await(0,Fwt.default)(t,{method:a,headers:n,body:e.body,timeout:e.timeout,retry:!1}).catch(f=>(fbe.log.http("fetch",`${a} ${t} attempt ${s} failed with ${f}`),r(f)));if(c.ok)return c;{let f=await Wwt(c);if(fbe.log.http("fetch",`${a} ${t} attempt ${s} failed with ${c.status}`),Ywt(c.status))return r(f);throw f}},Vwt(e.retry))}var Wwt=async t=>{let e=t.statusText,r=t.headers.get(Mwt)||void 0;if(t.headers.get(Uwt)?.includes("application/json"))try{e=(await t.json()).message||e}catch{}return new Lwt.HTTPError({status:t.status,message:e,location:r})},Ywt=t=>[Gwt,jwt].includes(t)||t>=Hwt,Vwt=t=>typeof t=="boolean"?{retries:t?1:0}:typeof t=="number"?{retries:t}:{retries:0,...t}});var pbe=_(vO=>{"use strict";Object.defineProperty(vO,"__esModule",{value:!0});vO.Fulcio=void 0;var Jwt=BO(),P7=class{constructor(e){this.options=e}async createSigningCertificate(e){let{baseURL:r,retry:s,timeout:a}=this.options,n=`${r}/api/v2/signingCert`;return(await(0,Jwt.fetchWithRetry)(n,{headers:{"Content-Type":"application/json"},body:JSON.stringify(e),timeout:a,retry:s})).json()}};vO.Fulcio=P7});var hbe=_(SO=>{"use strict";Object.defineProperty(SO,"__esModule",{value:!0});SO.CAClient=void 0;var Kwt=$w(),zwt=pbe(),x7=class{constructor(e){this.fulcio=new zwt.Fulcio({baseURL:e.fulcioBaseURL,retry:e.retry,timeout:e.timeout})}async createSigningCertificate(e,r,s){let a=Xwt(e,r,s);try{let n=await this.fulcio.createSigningCertificate(a);return(n.signedCertificateEmbeddedSct?n.signedCertificateEmbeddedSct:n.signedCertificateDetachedSct).chain.certificates}catch(n){(0,Kwt.internalError)(n,"CA_CREATE_SIGNING_CERTIFICATE_ERROR","error creating signing certificate")}}};SO.CAClient=x7;function Xwt(t,e,r){return{credentials:{oidcIdentityToken:t},publicKeyRequest:{publicKey:{algorithm:"ECDSA",content:e},proofOfPossession:r.toString("base64")}}}});var dbe=_(t1=>{"use strict";var Zwt=t1&&t1.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(t1,"__esModule",{value:!0});t1.EphemeralSigner=void 0;var gbe=Zwt(Ie("crypto")),$wt="ec",e1t="P-256",k7=class{constructor(){this.keypair=gbe.default.generateKeyPairSync($wt,{namedCurve:e1t})}async sign(e){let r=gbe.default.sign(null,e,this.keypair.privateKey),s=this.keypair.publicKey.export({format:"pem",type:"spki"}).toString("ascii");return{signature:r,key:{$case:"publicKey",publicKey:s}}}};t1.EphemeralSigner=k7});var mbe=_(sy=>{"use strict";Object.defineProperty(sy,"__esModule",{value:!0});sy.FulcioSigner=sy.DEFAULT_FULCIO_URL=void 0;var Q7=$w(),t1t=vg(),r1t=hbe(),n1t=dbe();sy.DEFAULT_FULCIO_URL="https://fulcio.sigstore.dev";var T7=class{constructor(e){this.ca=new r1t.CAClient({...e,fulcioBaseURL:e.fulcioBaseURL||sy.DEFAULT_FULCIO_URL}),this.identityProvider=e.identityProvider,this.keyHolder=e.keyHolder||new n1t.EphemeralSigner}async sign(e){let r=await this.getIdentityToken(),s;try{s=t1t.oidc.extractJWTSubject(r)}catch(f){throw new Q7.InternalError({code:"IDENTITY_TOKEN_PARSE_ERROR",message:`invalid identity token: ${r}`,cause:f})}let a=await this.keyHolder.sign(Buffer.from(s));if(a.key.$case!=="publicKey")throw new Q7.InternalError({code:"CA_CREATE_SIGNING_CERTIFICATE_ERROR",message:"unexpected format for signing key"});let n=await this.ca.createSigningCertificate(r,a.key.publicKey,a.signature);return{signature:(await this.keyHolder.sign(e)).signature,key:{$case:"x509Certificate",certificate:n[0]}}}async getIdentityToken(){try{return await this.identityProvider.getToken()}catch(e){throw new Q7.InternalError({code:"IDENTITY_TOKEN_READ_ERROR",message:"error retrieving identity token",cause:e})}}};sy.FulcioSigner=T7});var Ebe=_(r1=>{"use strict";Object.defineProperty(r1,"__esModule",{value:!0});r1.FulcioSigner=r1.DEFAULT_FULCIO_URL=void 0;var ybe=mbe();Object.defineProperty(r1,"DEFAULT_FULCIO_URL",{enumerable:!0,get:function(){return ybe.DEFAULT_FULCIO_URL}});Object.defineProperty(r1,"FulcioSigner",{enumerable:!0,get:function(){return ybe.FulcioSigner}})});var wbe=_(DO=>{"use strict";Object.defineProperty(DO,"__esModule",{value:!0});DO.Rekor=void 0;var Ibe=BO(),R7=class{constructor(e){this.options=e}async createEntry(e){let{baseURL:r,timeout:s,retry:a}=this.options,n=`${r}/api/v1/log/entries`,f=await(await(0,Ibe.fetchWithRetry)(n,{headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(e),timeout:s,retry:a})).json();return Cbe(f)}async getEntry(e){let{baseURL:r,timeout:s,retry:a}=this.options,n=`${r}/api/v1/log/entries/${e}`,f=await(await(0,Ibe.fetchWithRetry)(n,{method:"GET",headers:{Accept:"application/json"},timeout:s,retry:a})).json();return Cbe(f)}};DO.Rekor=R7;function Cbe(t){let e=Object.entries(t);if(e.length!=1)throw new Error("Received multiple entries in Rekor response");let[r,s]=e[0];return{...s,uuid:r}}});var vbe=_(bO=>{"use strict";Object.defineProperty(bO,"__esModule",{value:!0});bO.TLogClient=void 0;var Bbe=$w(),i1t=EO(),s1t=wbe(),F7=class{constructor(e){this.fetchOnConflict=e.fetchOnConflict??!1,this.rekor=new s1t.Rekor({baseURL:e.rekorBaseURL,retry:e.retry,timeout:e.timeout})}async createEntry(e){let r;try{r=await this.rekor.createEntry(e)}catch(s){if(o1t(s)&&this.fetchOnConflict){let a=s.location.split("/").pop()||"";try{r=await this.rekor.getEntry(a)}catch(n){(0,Bbe.internalError)(n,"TLOG_FETCH_ENTRY_ERROR","error fetching tlog entry")}}else(0,Bbe.internalError)(s,"TLOG_CREATE_ENTRY_ERROR","error creating tlog entry")}return r}};bO.TLogClient=F7;function o1t(t){return t instanceof i1t.HTTPError&&t.statusCode===409&&t.location!==void 0}});var Sbe=_(N7=>{"use strict";Object.defineProperty(N7,"__esModule",{value:!0});N7.toProposedEntry=l1t;var a1t=Ib(),Sg=vg(),Pb="sha256";function l1t(t,e,r="dsse"){switch(t.$case){case"dsseEnvelope":return r==="intoto"?f1t(t.dsseEnvelope,e):u1t(t.dsseEnvelope,e);case"messageSignature":return c1t(t.messageSignature,e)}}function c1t(t,e){let r=t.messageDigest.digest.toString("hex"),s=t.signature.toString("base64"),a=Sg.encoding.base64Encode(e);return{apiVersion:"0.0.1",kind:"hashedrekord",spec:{data:{hash:{algorithm:Pb,value:r}},signature:{content:s,publicKey:{content:a}}}}}function u1t(t,e){let r=JSON.stringify((0,a1t.envelopeToJSON)(t)),s=Sg.encoding.base64Encode(e);return{apiVersion:"0.0.1",kind:"dsse",spec:{proposedContent:{envelope:r,verifiers:[s]}}}}function f1t(t,e){let r=Sg.crypto.digest(Pb,t.payload).toString("hex"),s=A1t(t,e),a=Sg.encoding.base64Encode(t.payload.toString("base64")),n=Sg.encoding.base64Encode(t.signatures[0].sig.toString("base64")),c=t.signatures[0].keyid,f=Sg.encoding.base64Encode(e),p={payloadType:t.payloadType,payload:a,signatures:[{sig:n,publicKey:f}]};return c.length>0&&(p.signatures[0].keyid=c),{apiVersion:"0.0.2",kind:"intoto",spec:{content:{envelope:p,hash:{algorithm:Pb,value:s},payloadHash:{algorithm:Pb,value:r}}}}}function A1t(t,e){let r={payloadType:t.payloadType,payload:t.payload.toString("base64"),signatures:[{sig:t.signatures[0].sig.toString("base64"),publicKey:e}]};return t.signatures[0].keyid.length>0&&(r.signatures[0].keyid=t.signatures[0].keyid),Sg.crypto.digest(Pb,Sg.json.canonicalize(r)).toString("hex")}});var Dbe=_(oy=>{"use strict";Object.defineProperty(oy,"__esModule",{value:!0});oy.RekorWitness=oy.DEFAULT_REKOR_URL=void 0;var p1t=vg(),h1t=vbe(),g1t=Sbe();oy.DEFAULT_REKOR_URL="https://rekor.sigstore.dev";var O7=class{constructor(e){this.entryType=e.entryType,this.tlog=new h1t.TLogClient({...e,rekorBaseURL:e.rekorBaseURL||oy.DEFAULT_REKOR_URL})}async testify(e,r){let s=(0,g1t.toProposedEntry)(e,r,this.entryType),a=await this.tlog.createEntry(s);return d1t(a)}};oy.RekorWitness=O7;function d1t(t){let e=Buffer.from(t.logID,"hex"),r=p1t.encoding.base64Decode(t.body),s=JSON.parse(r),a=t?.verification?.signedEntryTimestamp?m1t(t.verification.signedEntryTimestamp):void 0,n=t?.verification?.inclusionProof?y1t(t.verification.inclusionProof):void 0;return{tlogEntries:[{logIndex:t.logIndex.toString(),logId:{keyId:e},integratedTime:t.integratedTime.toString(),kindVersion:{kind:s.kind,version:s.apiVersion},inclusionPromise:a,inclusionProof:n,canonicalizedBody:Buffer.from(t.body,"base64")}]}}function m1t(t){return{signedEntryTimestamp:Buffer.from(t,"base64")}}function y1t(t){return{logIndex:t.logIndex.toString(),treeSize:t.treeSize.toString(),rootHash:Buffer.from(t.rootHash,"hex"),hashes:t.hashes.map(e=>Buffer.from(e,"hex")),checkpoint:{envelope:t.checkpoint}}}});var bbe=_(PO=>{"use strict";Object.defineProperty(PO,"__esModule",{value:!0});PO.TimestampAuthority=void 0;var E1t=BO(),L7=class{constructor(e){this.options=e}async createTimestamp(e){let{baseURL:r,timeout:s,retry:a}=this.options,n=`${r}/api/v1/timestamp`;return(await(0,E1t.fetchWithRetry)(n,{headers:{"Content-Type":"application/json"},body:JSON.stringify(e),timeout:s,retry:a})).buffer()}};PO.TimestampAuthority=L7});var xbe=_(xO=>{"use strict";Object.defineProperty(xO,"__esModule",{value:!0});xO.TSAClient=void 0;var I1t=$w(),C1t=bbe(),w1t=vg(),Pbe="sha256",M7=class{constructor(e){this.tsa=new C1t.TimestampAuthority({baseURL:e.tsaBaseURL,retry:e.retry,timeout:e.timeout})}async createTimestamp(e){let r={artifactHash:w1t.crypto.digest(Pbe,e).toString("base64"),hashAlgorithm:Pbe};try{return await this.tsa.createTimestamp(r)}catch(s){(0,I1t.internalError)(s,"TSA_CREATE_TIMESTAMP_ERROR","error creating timestamp")}}};xO.TSAClient=M7});var kbe=_(kO=>{"use strict";Object.defineProperty(kO,"__esModule",{value:!0});kO.TSAWitness=void 0;var B1t=xbe(),U7=class{constructor(e){this.tsa=new B1t.TSAClient({tsaBaseURL:e.tsaBaseURL,retry:e.retry,timeout:e.timeout})}async testify(e){let r=v1t(e);return{rfc3161Timestamps:[{signedTimestamp:await this.tsa.createTimestamp(r)}]}}};kO.TSAWitness=U7;function v1t(t){switch(t.$case){case"dsseEnvelope":return t.dsseEnvelope.signatures[0].sig;case"messageSignature":return t.messageSignature.signature}}});var Tbe=_(Dg=>{"use strict";Object.defineProperty(Dg,"__esModule",{value:!0});Dg.TSAWitness=Dg.RekorWitness=Dg.DEFAULT_REKOR_URL=void 0;var Qbe=Dbe();Object.defineProperty(Dg,"DEFAULT_REKOR_URL",{enumerable:!0,get:function(){return Qbe.DEFAULT_REKOR_URL}});Object.defineProperty(Dg,"RekorWitness",{enumerable:!0,get:function(){return Qbe.RekorWitness}});var S1t=kbe();Object.defineProperty(Dg,"TSAWitness",{enumerable:!0,get:function(){return S1t.TSAWitness}})});var H7=_(ys=>{"use strict";Object.defineProperty(ys,"__esModule",{value:!0});ys.TSAWitness=ys.RekorWitness=ys.DEFAULT_REKOR_URL=ys.FulcioSigner=ys.DEFAULT_FULCIO_URL=ys.CIContextProvider=ys.InternalError=ys.MessageSignatureBundleBuilder=ys.DSSEBundleBuilder=void 0;var Rbe=JDe();Object.defineProperty(ys,"DSSEBundleBuilder",{enumerable:!0,get:function(){return Rbe.DSSEBundleBuilder}});Object.defineProperty(ys,"MessageSignatureBundleBuilder",{enumerable:!0,get:function(){return Rbe.MessageSignatureBundleBuilder}});var D1t=$w();Object.defineProperty(ys,"InternalError",{enumerable:!0,get:function(){return D1t.InternalError}});var b1t=XDe();Object.defineProperty(ys,"CIContextProvider",{enumerable:!0,get:function(){return b1t.CIContextProvider}});var Fbe=Ebe();Object.defineProperty(ys,"DEFAULT_FULCIO_URL",{enumerable:!0,get:function(){return Fbe.DEFAULT_FULCIO_URL}});Object.defineProperty(ys,"FulcioSigner",{enumerable:!0,get:function(){return Fbe.FulcioSigner}});var _7=Tbe();Object.defineProperty(ys,"DEFAULT_REKOR_URL",{enumerable:!0,get:function(){return _7.DEFAULT_REKOR_URL}});Object.defineProperty(ys,"RekorWitness",{enumerable:!0,get:function(){return _7.RekorWitness}});Object.defineProperty(ys,"TSAWitness",{enumerable:!0,get:function(){return _7.TSAWitness}})});var Obe=_(xb=>{"use strict";var Nbe=xb&&xb.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(xb,"__esModule",{value:!0});xb.appDataPath=x1t;var P1t=Nbe(Ie("os")),n1=Nbe(Ie("path"));function x1t(t){let e=P1t.default.homedir();switch(process.platform){case"darwin":{let r=n1.default.join(e,"Library","Application Support");return n1.default.join(r,t)}case"win32":{let r=process.env.LOCALAPPDATA||n1.default.join(e,"AppData","Local");return n1.default.join(r,t,"Data")}default:{let r=process.env.XDG_DATA_HOME||n1.default.join(e,".local","share");return n1.default.join(r,t)}}}});var PA=_(wl=>{"use strict";Object.defineProperty(wl,"__esModule",{value:!0});wl.UnsupportedAlgorithmError=wl.CryptoError=wl.LengthOrHashMismatchError=wl.UnsignedMetadataError=wl.RepositoryError=wl.ValueError=void 0;var j7=class extends Error{};wl.ValueError=j7;var kb=class extends Error{};wl.RepositoryError=kb;var G7=class extends kb{};wl.UnsignedMetadataError=G7;var q7=class extends kb{};wl.LengthOrHashMismatchError=q7;var QO=class extends Error{};wl.CryptoError=QO;var W7=class extends QO{};wl.UnsupportedAlgorithmError=W7});var Mbe=_(bg=>{"use strict";Object.defineProperty(bg,"__esModule",{value:!0});bg.isDefined=k1t;bg.isObject=Lbe;bg.isStringArray=Q1t;bg.isObjectArray=T1t;bg.isStringRecord=R1t;bg.isObjectRecord=F1t;function k1t(t){return t!==void 0}function Lbe(t){return typeof t=="object"&&t!==null}function Q1t(t){return Array.isArray(t)&&t.every(e=>typeof e=="string")}function T1t(t){return Array.isArray(t)&&t.every(Lbe)}function R1t(t){return typeof t=="object"&&t!==null&&Object.keys(t).every(e=>typeof e=="string")&&Object.values(t).every(e=>typeof e=="string")}function F1t(t){return typeof t=="object"&&t!==null&&Object.keys(t).every(e=>typeof e=="string")&&Object.values(t).every(e=>typeof e=="object"&&e!==null)}});var V7=_(($nr,Hbe)=>{var Ube=",",N1t=":",O1t="[",L1t="]",M1t="{",U1t="}";function Y7(t){let e=[];if(typeof t=="string")e.push(_be(t));else if(typeof t=="boolean")e.push(JSON.stringify(t));else if(Number.isInteger(t))e.push(JSON.stringify(t));else if(t===null)e.push(JSON.stringify(t));else if(Array.isArray(t)){e.push(O1t);let r=!0;t.forEach(s=>{r||e.push(Ube),r=!1,e.push(Y7(s))}),e.push(L1t)}else if(typeof t=="object"){e.push(M1t);let r=!0;Object.keys(t).sort().forEach(s=>{r||e.push(Ube),r=!1,e.push(_be(s)),e.push(N1t),e.push(Y7(t[s]))}),e.push(U1t)}else throw new TypeError("cannot encode "+t.toString());return e.join("")}function _be(t){return'"'+t.replace(/\\/g,"\\\\").replace(/"/g,'\\"')+'"'}Hbe.exports={canonicalize:Y7}});var jbe=_(i1=>{"use strict";var _1t=i1&&i1.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(i1,"__esModule",{value:!0});i1.verifySignature=void 0;var H1t=V7(),j1t=_1t(Ie("crypto")),G1t=(t,e,r)=>{let s=Buffer.from((0,H1t.canonicalize)(t));return j1t.default.verify(void 0,s,e,Buffer.from(r,"hex"))};i1.verifySignature=G1t});var ff=_(eu=>{"use strict";var q1t=eu&&eu.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r);var a=Object.getOwnPropertyDescriptor(e,r);(!a||("get"in a?!e.__esModule:a.writable||a.configurable))&&(a={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(t,s,a)}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),W1t=eu&&eu.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),Gbe=eu&&eu.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!=="default"&&Object.prototype.hasOwnProperty.call(t,r)&&q1t(e,t,r);return W1t(e,t),e};Object.defineProperty(eu,"__esModule",{value:!0});eu.crypto=eu.guard=void 0;eu.guard=Gbe(Mbe());eu.crypto=Gbe(jbe())});var ay=_(hh=>{"use strict";var Y1t=hh&&hh.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(hh,"__esModule",{value:!0});hh.Signed=hh.MetadataKind=void 0;hh.isMetadataKind=J1t;var V1t=Y1t(Ie("util")),Qb=PA(),J7=ff(),qbe=["1","0","31"],K7;(function(t){t.Root="root",t.Timestamp="timestamp",t.Snapshot="snapshot",t.Targets="targets"})(K7||(hh.MetadataKind=K7={}));function J1t(t){return typeof t=="string"&&Object.values(K7).includes(t)}var z7=class t{constructor(e){this.specVersion=e.specVersion||qbe.join(".");let r=this.specVersion.split(".");if(!(r.length===2||r.length===3)||!r.every(s=>K1t(s)))throw new Qb.ValueError("Failed to parse specVersion");if(r[0]!=qbe[0])throw new Qb.ValueError("Unsupported specVersion");this.expires=e.expires,this.version=e.version,this.unrecognizedFields=e.unrecognizedFields||{}}equals(e){return e instanceof t?this.specVersion===e.specVersion&&this.expires===e.expires&&this.version===e.version&&V1t.default.isDeepStrictEqual(this.unrecognizedFields,e.unrecognizedFields):!1}isExpired(e){return e||(e=new Date),e>=new Date(this.expires)}static commonFieldsFromJSON(e){let{spec_version:r,expires:s,version:a,...n}=e;if(J7.guard.isDefined(r)){if(typeof r!="string")throw new TypeError("spec_version must be a string")}else throw new Qb.ValueError("spec_version is not defined");if(J7.guard.isDefined(s)){if(typeof s!="string")throw new TypeError("expires must be a string")}else throw new Qb.ValueError("expires is not defined");if(J7.guard.isDefined(a)){if(typeof a!="number")throw new TypeError("version must be a number")}else throw new Qb.ValueError("version is not defined");return{specVersion:r,expires:s,version:a,unrecognizedFields:n}}};hh.Signed=z7;function K1t(t){return!isNaN(Number(t))}});var Tb=_(xg=>{"use strict";var Wbe=xg&&xg.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(xg,"__esModule",{value:!0});xg.TargetFile=xg.MetaFile=void 0;var Ybe=Wbe(Ie("crypto")),RO=Wbe(Ie("util")),Pg=PA(),TO=ff(),X7=class t{constructor(e){if(e.version<=0)throw new Pg.ValueError("Metafile version must be at least 1");e.length!==void 0&&Vbe(e.length),this.version=e.version,this.length=e.length,this.hashes=e.hashes,this.unrecognizedFields=e.unrecognizedFields||{}}equals(e){return e instanceof t?this.version===e.version&&this.length===e.length&&RO.default.isDeepStrictEqual(this.hashes,e.hashes)&&RO.default.isDeepStrictEqual(this.unrecognizedFields,e.unrecognizedFields):!1}verify(e){if(this.length!==void 0&&e.length!==this.length)throw new Pg.LengthOrHashMismatchError(`Expected length ${this.length} but got ${e.length}`);this.hashes&&Object.entries(this.hashes).forEach(([r,s])=>{let a;try{a=Ybe.default.createHash(r)}catch{throw new Pg.LengthOrHashMismatchError(`Hash algorithm ${r} not supported`)}let n=a.update(e).digest("hex");if(n!==s)throw new Pg.LengthOrHashMismatchError(`Expected hash ${s} but got ${n}`)})}toJSON(){let e={version:this.version,...this.unrecognizedFields};return this.length!==void 0&&(e.length=this.length),this.hashes&&(e.hashes=this.hashes),e}static fromJSON(e){let{version:r,length:s,hashes:a,...n}=e;if(typeof r!="number")throw new TypeError("version must be a number");if(TO.guard.isDefined(s)&&typeof s!="number")throw new TypeError("length must be a number");if(TO.guard.isDefined(a)&&!TO.guard.isStringRecord(a))throw new TypeError("hashes must be string keys and values");return new t({version:r,length:s,hashes:a,unrecognizedFields:n})}};xg.MetaFile=X7;var Z7=class t{constructor(e){Vbe(e.length),this.length=e.length,this.path=e.path,this.hashes=e.hashes,this.unrecognizedFields=e.unrecognizedFields||{}}get custom(){let e=this.unrecognizedFields.custom;return!e||Array.isArray(e)||typeof e!="object"?{}:e}equals(e){return e instanceof t?this.length===e.length&&this.path===e.path&&RO.default.isDeepStrictEqual(this.hashes,e.hashes)&&RO.default.isDeepStrictEqual(this.unrecognizedFields,e.unrecognizedFields):!1}async verify(e){let r=0,s=Object.keys(this.hashes).reduce((a,n)=>{try{a[n]=Ybe.default.createHash(n)}catch{throw new Pg.LengthOrHashMismatchError(`Hash algorithm ${n} not supported`)}return a},{});for await(let a of e)r+=a.length,Object.values(s).forEach(n=>{n.update(a)});if(r!==this.length)throw new Pg.LengthOrHashMismatchError(`Expected length ${this.length} but got ${r}`);Object.entries(s).forEach(([a,n])=>{let c=this.hashes[a],f=n.digest("hex");if(f!==c)throw new Pg.LengthOrHashMismatchError(`Expected hash ${c} but got ${f}`)})}toJSON(){return{length:this.length,hashes:this.hashes,...this.unrecognizedFields}}static fromJSON(e,r){let{length:s,hashes:a,...n}=r;if(typeof s!="number")throw new TypeError("length must be a number");if(!TO.guard.isStringRecord(a))throw new TypeError("hashes must have string keys and values");return new t({length:s,path:e,hashes:a,unrecognizedFields:n})}};xg.TargetFile=Z7;function Vbe(t){if(t<0)throw new Pg.ValueError("Length must be at least 0")}});var Jbe=_($7=>{"use strict";Object.defineProperty($7,"__esModule",{value:!0});$7.encodeOIDString=X1t;var z1t=6;function X1t(t){let e=t.split("."),r=parseInt(e[0],10)*40+parseInt(e[1],10),s=[];e.slice(2).forEach(n=>{let c=Z1t(parseInt(n,10));s.push(...c)});let a=Buffer.from([r,...s]);return Buffer.from([z1t,a.length,...a])}function Z1t(t){let e=[],r=0;for(;t>0;)e.unshift(t&127|r),t>>=7,r=128;return e}});var Zbe=_(Fb=>{"use strict";var $1t=Fb&&Fb.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(Fb,"__esModule",{value:!0});Fb.getPublicKey=n2t;var s1=$1t(Ie("crypto")),Rb=PA(),eJ=Jbe(),FO=48,Kbe=3,zbe=0,e2t="1.3.101.112",t2t="1.2.840.10045.2.1",r2t="1.2.840.10045.3.1.7",tJ="-----BEGIN PUBLIC KEY-----";function n2t(t){switch(t.keyType){case"rsa":return i2t(t);case"ed25519":return s2t(t);case"ecdsa":case"ecdsa-sha2-nistp256":case"ecdsa-sha2-nistp384":return o2t(t);default:throw new Rb.UnsupportedAlgorithmError(`Unsupported key type: ${t.keyType}`)}}function i2t(t){if(!t.keyVal.startsWith(tJ))throw new Rb.CryptoError("Invalid key format");let e=s1.default.createPublicKey(t.keyVal);switch(t.scheme){case"rsassa-pss-sha256":return{key:e,padding:s1.default.constants.RSA_PKCS1_PSS_PADDING};default:throw new Rb.UnsupportedAlgorithmError(`Unsupported RSA scheme: ${t.scheme}`)}}function s2t(t){let e;if(t.keyVal.startsWith(tJ))e=s1.default.createPublicKey(t.keyVal);else{if(!Xbe(t.keyVal))throw new Rb.CryptoError("Invalid key format");e=s1.default.createPublicKey({key:a2t.hexToDER(t.keyVal),format:"der",type:"spki"})}return{key:e}}function o2t(t){let e;if(t.keyVal.startsWith(tJ))e=s1.default.createPublicKey(t.keyVal);else{if(!Xbe(t.keyVal))throw new Rb.CryptoError("Invalid key format");e=s1.default.createPublicKey({key:l2t.hexToDER(t.keyVal),format:"der",type:"spki"})}return{key:e}}var a2t={hexToDER:t=>{let e=Buffer.from(t,"hex"),r=(0,eJ.encodeOIDString)(e2t),s=Buffer.concat([Buffer.concat([Buffer.from([FO]),Buffer.from([r.length]),r]),Buffer.concat([Buffer.from([Kbe]),Buffer.from([e.length+1]),Buffer.from([zbe]),e])]);return Buffer.concat([Buffer.from([FO]),Buffer.from([s.length]),s])}},l2t={hexToDER:t=>{let e=Buffer.from(t,"hex"),r=Buffer.concat([Buffer.from([Kbe]),Buffer.from([e.length+1]),Buffer.from([zbe]),e]),s=Buffer.concat([(0,eJ.encodeOIDString)(t2t),(0,eJ.encodeOIDString)(r2t)]),a=Buffer.concat([Buffer.from([FO]),Buffer.from([s.length]),s]);return Buffer.concat([Buffer.from([FO]),Buffer.from([a.length+r.length]),a,r])}},Xbe=t=>/^[0-9a-fA-F]+$/.test(t)});var NO=_(o1=>{"use strict";var c2t=o1&&o1.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(o1,"__esModule",{value:!0});o1.Key=void 0;var $be=c2t(Ie("util")),Nb=PA(),ePe=ff(),u2t=Zbe(),rJ=class t{constructor(e){let{keyID:r,keyType:s,scheme:a,keyVal:n,unrecognizedFields:c}=e;this.keyID=r,this.keyType=s,this.scheme=a,this.keyVal=n,this.unrecognizedFields=c||{}}verifySignature(e){let r=e.signatures[this.keyID];if(!r)throw new Nb.UnsignedMetadataError("no signature for key found in metadata");if(!this.keyVal.public)throw new Nb.UnsignedMetadataError("no public key found");let s=(0,u2t.getPublicKey)({keyType:this.keyType,scheme:this.scheme,keyVal:this.keyVal.public}),a=e.signed.toJSON();try{if(!ePe.crypto.verifySignature(a,s,r.sig))throw new Nb.UnsignedMetadataError(`failed to verify ${this.keyID} signature`)}catch(n){throw n instanceof Nb.UnsignedMetadataError?n:new Nb.UnsignedMetadataError(`failed to verify ${this.keyID} signature`)}}equals(e){return e instanceof t?this.keyID===e.keyID&&this.keyType===e.keyType&&this.scheme===e.scheme&&$be.default.isDeepStrictEqual(this.keyVal,e.keyVal)&&$be.default.isDeepStrictEqual(this.unrecognizedFields,e.unrecognizedFields):!1}toJSON(){return{keytype:this.keyType,scheme:this.scheme,keyval:this.keyVal,...this.unrecognizedFields}}static fromJSON(e,r){let{keytype:s,scheme:a,keyval:n,...c}=r;if(typeof s!="string")throw new TypeError("keytype must be a string");if(typeof a!="string")throw new TypeError("scheme must be a string");if(!ePe.guard.isStringRecord(n))throw new TypeError("keyval must be a string record");return new t({keyID:e,keyType:s,scheme:a,keyVal:n,unrecognizedFields:c})}};o1.Key=rJ});var sPe=_((air,iPe)=>{"use strict";iPe.exports=rPe;function rPe(t,e,r){t instanceof RegExp&&(t=tPe(t,r)),e instanceof RegExp&&(e=tPe(e,r));var s=nPe(t,e,r);return s&&{start:s[0],end:s[1],pre:r.slice(0,s[0]),body:r.slice(s[0]+t.length,s[1]),post:r.slice(s[1]+e.length)}}function tPe(t,e){var r=e.match(t);return r?r[0]:null}rPe.range=nPe;function nPe(t,e,r){var s,a,n,c,f,p=r.indexOf(t),h=r.indexOf(e,p+1),E=p;if(p>=0&&h>0){for(s=[],n=r.length;E>=0&&!f;)E==p?(s.push(E),p=r.indexOf(t,E+1)):s.length==1?f=[s.pop(),h]:(a=s.pop(),a=0?p:h;s.length&&(f=[n,c])}return f}});var pPe=_((lir,APe)=>{var oPe=sPe();APe.exports=p2t;var aPe="\0SLASH"+Math.random()+"\0",lPe="\0OPEN"+Math.random()+"\0",iJ="\0CLOSE"+Math.random()+"\0",cPe="\0COMMA"+Math.random()+"\0",uPe="\0PERIOD"+Math.random()+"\0";function nJ(t){return parseInt(t,10)==t?parseInt(t,10):t.charCodeAt(0)}function f2t(t){return t.split("\\\\").join(aPe).split("\\{").join(lPe).split("\\}").join(iJ).split("\\,").join(cPe).split("\\.").join(uPe)}function A2t(t){return t.split(aPe).join("\\").split(lPe).join("{").split(iJ).join("}").split(cPe).join(",").split(uPe).join(".")}function fPe(t){if(!t)return[""];var e=[],r=oPe("{","}",t);if(!r)return t.split(",");var s=r.pre,a=r.body,n=r.post,c=s.split(",");c[c.length-1]+="{"+a+"}";var f=fPe(n);return n.length&&(c[c.length-1]+=f.shift(),c.push.apply(c,f)),e.push.apply(e,c),e}function p2t(t){return t?(t.substr(0,2)==="{}"&&(t="\\{\\}"+t.substr(2)),Ob(f2t(t),!0).map(A2t)):[]}function h2t(t){return"{"+t+"}"}function g2t(t){return/^-?0\d/.test(t)}function d2t(t,e){return t<=e}function m2t(t,e){return t>=e}function Ob(t,e){var r=[],s=oPe("{","}",t);if(!s)return[t];var a=s.pre,n=s.post.length?Ob(s.post,!1):[""];if(/\$$/.test(s.pre))for(var c=0;c=0;if(!E&&!C)return s.post.match(/,.*\}/)?(t=s.pre+"{"+s.body+iJ+s.post,Ob(t)):[t];var S;if(E)S=s.body.split(/\.\./);else if(S=fPe(s.body),S.length===1&&(S=Ob(S[0],!1).map(h2t),S.length===1))return n.map(function(Ce){return s.pre+S[0]+Ce});var P;if(E){var I=nJ(S[0]),R=nJ(S[1]),N=Math.max(S[0].length,S[1].length),U=S.length==3?Math.abs(nJ(S[2])):1,W=d2t,ee=R0){var pe=new Array(me+1).join("0");ue<0?le="-"+pe+le.slice(1):le=pe+le}}P.push(le)}}else{P=[];for(var Be=0;Be{"use strict";Object.defineProperty(OO,"__esModule",{value:!0});OO.assertValidPattern=void 0;var y2t=1024*64,E2t=t=>{if(typeof t!="string")throw new TypeError("invalid pattern");if(t.length>y2t)throw new TypeError("pattern is too long")};OO.assertValidPattern=E2t});var dPe=_(LO=>{"use strict";Object.defineProperty(LO,"__esModule",{value:!0});LO.parseClass=void 0;var I2t={"[:alnum:]":["\\p{L}\\p{Nl}\\p{Nd}",!0],"[:alpha:]":["\\p{L}\\p{Nl}",!0],"[:ascii:]":["\\x00-\\x7f",!1],"[:blank:]":["\\p{Zs}\\t",!0],"[:cntrl:]":["\\p{Cc}",!0],"[:digit:]":["\\p{Nd}",!0],"[:graph:]":["\\p{Z}\\p{C}",!0,!0],"[:lower:]":["\\p{Ll}",!0],"[:print:]":["\\p{C}",!0],"[:punct:]":["\\p{P}",!0],"[:space:]":["\\p{Z}\\t\\r\\n\\v\\f",!0],"[:upper:]":["\\p{Lu}",!0],"[:word:]":["\\p{L}\\p{Nl}\\p{Nd}\\p{Pc}",!0],"[:xdigit:]":["A-Fa-f0-9",!1]},Lb=t=>t.replace(/[[\]\\-]/g,"\\$&"),C2t=t=>t.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),gPe=t=>t.join(""),w2t=(t,e)=>{let r=e;if(t.charAt(r)!=="[")throw new Error("not in a brace expression");let s=[],a=[],n=r+1,c=!1,f=!1,p=!1,h=!1,E=r,C="";e:for(;nC?s.push(Lb(C)+"-"+Lb(R)):R===C&&s.push(Lb(R)),C="",n++;continue}if(t.startsWith("-]",n+1)){s.push(Lb(R+"-")),n+=2;continue}if(t.startsWith("-",n+1)){C=R,n+=2;continue}s.push(Lb(R)),n++}if(E{"use strict";Object.defineProperty(MO,"__esModule",{value:!0});MO.unescape=void 0;var B2t=(t,{windowsPathsNoEscape:e=!1}={})=>e?t.replace(/\[([^\/\\])\]/g,"$1"):t.replace(/((?!\\).|^)\[([^\/\\])\]/g,"$1$2").replace(/\\([^\/])/g,"$1");MO.unescape=B2t});var aJ=_(jO=>{"use strict";Object.defineProperty(jO,"__esModule",{value:!0});jO.AST=void 0;var v2t=dPe(),_O=UO(),S2t=new Set(["!","?","+","*","@"]),mPe=t=>S2t.has(t),D2t="(?!(?:^|/)\\.\\.?(?:$|/))",HO="(?!\\.)",b2t=new Set(["[","."]),P2t=new Set(["..","."]),x2t=new Set("().*{}+?[]^$\\!"),k2t=t=>t.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),oJ="[^/]",yPe=oJ+"*?",EPe=oJ+"+?",sJ=class t{type;#t;#r;#i=!1;#e=[];#n;#o;#l;#a=!1;#s;#c;#f=!1;constructor(e,r,s={}){this.type=e,e&&(this.#r=!0),this.#n=r,this.#t=this.#n?this.#n.#t:this,this.#s=this.#t===this?s:this.#t.#s,this.#l=this.#t===this?[]:this.#t.#l,e==="!"&&!this.#t.#a&&this.#l.push(this),this.#o=this.#n?this.#n.#e.length:0}get hasMagic(){if(this.#r!==void 0)return this.#r;for(let e of this.#e)if(typeof e!="string"&&(e.type||e.hasMagic))return this.#r=!0;return this.#r}toString(){return this.#c!==void 0?this.#c:this.type?this.#c=this.type+"("+this.#e.map(e=>String(e)).join("|")+")":this.#c=this.#e.map(e=>String(e)).join("")}#p(){if(this!==this.#t)throw new Error("should only call on root");if(this.#a)return this;this.toString(),this.#a=!0;let e;for(;e=this.#l.pop();){if(e.type!=="!")continue;let r=e,s=r.#n;for(;s;){for(let a=r.#o+1;!s.type&&atypeof r=="string"?r:r.toJSON()):[this.type,...this.#e.map(r=>r.toJSON())];return this.isStart()&&!this.type&&e.unshift([]),this.isEnd()&&(this===this.#t||this.#t.#a&&this.#n?.type==="!")&&e.push({}),e}isStart(){if(this.#t===this)return!0;if(!this.#n?.isStart())return!1;if(this.#o===0)return!0;let e=this.#n;for(let r=0;r{let[I,R,N,U]=typeof P=="string"?t.#h(P,this.#r,p):P.toRegExpSource(e);return this.#r=this.#r||N,this.#i=this.#i||U,I}).join(""),E="";if(this.isStart()&&typeof this.#e[0]=="string"&&!(this.#e.length===1&&P2t.has(this.#e[0]))){let I=b2t,R=r&&I.has(h.charAt(0))||h.startsWith("\\.")&&I.has(h.charAt(2))||h.startsWith("\\.\\.")&&I.has(h.charAt(4)),N=!r&&!e&&I.has(h.charAt(0));E=R?D2t:N?HO:""}let C="";return this.isEnd()&&this.#t.#a&&this.#n?.type==="!"&&(C="(?:$|\\/)"),[E+h+C,(0,_O.unescape)(h),this.#r=!!this.#r,this.#i]}let s=this.type==="*"||this.type==="+",a=this.type==="!"?"(?:(?!(?:":"(?:",n=this.#A(r);if(this.isStart()&&this.isEnd()&&!n&&this.type!=="!"){let p=this.toString();return this.#e=[p],this.type=null,this.#r=void 0,[p,(0,_O.unescape)(this.toString()),!1,!1]}let c=!s||e||r||!HO?"":this.#A(!0);c===n&&(c=""),c&&(n=`(?:${n})(?:${c})*?`);let f="";if(this.type==="!"&&this.#f)f=(this.isStart()&&!r?HO:"")+EPe;else{let p=this.type==="!"?"))"+(this.isStart()&&!r&&!e?HO:"")+yPe+")":this.type==="@"?")":this.type==="?"?")?":this.type==="+"&&c?")":this.type==="*"&&c?")?":`)${this.type}`;f=a+n+p}return[f,(0,_O.unescape)(n),this.#r=!!this.#r,this.#i]}#A(e){return this.#e.map(r=>{if(typeof r=="string")throw new Error("string type in extglob ast??");let[s,a,n,c]=r.toRegExpSource(e);return this.#i=this.#i||c,s}).filter(r=>!(this.isStart()&&this.isEnd())||!!r).join("|")}static#h(e,r,s=!1){let a=!1,n="",c=!1;for(let f=0;f{"use strict";Object.defineProperty(GO,"__esModule",{value:!0});GO.escape=void 0;var Q2t=(t,{windowsPathsNoEscape:e=!1}={})=>e?t.replace(/[?*()[\]]/g,"[$&]"):t.replace(/[?*()[\]\\]/g,"\\$&");GO.escape=Q2t});var DPe=_(pr=>{"use strict";var T2t=pr&&pr.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(pr,"__esModule",{value:!0});pr.unescape=pr.escape=pr.AST=pr.Minimatch=pr.match=pr.makeRe=pr.braceExpand=pr.defaults=pr.filter=pr.GLOBSTAR=pr.sep=pr.minimatch=void 0;var R2t=T2t(pPe()),qO=hPe(),wPe=aJ(),F2t=lJ(),N2t=UO(),O2t=(t,e,r={})=>((0,qO.assertValidPattern)(e),!r.nocomment&&e.charAt(0)==="#"?!1:new ly(e,r).match(t));pr.minimatch=O2t;var L2t=/^\*+([^+@!?\*\[\(]*)$/,M2t=t=>e=>!e.startsWith(".")&&e.endsWith(t),U2t=t=>e=>e.endsWith(t),_2t=t=>(t=t.toLowerCase(),e=>!e.startsWith(".")&&e.toLowerCase().endsWith(t)),H2t=t=>(t=t.toLowerCase(),e=>e.toLowerCase().endsWith(t)),j2t=/^\*+\.\*+$/,G2t=t=>!t.startsWith(".")&&t.includes("."),q2t=t=>t!=="."&&t!==".."&&t.includes("."),W2t=/^\.\*+$/,Y2t=t=>t!=="."&&t!==".."&&t.startsWith("."),V2t=/^\*+$/,J2t=t=>t.length!==0&&!t.startsWith("."),K2t=t=>t.length!==0&&t!=="."&&t!=="..",z2t=/^\?+([^+@!?\*\[\(]*)?$/,X2t=([t,e=""])=>{let r=BPe([t]);return e?(e=e.toLowerCase(),s=>r(s)&&s.toLowerCase().endsWith(e)):r},Z2t=([t,e=""])=>{let r=vPe([t]);return e?(e=e.toLowerCase(),s=>r(s)&&s.toLowerCase().endsWith(e)):r},$2t=([t,e=""])=>{let r=vPe([t]);return e?s=>r(s)&&s.endsWith(e):r},eBt=([t,e=""])=>{let r=BPe([t]);return e?s=>r(s)&&s.endsWith(e):r},BPe=([t])=>{let e=t.length;return r=>r.length===e&&!r.startsWith(".")},vPe=([t])=>{let e=t.length;return r=>r.length===e&&r!=="."&&r!==".."},SPe=typeof process=="object"&&process?typeof process.env=="object"&&process.env&&process.env.__MINIMATCH_TESTING_PLATFORM__||process.platform:"posix",IPe={win32:{sep:"\\"},posix:{sep:"/"}};pr.sep=SPe==="win32"?IPe.win32.sep:IPe.posix.sep;pr.minimatch.sep=pr.sep;pr.GLOBSTAR=Symbol("globstar **");pr.minimatch.GLOBSTAR=pr.GLOBSTAR;var tBt="[^/]",rBt=tBt+"*?",nBt="(?:(?!(?:\\/|^)(?:\\.{1,2})($|\\/)).)*?",iBt="(?:(?!(?:\\/|^)\\.).)*?",sBt=(t,e={})=>r=>(0,pr.minimatch)(r,t,e);pr.filter=sBt;pr.minimatch.filter=pr.filter;var tu=(t,e={})=>Object.assign({},t,e),oBt=t=>{if(!t||typeof t!="object"||!Object.keys(t).length)return pr.minimatch;let e=pr.minimatch;return Object.assign((s,a,n={})=>e(s,a,tu(t,n)),{Minimatch:class extends e.Minimatch{constructor(a,n={}){super(a,tu(t,n))}static defaults(a){return e.defaults(tu(t,a)).Minimatch}},AST:class extends e.AST{constructor(a,n,c={}){super(a,n,tu(t,c))}static fromGlob(a,n={}){return e.AST.fromGlob(a,tu(t,n))}},unescape:(s,a={})=>e.unescape(s,tu(t,a)),escape:(s,a={})=>e.escape(s,tu(t,a)),filter:(s,a={})=>e.filter(s,tu(t,a)),defaults:s=>e.defaults(tu(t,s)),makeRe:(s,a={})=>e.makeRe(s,tu(t,a)),braceExpand:(s,a={})=>e.braceExpand(s,tu(t,a)),match:(s,a,n={})=>e.match(s,a,tu(t,n)),sep:e.sep,GLOBSTAR:pr.GLOBSTAR})};pr.defaults=oBt;pr.minimatch.defaults=pr.defaults;var aBt=(t,e={})=>((0,qO.assertValidPattern)(t),e.nobrace||!/\{(?:(?!\{).)*\}/.test(t)?[t]:(0,R2t.default)(t));pr.braceExpand=aBt;pr.minimatch.braceExpand=pr.braceExpand;var lBt=(t,e={})=>new ly(t,e).makeRe();pr.makeRe=lBt;pr.minimatch.makeRe=pr.makeRe;var cBt=(t,e,r={})=>{let s=new ly(e,r);return t=t.filter(a=>s.match(a)),s.options.nonull&&!t.length&&t.push(e),t};pr.match=cBt;pr.minimatch.match=pr.match;var CPe=/[?*]|[+@!]\(.*?\)|\[|\]/,uBt=t=>t.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),ly=class{options;set;pattern;windowsPathsNoEscape;nonegate;negate;comment;empty;preserveMultipleSlashes;partial;globSet;globParts;nocase;isWindows;platform;windowsNoMagicRoot;regexp;constructor(e,r={}){(0,qO.assertValidPattern)(e),r=r||{},this.options=r,this.pattern=e,this.platform=r.platform||SPe,this.isWindows=this.platform==="win32",this.windowsPathsNoEscape=!!r.windowsPathsNoEscape||r.allowWindowsEscape===!1,this.windowsPathsNoEscape&&(this.pattern=this.pattern.replace(/\\/g,"/")),this.preserveMultipleSlashes=!!r.preserveMultipleSlashes,this.regexp=null,this.negate=!1,this.nonegate=!!r.nonegate,this.comment=!1,this.empty=!1,this.partial=!!r.partial,this.nocase=!!this.options.nocase,this.windowsNoMagicRoot=r.windowsNoMagicRoot!==void 0?r.windowsNoMagicRoot:!!(this.isWindows&&this.nocase),this.globSet=[],this.globParts=[],this.set=[],this.make()}hasMagic(){if(this.options.magicalBraces&&this.set.length>1)return!0;for(let e of this.set)for(let r of e)if(typeof r!="string")return!0;return!1}debug(...e){}make(){let e=this.pattern,r=this.options;if(!r.nocomment&&e.charAt(0)==="#"){this.comment=!0;return}if(!e){this.empty=!0;return}this.parseNegate(),this.globSet=[...new Set(this.braceExpand())],r.debug&&(this.debug=(...n)=>console.error(...n)),this.debug(this.pattern,this.globSet);let s=this.globSet.map(n=>this.slashSplit(n));this.globParts=this.preprocess(s),this.debug(this.pattern,this.globParts);let a=this.globParts.map((n,c,f)=>{if(this.isWindows&&this.windowsNoMagicRoot){let p=n[0]===""&&n[1]===""&&(n[2]==="?"||!CPe.test(n[2]))&&!CPe.test(n[3]),h=/^[a-z]:/i.test(n[0]);if(p)return[...n.slice(0,4),...n.slice(4).map(E=>this.parse(E))];if(h)return[n[0],...n.slice(1).map(E=>this.parse(E))]}return n.map(p=>this.parse(p))});if(this.debug(this.pattern,a),this.set=a.filter(n=>n.indexOf(!1)===-1),this.isWindows)for(let n=0;n=2?(e=this.firstPhasePreProcess(e),e=this.secondPhasePreProcess(e)):r>=1?e=this.levelOneOptimize(e):e=this.adjascentGlobstarOptimize(e),e}adjascentGlobstarOptimize(e){return e.map(r=>{let s=-1;for(;(s=r.indexOf("**",s+1))!==-1;){let a=s;for(;r[a+1]==="**";)a++;a!==s&&r.splice(s,a-s)}return r})}levelOneOptimize(e){return e.map(r=>(r=r.reduce((s,a)=>{let n=s[s.length-1];return a==="**"&&n==="**"?s:a===".."&&n&&n!==".."&&n!=="."&&n!=="**"?(s.pop(),s):(s.push(a),s)},[]),r.length===0?[""]:r))}levelTwoFileOptimize(e){Array.isArray(e)||(e=this.slashSplit(e));let r=!1;do{if(r=!1,!this.preserveMultipleSlashes){for(let a=1;aa&&s.splice(a+1,c-a);let f=s[a+1],p=s[a+2],h=s[a+3];if(f!==".."||!p||p==="."||p===".."||!h||h==="."||h==="..")continue;r=!0,s.splice(a,1);let E=s.slice(0);E[a]="**",e.push(E),a--}if(!this.preserveMultipleSlashes){for(let c=1;cr.length)}partsMatch(e,r,s=!1){let a=0,n=0,c=[],f="";for(;aee?r=r.slice(ie):ee>ie&&(e=e.slice(ee)))}}let{optimizationLevel:n=1}=this.options;n>=2&&(e=this.levelTwoFileOptimize(e)),this.debug("matchOne",this,{file:e,pattern:r}),this.debug("matchOne",e.length,r.length);for(var c=0,f=0,p=e.length,h=r.length;c>> no match, partial?`,e,S,r,P),S===p))}let R;if(typeof E=="string"?(R=C===E,this.debug("string match",E,C,R)):(R=E.test(C),this.debug("pattern match",E,C,R)),!R)return!1}if(c===p&&f===h)return!0;if(c===p)return s;if(f===h)return c===p-1&&e[c]==="";throw new Error("wtf?")}braceExpand(){return(0,pr.braceExpand)(this.pattern,this.options)}parse(e){(0,qO.assertValidPattern)(e);let r=this.options;if(e==="**")return pr.GLOBSTAR;if(e==="")return"";let s,a=null;(s=e.match(V2t))?a=r.dot?K2t:J2t:(s=e.match(L2t))?a=(r.nocase?r.dot?H2t:_2t:r.dot?U2t:M2t)(s[1]):(s=e.match(z2t))?a=(r.nocase?r.dot?Z2t:X2t:r.dot?$2t:eBt)(s):(s=e.match(j2t))?a=r.dot?q2t:G2t:(s=e.match(W2t))&&(a=Y2t);let n=wPe.AST.fromGlob(e,this.options).toMMPattern();return a&&typeof n=="object"&&Reflect.defineProperty(n,"test",{value:a}),n}makeRe(){if(this.regexp||this.regexp===!1)return this.regexp;let e=this.set;if(!e.length)return this.regexp=!1,this.regexp;let r=this.options,s=r.noglobstar?rBt:r.dot?nBt:iBt,a=new Set(r.nocase?["i"]:[]),n=e.map(p=>{let h=p.map(E=>{if(E instanceof RegExp)for(let C of E.flags.split(""))a.add(C);return typeof E=="string"?uBt(E):E===pr.GLOBSTAR?pr.GLOBSTAR:E._src});return h.forEach((E,C)=>{let S=h[C+1],P=h[C-1];E!==pr.GLOBSTAR||P===pr.GLOBSTAR||(P===void 0?S!==void 0&&S!==pr.GLOBSTAR?h[C+1]="(?:\\/|"+s+"\\/)?"+S:h[C]=s:S===void 0?h[C-1]=P+"(?:\\/|"+s+")?":S!==pr.GLOBSTAR&&(h[C-1]=P+"(?:\\/|\\/"+s+"\\/)"+S,h[C+1]=pr.GLOBSTAR))}),h.filter(E=>E!==pr.GLOBSTAR).join("/")}).join("|"),[c,f]=e.length>1?["(?:",")"]:["",""];n="^"+c+n+f+"$",this.negate&&(n="^(?!"+n+").+$");try{this.regexp=new RegExp(n,[...a].join(""))}catch{this.regexp=!1}return this.regexp}slashSplit(e){return this.preserveMultipleSlashes?e.split("/"):this.isWindows&&/^\/\/[^\/]+/.test(e)?["",...e.split(/\/+/)]:e.split(/\/+/)}match(e,r=this.partial){if(this.debug("match",e,this.pattern),this.comment)return!1;if(this.empty)return e==="";if(e==="/"&&r)return!0;let s=this.options;this.isWindows&&(e=e.split("\\").join("/"));let a=this.slashSplit(e);this.debug(this.pattern,"split",a);let n=this.set;this.debug(this.pattern,"set",n);let c=a[a.length-1];if(!c)for(let f=a.length-2;!c&&f>=0;f--)c=a[f];for(let f=0;f{"use strict";var bPe=ru&&ru.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(ru,"__esModule",{value:!0});ru.SuccinctRoles=ru.DelegatedRole=ru.Role=ru.TOP_LEVEL_ROLE_NAMES=void 0;var PPe=bPe(Ie("crypto")),hBt=DPe(),WO=bPe(Ie("util")),YO=PA(),cy=ff();ru.TOP_LEVEL_ROLE_NAMES=["root","targets","snapshot","timestamp"];var Mb=class t{constructor(e){let{keyIDs:r,threshold:s,unrecognizedFields:a}=e;if(gBt(r))throw new YO.ValueError("duplicate key IDs found");if(s<1)throw new YO.ValueError("threshold must be at least 1");this.keyIDs=r,this.threshold=s,this.unrecognizedFields=a||{}}equals(e){return e instanceof t?this.threshold===e.threshold&&WO.default.isDeepStrictEqual(this.keyIDs,e.keyIDs)&&WO.default.isDeepStrictEqual(this.unrecognizedFields,e.unrecognizedFields):!1}toJSON(){return{keyids:this.keyIDs,threshold:this.threshold,...this.unrecognizedFields}}static fromJSON(e){let{keyids:r,threshold:s,...a}=e;if(!cy.guard.isStringArray(r))throw new TypeError("keyids must be an array");if(typeof s!="number")throw new TypeError("threshold must be a number");return new t({keyIDs:r,threshold:s,unrecognizedFields:a})}};ru.Role=Mb;function gBt(t){return new Set(t).size!==t.length}var cJ=class t extends Mb{constructor(e){super(e);let{name:r,terminating:s,paths:a,pathHashPrefixes:n}=e;if(this.name=r,this.terminating=s,e.paths&&e.pathHashPrefixes)throw new YO.ValueError("paths and pathHashPrefixes are mutually exclusive");this.paths=a,this.pathHashPrefixes=n}equals(e){return e instanceof t?super.equals(e)&&this.name===e.name&&this.terminating===e.terminating&&WO.default.isDeepStrictEqual(this.paths,e.paths)&&WO.default.isDeepStrictEqual(this.pathHashPrefixes,e.pathHashPrefixes):!1}isDelegatedPath(e){if(this.paths)return this.paths.some(r=>mBt(e,r));if(this.pathHashPrefixes){let s=PPe.default.createHash("sha256").update(e).digest("hex");return this.pathHashPrefixes.some(a=>s.startsWith(a))}return!1}toJSON(){let e={...super.toJSON(),name:this.name,terminating:this.terminating};return this.paths&&(e.paths=this.paths),this.pathHashPrefixes&&(e.path_hash_prefixes=this.pathHashPrefixes),e}static fromJSON(e){let{keyids:r,threshold:s,name:a,terminating:n,paths:c,path_hash_prefixes:f,...p}=e;if(!cy.guard.isStringArray(r))throw new TypeError("keyids must be an array of strings");if(typeof s!="number")throw new TypeError("threshold must be a number");if(typeof a!="string")throw new TypeError("name must be a string");if(typeof n!="boolean")throw new TypeError("terminating must be a boolean");if(cy.guard.isDefined(c)&&!cy.guard.isStringArray(c))throw new TypeError("paths must be an array of strings");if(cy.guard.isDefined(f)&&!cy.guard.isStringArray(f))throw new TypeError("path_hash_prefixes must be an array of strings");return new t({keyIDs:r,threshold:s,name:a,terminating:n,paths:c,pathHashPrefixes:f,unrecognizedFields:p})}};ru.DelegatedRole=cJ;var dBt=(t,e)=>t.map((r,s)=>[r,e[s]]);function mBt(t,e){let r=t.split("/"),s=e.split("/");return s.length!=r.length?!1:dBt(r,s).every(([a,n])=>(0,hBt.minimatch)(a,n))}var uJ=class t extends Mb{constructor(e){super(e);let{bitLength:r,namePrefix:s}=e;if(r<=0||r>32)throw new YO.ValueError("bitLength must be between 1 and 32");this.bitLength=r,this.namePrefix=s,this.numberOfBins=Math.pow(2,r),this.suffixLen=(this.numberOfBins-1).toString(16).length}equals(e){return e instanceof t?super.equals(e)&&this.bitLength===e.bitLength&&this.namePrefix===e.namePrefix:!1}getRoleForTarget(e){let a=PPe.default.createHash("sha256").update(e).digest().subarray(0,4),n=32-this.bitLength,f=(a.readUInt32BE()>>>n).toString(16).padStart(this.suffixLen,"0");return`${this.namePrefix}-${f}`}*getRoles(){for(let e=0;e{"use strict";var yBt=a1&&a1.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(a1,"__esModule",{value:!0});a1.Root=void 0;var xPe=yBt(Ie("util")),AJ=ay(),kPe=PA(),EBt=NO(),VO=fJ(),JO=ff(),pJ=class t extends AJ.Signed{constructor(e){if(super(e),this.type=AJ.MetadataKind.Root,this.keys=e.keys||{},this.consistentSnapshot=e.consistentSnapshot??!0,!e.roles)this.roles=VO.TOP_LEVEL_ROLE_NAMES.reduce((r,s)=>({...r,[s]:new VO.Role({keyIDs:[],threshold:1})}),{});else{let r=new Set(Object.keys(e.roles));if(!VO.TOP_LEVEL_ROLE_NAMES.every(s=>r.has(s)))throw new kPe.ValueError("missing top-level role");this.roles=e.roles}}addKey(e,r){if(!this.roles[r])throw new kPe.ValueError(`role ${r} does not exist`);this.roles[r].keyIDs.includes(e.keyID)||this.roles[r].keyIDs.push(e.keyID),this.keys[e.keyID]=e}equals(e){return e instanceof t?super.equals(e)&&this.consistentSnapshot===e.consistentSnapshot&&xPe.default.isDeepStrictEqual(this.keys,e.keys)&&xPe.default.isDeepStrictEqual(this.roles,e.roles):!1}toJSON(){return{_type:this.type,spec_version:this.specVersion,version:this.version,expires:this.expires,keys:IBt(this.keys),roles:CBt(this.roles),consistent_snapshot:this.consistentSnapshot,...this.unrecognizedFields}}static fromJSON(e){let{unrecognizedFields:r,...s}=AJ.Signed.commonFieldsFromJSON(e),{keys:a,roles:n,consistent_snapshot:c,...f}=r;if(typeof c!="boolean")throw new TypeError("consistent_snapshot must be a boolean");return new t({...s,keys:wBt(a),roles:BBt(n),consistentSnapshot:c,unrecognizedFields:f})}};a1.Root=pJ;function IBt(t){return Object.entries(t).reduce((e,[r,s])=>({...e,[r]:s.toJSON()}),{})}function CBt(t){return Object.entries(t).reduce((e,[r,s])=>({...e,[r]:s.toJSON()}),{})}function wBt(t){let e;if(JO.guard.isDefined(t)){if(!JO.guard.isObjectRecord(t))throw new TypeError("keys must be an object");e=Object.entries(t).reduce((r,[s,a])=>({...r,[s]:EBt.Key.fromJSON(s,a)}),{})}return e}function BBt(t){let e;if(JO.guard.isDefined(t)){if(!JO.guard.isObjectRecord(t))throw new TypeError("roles must be an object");e=Object.entries(t).reduce((r,[s,a])=>({...r,[s]:VO.Role.fromJSON(a)}),{})}return e}});var dJ=_(KO=>{"use strict";Object.defineProperty(KO,"__esModule",{value:!0});KO.Signature=void 0;var gJ=class t{constructor(e){let{keyID:r,sig:s}=e;this.keyID=r,this.sig=s}toJSON(){return{keyid:this.keyID,sig:this.sig}}static fromJSON(e){let{keyid:r,sig:s}=e;if(typeof r!="string")throw new TypeError("keyid must be a string");if(typeof s!="string")throw new TypeError("sig must be a string");return new t({keyID:r,sig:s})}};KO.Signature=gJ});var EJ=_(l1=>{"use strict";var vBt=l1&&l1.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(l1,"__esModule",{value:!0});l1.Snapshot=void 0;var SBt=vBt(Ie("util")),mJ=ay(),TPe=Tb(),QPe=ff(),yJ=class t extends mJ.Signed{constructor(e){super(e),this.type=mJ.MetadataKind.Snapshot,this.meta=e.meta||{"targets.json":new TPe.MetaFile({version:1})}}equals(e){return e instanceof t?super.equals(e)&&SBt.default.isDeepStrictEqual(this.meta,e.meta):!1}toJSON(){return{_type:this.type,meta:DBt(this.meta),spec_version:this.specVersion,version:this.version,expires:this.expires,...this.unrecognizedFields}}static fromJSON(e){let{unrecognizedFields:r,...s}=mJ.Signed.commonFieldsFromJSON(e),{meta:a,...n}=r;return new t({...s,meta:bBt(a),unrecognizedFields:n})}};l1.Snapshot=yJ;function DBt(t){return Object.entries(t).reduce((e,[r,s])=>({...e,[r]:s.toJSON()}),{})}function bBt(t){let e;if(QPe.guard.isDefined(t))if(QPe.guard.isObjectRecord(t))e=Object.entries(t).reduce((r,[s,a])=>({...r,[s]:TPe.MetaFile.fromJSON(a)}),{});else throw new TypeError("meta field is malformed");return e}});var RPe=_(c1=>{"use strict";var PBt=c1&&c1.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(c1,"__esModule",{value:!0});c1.Delegations=void 0;var zO=PBt(Ie("util")),xBt=PA(),kBt=NO(),IJ=fJ(),XO=ff(),CJ=class t{constructor(e){if(this.keys=e.keys,this.unrecognizedFields=e.unrecognizedFields||{},e.roles&&Object.keys(e.roles).some(r=>IJ.TOP_LEVEL_ROLE_NAMES.includes(r)))throw new xBt.ValueError("Delegated role name conflicts with top-level role name");this.succinctRoles=e.succinctRoles,this.roles=e.roles}equals(e){return e instanceof t?zO.default.isDeepStrictEqual(this.keys,e.keys)&&zO.default.isDeepStrictEqual(this.roles,e.roles)&&zO.default.isDeepStrictEqual(this.unrecognizedFields,e.unrecognizedFields)&&zO.default.isDeepStrictEqual(this.succinctRoles,e.succinctRoles):!1}*rolesForTarget(e){if(this.roles)for(let r of Object.values(this.roles))r.isDelegatedPath(e)&&(yield{role:r.name,terminating:r.terminating});else this.succinctRoles&&(yield{role:this.succinctRoles.getRoleForTarget(e),terminating:!0})}toJSON(){let e={keys:QBt(this.keys),...this.unrecognizedFields};return this.roles?e.roles=TBt(this.roles):this.succinctRoles&&(e.succinct_roles=this.succinctRoles.toJSON()),e}static fromJSON(e){let{keys:r,roles:s,succinct_roles:a,...n}=e,c;return XO.guard.isObject(a)&&(c=IJ.SuccinctRoles.fromJSON(a)),new t({keys:RBt(r),roles:FBt(s),unrecognizedFields:n,succinctRoles:c})}};c1.Delegations=CJ;function QBt(t){return Object.entries(t).reduce((e,[r,s])=>({...e,[r]:s.toJSON()}),{})}function TBt(t){return Object.values(t).map(e=>e.toJSON())}function RBt(t){if(!XO.guard.isObjectRecord(t))throw new TypeError("keys is malformed");return Object.entries(t).reduce((e,[r,s])=>({...e,[r]:kBt.Key.fromJSON(r,s)}),{})}function FBt(t){let e;if(XO.guard.isDefined(t)){if(!XO.guard.isObjectArray(t))throw new TypeError("roles is malformed");e=t.reduce((r,s)=>{let a=IJ.DelegatedRole.fromJSON(s);return{...r,[a.name]:a}},{})}return e}});var vJ=_(u1=>{"use strict";var NBt=u1&&u1.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(u1,"__esModule",{value:!0});u1.Targets=void 0;var FPe=NBt(Ie("util")),wJ=ay(),OBt=RPe(),LBt=Tb(),ZO=ff(),BJ=class t extends wJ.Signed{constructor(e){super(e),this.type=wJ.MetadataKind.Targets,this.targets=e.targets||{},this.delegations=e.delegations}addTarget(e){this.targets[e.path]=e}equals(e){return e instanceof t?super.equals(e)&&FPe.default.isDeepStrictEqual(this.targets,e.targets)&&FPe.default.isDeepStrictEqual(this.delegations,e.delegations):!1}toJSON(){let e={_type:this.type,spec_version:this.specVersion,version:this.version,expires:this.expires,targets:MBt(this.targets),...this.unrecognizedFields};return this.delegations&&(e.delegations=this.delegations.toJSON()),e}static fromJSON(e){let{unrecognizedFields:r,...s}=wJ.Signed.commonFieldsFromJSON(e),{targets:a,delegations:n,...c}=r;return new t({...s,targets:UBt(a),delegations:_Bt(n),unrecognizedFields:c})}};u1.Targets=BJ;function MBt(t){return Object.entries(t).reduce((e,[r,s])=>({...e,[r]:s.toJSON()}),{})}function UBt(t){let e;if(ZO.guard.isDefined(t))if(ZO.guard.isObjectRecord(t))e=Object.entries(t).reduce((r,[s,a])=>({...r,[s]:LBt.TargetFile.fromJSON(s,a)}),{});else throw new TypeError("targets must be an object");return e}function _Bt(t){let e;if(ZO.guard.isDefined(t))if(ZO.guard.isObject(t))e=OBt.Delegations.fromJSON(t);else throw new TypeError("delegations must be an object");return e}});var PJ=_($O=>{"use strict";Object.defineProperty($O,"__esModule",{value:!0});$O.Timestamp=void 0;var SJ=ay(),NPe=Tb(),DJ=ff(),bJ=class t extends SJ.Signed{constructor(e){super(e),this.type=SJ.MetadataKind.Timestamp,this.snapshotMeta=e.snapshotMeta||new NPe.MetaFile({version:1})}equals(e){return e instanceof t?super.equals(e)&&this.snapshotMeta.equals(e.snapshotMeta):!1}toJSON(){return{_type:this.type,spec_version:this.specVersion,version:this.version,expires:this.expires,meta:{"snapshot.json":this.snapshotMeta.toJSON()},...this.unrecognizedFields}}static fromJSON(e){let{unrecognizedFields:r,...s}=SJ.Signed.commonFieldsFromJSON(e),{meta:a,...n}=r;return new t({...s,snapshotMeta:HBt(a),unrecognizedFields:n})}};$O.Timestamp=bJ;function HBt(t){let e;if(DJ.guard.isDefined(t)){let r=t["snapshot.json"];if(!DJ.guard.isDefined(r)||!DJ.guard.isObject(r))throw new TypeError("missing snapshot.json in meta");e=NPe.MetaFile.fromJSON(r)}return e}});var LPe=_(A1=>{"use strict";var jBt=A1&&A1.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(A1,"__esModule",{value:!0});A1.Metadata=void 0;var GBt=V7(),OPe=jBt(Ie("util")),f1=ay(),Ub=PA(),qBt=hJ(),WBt=dJ(),YBt=EJ(),VBt=vJ(),JBt=PJ(),xJ=ff(),kJ=class t{constructor(e,r,s){this.signed=e,this.signatures=r||{},this.unrecognizedFields=s||{}}sign(e,r=!0){let s=Buffer.from((0,GBt.canonicalize)(this.signed.toJSON())),a=e(s);r||(this.signatures={}),this.signatures[a.keyID]=a}verifyDelegate(e,r){let s,a={};switch(this.signed.type){case f1.MetadataKind.Root:a=this.signed.keys,s=this.signed.roles[e];break;case f1.MetadataKind.Targets:if(!this.signed.delegations)throw new Ub.ValueError(`No delegations found for ${e}`);a=this.signed.delegations.keys,this.signed.delegations.roles?s=this.signed.delegations.roles[e]:this.signed.delegations.succinctRoles&&this.signed.delegations.succinctRoles.isDelegatedRole(e)&&(s=this.signed.delegations.succinctRoles);break;default:throw new TypeError("invalid metadata type")}if(!s)throw new Ub.ValueError(`no delegation found for ${e}`);let n=new Set;if(s.keyIDs.forEach(c=>{let f=a[c];if(f)try{f.verifySignature(r),n.add(f.keyID)}catch{}}),n.sizer.toJSON()),signed:this.signed.toJSON(),...this.unrecognizedFields}}static fromJSON(e,r){let{signed:s,signatures:a,...n}=r;if(!xJ.guard.isDefined(s)||!xJ.guard.isObject(s))throw new TypeError("signed is not defined");if(e!==s._type)throw new Ub.ValueError(`expected '${e}', got ${s._type}`);if(!xJ.guard.isObjectArray(a))throw new TypeError("signatures is not an array");let c;switch(e){case f1.MetadataKind.Root:c=qBt.Root.fromJSON(s);break;case f1.MetadataKind.Timestamp:c=JBt.Timestamp.fromJSON(s);break;case f1.MetadataKind.Snapshot:c=YBt.Snapshot.fromJSON(s);break;case f1.MetadataKind.Targets:c=VBt.Targets.fromJSON(s);break;default:throw new TypeError("invalid metadata type")}let f={};return a.forEach(p=>{let h=WBt.Signature.fromJSON(p);if(f[h.keyID])throw new Ub.ValueError(`multiple signatures found for keyid: ${h.keyID}`);f[h.keyID]=h}),new t(c,f,n)}};A1.Metadata=kJ});var eL=_(Fi=>{"use strict";Object.defineProperty(Fi,"__esModule",{value:!0});Fi.Timestamp=Fi.Targets=Fi.Snapshot=Fi.Signature=Fi.Root=Fi.Metadata=Fi.Key=Fi.TargetFile=Fi.MetaFile=Fi.ValueError=Fi.MetadataKind=void 0;var KBt=ay();Object.defineProperty(Fi,"MetadataKind",{enumerable:!0,get:function(){return KBt.MetadataKind}});var zBt=PA();Object.defineProperty(Fi,"ValueError",{enumerable:!0,get:function(){return zBt.ValueError}});var MPe=Tb();Object.defineProperty(Fi,"MetaFile",{enumerable:!0,get:function(){return MPe.MetaFile}});Object.defineProperty(Fi,"TargetFile",{enumerable:!0,get:function(){return MPe.TargetFile}});var XBt=NO();Object.defineProperty(Fi,"Key",{enumerable:!0,get:function(){return XBt.Key}});var ZBt=LPe();Object.defineProperty(Fi,"Metadata",{enumerable:!0,get:function(){return ZBt.Metadata}});var $Bt=hJ();Object.defineProperty(Fi,"Root",{enumerable:!0,get:function(){return $Bt.Root}});var evt=dJ();Object.defineProperty(Fi,"Signature",{enumerable:!0,get:function(){return evt.Signature}});var tvt=EJ();Object.defineProperty(Fi,"Snapshot",{enumerable:!0,get:function(){return tvt.Snapshot}});var rvt=vJ();Object.defineProperty(Fi,"Targets",{enumerable:!0,get:function(){return rvt.Targets}});var nvt=PJ();Object.defineProperty(Fi,"Timestamp",{enumerable:!0,get:function(){return nvt.Timestamp}})});var _Pe=_((Dir,UPe)=>{var p1=1e3,h1=p1*60,g1=h1*60,uy=g1*24,ivt=uy*7,svt=uy*365.25;UPe.exports=function(t,e){e=e||{};var r=typeof t;if(r==="string"&&t.length>0)return ovt(t);if(r==="number"&&isFinite(t))return e.long?lvt(t):avt(t);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(t))};function ovt(t){if(t=String(t),!(t.length>100)){var e=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(t);if(e){var r=parseFloat(e[1]),s=(e[2]||"ms").toLowerCase();switch(s){case"years":case"year":case"yrs":case"yr":case"y":return r*svt;case"weeks":case"week":case"w":return r*ivt;case"days":case"day":case"d":return r*uy;case"hours":case"hour":case"hrs":case"hr":case"h":return r*g1;case"minutes":case"minute":case"mins":case"min":case"m":return r*h1;case"seconds":case"second":case"secs":case"sec":case"s":return r*p1;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return r;default:return}}}}function avt(t){var e=Math.abs(t);return e>=uy?Math.round(t/uy)+"d":e>=g1?Math.round(t/g1)+"h":e>=h1?Math.round(t/h1)+"m":e>=p1?Math.round(t/p1)+"s":t+"ms"}function lvt(t){var e=Math.abs(t);return e>=uy?tL(t,e,uy,"day"):e>=g1?tL(t,e,g1,"hour"):e>=h1?tL(t,e,h1,"minute"):e>=p1?tL(t,e,p1,"second"):t+" ms"}function tL(t,e,r,s){var a=e>=r*1.5;return Math.round(t/r)+" "+s+(a?"s":"")}});var QJ=_((bir,HPe)=>{function cvt(t){r.debug=r,r.default=r,r.coerce=p,r.disable=c,r.enable=a,r.enabled=f,r.humanize=_Pe(),r.destroy=h,Object.keys(t).forEach(E=>{r[E]=t[E]}),r.names=[],r.skips=[],r.formatters={};function e(E){let C=0;for(let S=0;S{if(le==="%%")return"%";ie++;let pe=r.formatters[me];if(typeof pe=="function"){let Be=N[ie];le=pe.call(U,Be),N.splice(ie,1),ie--}return le}),r.formatArgs.call(U,N),(U.log||r.log).apply(U,N)}return R.namespace=E,R.useColors=r.useColors(),R.color=r.selectColor(E),R.extend=s,R.destroy=r.destroy,Object.defineProperty(R,"enabled",{enumerable:!0,configurable:!1,get:()=>S!==null?S:(P!==r.namespaces&&(P=r.namespaces,I=r.enabled(E)),I),set:N=>{S=N}}),typeof r.init=="function"&&r.init(R),R}function s(E,C){let S=r(this.namespace+(typeof C>"u"?":":C)+E);return S.log=this.log,S}function a(E){r.save(E),r.namespaces=E,r.names=[],r.skips=[];let C=(typeof E=="string"?E:"").trim().replace(" ",",").split(",").filter(Boolean);for(let S of C)S[0]==="-"?r.skips.push(S.slice(1)):r.names.push(S)}function n(E,C){let S=0,P=0,I=-1,R=0;for(;S"-"+C)].join(",");return r.enable(""),E}function f(E){for(let C of r.skips)if(n(E,C))return!1;for(let C of r.names)if(n(E,C))return!0;return!1}function p(E){return E instanceof Error?E.stack||E.message:E}function h(){console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.")}return r.enable(r.load()),r}HPe.exports=cvt});var jPe=_((sc,rL)=>{sc.formatArgs=fvt;sc.save=Avt;sc.load=pvt;sc.useColors=uvt;sc.storage=hvt();sc.destroy=(()=>{let t=!1;return()=>{t||(t=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})();sc.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"];function uvt(){if(typeof window<"u"&&window.process&&(window.process.type==="renderer"||window.process.__nwjs))return!0;if(typeof navigator<"u"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))return!1;let t;return typeof document<"u"&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||typeof window<"u"&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||typeof navigator<"u"&&navigator.userAgent&&(t=navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/))&&parseInt(t[1],10)>=31||typeof navigator<"u"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)}function fvt(t){if(t[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+t[0]+(this.useColors?"%c ":" ")+"+"+rL.exports.humanize(this.diff),!this.useColors)return;let e="color: "+this.color;t.splice(1,0,e,"color: inherit");let r=0,s=0;t[0].replace(/%[a-zA-Z%]/g,a=>{a!=="%%"&&(r++,a==="%c"&&(s=r))}),t.splice(s,0,e)}sc.log=console.debug||console.log||(()=>{});function Avt(t){try{t?sc.storage.setItem("debug",t):sc.storage.removeItem("debug")}catch{}}function pvt(){let t;try{t=sc.storage.getItem("debug")}catch{}return!t&&typeof process<"u"&&"env"in process&&(t=process.env.DEBUG),t}function hvt(){try{return localStorage}catch{}}rL.exports=QJ()(sc);var{formatters:gvt}=rL.exports;gvt.j=function(t){try{return JSON.stringify(t)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}});var qPe=_((Zs,iL)=>{var dvt=Ie("tty"),nL=Ie("util");Zs.init=Bvt;Zs.log=Ivt;Zs.formatArgs=yvt;Zs.save=Cvt;Zs.load=wvt;Zs.useColors=mvt;Zs.destroy=nL.deprecate(()=>{},"Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.");Zs.colors=[6,2,3,4,5,1];try{let t=Ie("supports-color");t&&(t.stderr||t).level>=2&&(Zs.colors=[20,21,26,27,32,33,38,39,40,41,42,43,44,45,56,57,62,63,68,69,74,75,76,77,78,79,80,81,92,93,98,99,112,113,128,129,134,135,148,149,160,161,162,163,164,165,166,167,168,169,170,171,172,173,178,179,184,185,196,197,198,199,200,201,202,203,204,205,206,207,208,209,214,215,220,221])}catch{}Zs.inspectOpts=Object.keys(process.env).filter(t=>/^debug_/i.test(t)).reduce((t,e)=>{let r=e.substring(6).toLowerCase().replace(/_([a-z])/g,(a,n)=>n.toUpperCase()),s=process.env[e];return/^(yes|on|true|enabled)$/i.test(s)?s=!0:/^(no|off|false|disabled)$/i.test(s)?s=!1:s==="null"?s=null:s=Number(s),t[r]=s,t},{});function mvt(){return"colors"in Zs.inspectOpts?!!Zs.inspectOpts.colors:dvt.isatty(process.stderr.fd)}function yvt(t){let{namespace:e,useColors:r}=this;if(r){let s=this.color,a="\x1B[3"+(s<8?s:"8;5;"+s),n=` ${a};1m${e} \x1B[0m`;t[0]=n+t[0].split(` +`).join(` +`+n),t.push(a+"m+"+iL.exports.humanize(this.diff)+"\x1B[0m")}else t[0]=Evt()+e+" "+t[0]}function Evt(){return Zs.inspectOpts.hideDate?"":new Date().toISOString()+" "}function Ivt(...t){return process.stderr.write(nL.formatWithOptions(Zs.inspectOpts,...t)+` +`)}function Cvt(t){t?process.env.DEBUG=t:delete process.env.DEBUG}function wvt(){return process.env.DEBUG}function Bvt(t){t.inspectOpts={};let e=Object.keys(Zs.inspectOpts);for(let r=0;re.trim()).join(" ")};GPe.O=function(t){return this.inspectOpts.colors=this.useColors,nL.inspect(t,this.inspectOpts)}});var RJ=_((Pir,TJ)=>{typeof process>"u"||process.type==="renderer"||process.browser===!0||process.__nwjs?TJ.exports=jPe():TJ.exports=qPe()});var oL=_(Ki=>{"use strict";Object.defineProperty(Ki,"__esModule",{value:!0});Ki.DownloadHTTPError=Ki.DownloadLengthMismatchError=Ki.DownloadError=Ki.ExpiredMetadataError=Ki.EqualVersionError=Ki.BadVersionError=Ki.RepositoryError=Ki.PersistError=Ki.RuntimeError=Ki.ValueError=void 0;var FJ=class extends Error{};Ki.ValueError=FJ;var NJ=class extends Error{};Ki.RuntimeError=NJ;var OJ=class extends Error{};Ki.PersistError=OJ;var _b=class extends Error{};Ki.RepositoryError=_b;var sL=class extends _b{};Ki.BadVersionError=sL;var LJ=class extends sL{};Ki.EqualVersionError=LJ;var MJ=class extends _b{};Ki.ExpiredMetadataError=MJ;var Hb=class extends Error{};Ki.DownloadError=Hb;var UJ=class extends Hb{};Ki.DownloadLengthMismatchError=UJ;var _J=class extends Hb{constructor(e,r){super(e),this.statusCode=r}};Ki.DownloadHTTPError=_J});var YPe=_(d1=>{"use strict";var jJ=d1&&d1.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(d1,"__esModule",{value:!0});d1.withTempFile=void 0;var HJ=jJ(Ie("fs/promises")),vvt=jJ(Ie("os")),WPe=jJ(Ie("path")),Svt=async t=>Dvt(async e=>t(WPe.default.join(e,"tempfile")));d1.withTempFile=Svt;var Dvt=async t=>{let e=await HJ.default.realpath(vvt.default.tmpdir()),r=await HJ.default.mkdtemp(e+WPe.default.sep);try{return await t(r)}finally{await HJ.default.rm(r,{force:!0,recursive:!0,maxRetries:3})}}});var qJ=_(kg=>{"use strict";var lL=kg&&kg.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(kg,"__esModule",{value:!0});kg.DefaultFetcher=kg.BaseFetcher=void 0;var bvt=lL(RJ()),VPe=lL(Ie("fs")),Pvt=lL(CO()),xvt=lL(Ie("util")),JPe=oL(),kvt=YPe(),Qvt=(0,bvt.default)("tuf:fetch"),aL=class{async downloadFile(e,r,s){return(0,kvt.withTempFile)(async a=>{let n=await this.fetch(e),c=0,f=VPe.default.createWriteStream(a);try{for await(let p of n){let h=Buffer.from(p);if(c+=h.length,c>r)throw new JPe.DownloadLengthMismatchError("Max length reached");await Tvt(f,h)}}finally{await xvt.default.promisify(f.close).bind(f)()}return s(a)})}async downloadBytes(e,r){return this.downloadFile(e,r,async s=>{let a=VPe.default.createReadStream(s),n=[];for await(let c of a)n.push(c);return Buffer.concat(n)})}};kg.BaseFetcher=aL;var GJ=class extends aL{constructor(e={}){super(),this.timeout=e.timeout,this.retry=e.retry}async fetch(e){Qvt("GET %s",e);let r=await(0,Pvt.default)(e,{timeout:this.timeout,retry:this.retry});if(!r.ok||!r?.body)throw new JPe.DownloadHTTPError("Failed to download",r.status);return r.body}};kg.DefaultFetcher=GJ;var Tvt=async(t,e)=>new Promise((r,s)=>{t.write(e,a=>{a&&s(a),r(!0)})})});var KPe=_(cL=>{"use strict";Object.defineProperty(cL,"__esModule",{value:!0});cL.defaultConfig=void 0;cL.defaultConfig={maxRootRotations:256,maxDelegations:32,rootMaxLength:512e3,timestampMaxLength:16384,snapshotMaxLength:2e6,targetsMaxLength:5e6,prefixTargetsWithHash:!0,fetchTimeout:1e5,fetchRetries:void 0,fetchRetry:2}});var zPe=_(uL=>{"use strict";Object.defineProperty(uL,"__esModule",{value:!0});uL.TrustedMetadataStore=void 0;var Es=eL(),Hi=oL(),WJ=class{constructor(e){this.trustedSet={},this.referenceTime=new Date,this.loadTrustedRoot(e)}get root(){if(!this.trustedSet.root)throw new ReferenceError("No trusted root metadata");return this.trustedSet.root}get timestamp(){return this.trustedSet.timestamp}get snapshot(){return this.trustedSet.snapshot}get targets(){return this.trustedSet.targets}getRole(e){return this.trustedSet[e]}updateRoot(e){let r=JSON.parse(e.toString("utf8")),s=Es.Metadata.fromJSON(Es.MetadataKind.Root,r);if(s.signed.type!=Es.MetadataKind.Root)throw new Hi.RepositoryError(`Expected 'root', got ${s.signed.type}`);if(this.root.verifyDelegate(Es.MetadataKind.Root,s),s.signed.version!=this.root.signed.version+1)throw new Hi.BadVersionError(`Expected version ${this.root.signed.version+1}, got ${s.signed.version}`);return s.verifyDelegate(Es.MetadataKind.Root,s),this.trustedSet.root=s,s}updateTimestamp(e){if(this.snapshot)throw new Hi.RuntimeError("Cannot update timestamp after snapshot");if(this.root.signed.isExpired(this.referenceTime))throw new Hi.ExpiredMetadataError("Final root.json is expired");let r=JSON.parse(e.toString("utf8")),s=Es.Metadata.fromJSON(Es.MetadataKind.Timestamp,r);if(s.signed.type!=Es.MetadataKind.Timestamp)throw new Hi.RepositoryError(`Expected 'timestamp', got ${s.signed.type}`);if(this.root.verifyDelegate(Es.MetadataKind.Timestamp,s),this.timestamp){if(s.signed.version{let p=n.signed.meta[c];if(!p)throw new Hi.RepositoryError(`Missing file ${c} in new snapshot`);if(p.version{"use strict";Object.defineProperty(YJ,"__esModule",{value:!0});YJ.join=Fvt;var Rvt=Ie("url");function Fvt(t,e){return new Rvt.URL(Nvt(t)+Ovt(e)).toString()}function Nvt(t){return t.endsWith("/")?t:t+"/"}function Ovt(t){return t.startsWith("/")?t.slice(1):t}});var ZPe=_(nu=>{"use strict";var Lvt=nu&&nu.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r);var a=Object.getOwnPropertyDescriptor(e,r);(!a||("get"in a?!e.__esModule:a.writable||a.configurable))&&(a={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(t,s,a)}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),Mvt=nu&&nu.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),KJ=nu&&nu.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!=="default"&&Object.prototype.hasOwnProperty.call(t,r)&&Lvt(e,t,r);return Mvt(e,t),e},Uvt=nu&&nu.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(nu,"__esModule",{value:!0});nu.Updater=void 0;var xA=eL(),_vt=Uvt(RJ()),m1=KJ(Ie("fs")),fL=KJ(Ie("path")),Hvt=KPe(),fy=oL(),jvt=qJ(),Gvt=zPe(),jb=KJ(XPe()),VJ=(0,_vt.default)("tuf:cache"),JJ=class{constructor(e){let{metadataDir:r,metadataBaseUrl:s,targetDir:a,targetBaseUrl:n,fetcher:c,config:f}=e;this.dir=r,this.metadataBaseUrl=s,this.targetDir=a,this.targetBaseUrl=n,this.forceCache=e.forceCache??!1;let p=this.loadLocalMetadata(xA.MetadataKind.Root);this.trustedSet=new Gvt.TrustedMetadataStore(p),this.config={...Hvt.defaultConfig,...f},this.fetcher=c||new jvt.DefaultFetcher({timeout:this.config.fetchTimeout,retry:this.config.fetchRetries??this.config.fetchRetry})}async refresh(){if(this.forceCache)try{await this.loadTimestamp({checkRemote:!1})}catch{await this.loadRoot(),await this.loadTimestamp()}else await this.loadRoot(),await this.loadTimestamp();await this.loadSnapshot(),await this.loadTargets(xA.MetadataKind.Targets,xA.MetadataKind.Root)}async getTargetInfo(e){return this.trustedSet.targets||await this.refresh(),this.preorderDepthFirstWalk(e)}async downloadTarget(e,r,s){let a=r||this.generateTargetPath(e);if(!s){if(!this.targetBaseUrl)throw new fy.ValueError("Target base URL not set");s=this.targetBaseUrl}let n=e.path;if(this.trustedSet.root.signed.consistentSnapshot&&this.config.prefixTargetsWithHash){let p=Object.values(e.hashes),{dir:h,base:E}=fL.parse(n),C=`${p[0]}.${E}`;n=h?`${h}/${C}`:C}let f=jb.join(s,n);return await this.fetcher.downloadFile(f,e.length,async p=>{await e.verify(m1.createReadStream(p)),VJ("WRITE %s",a),m1.copyFileSync(p,a)}),a}async findCachedTarget(e,r){r||(r=this.generateTargetPath(e));try{if(m1.existsSync(r))return await e.verify(m1.createReadStream(r)),r}catch{return}}loadLocalMetadata(e){let r=fL.join(this.dir,`${e}.json`);return VJ("READ %s",r),m1.readFileSync(r)}async loadRoot(){let r=this.trustedSet.root.signed.version+1,s=r+this.config.maxRootRotations;for(let a=r;a0;){let{roleName:a,parentRoleName:n}=r.pop();if(s.has(a))continue;let c=(await this.loadTargets(a,n))?.signed;if(!c)continue;let f=c.targets?.[e];if(f)return f;if(s.add(a),c.delegations){let p=[],h=c.delegations.rolesForTarget(e);for(let{role:E,terminating:C}of h)if(p.push({roleName:E,parentRoleName:a}),C){r.splice(0);break}p.reverse(),r.push(...p)}}}generateTargetPath(e){if(!this.targetDir)throw new fy.ValueError("Target directory not set");let r=encodeURIComponent(e.path);return fL.join(this.targetDir,r)}persistMetadata(e,r){let s=encodeURIComponent(e);try{let a=fL.join(this.dir,`${s}.json`);VJ("WRITE %s",a),m1.writeFileSync(a,r.toString("utf8"))}catch(a){throw new fy.PersistError(`Failed to persist metadata ${s} error: ${a}`)}}};nu.Updater=JJ});var $Pe=_(Qg=>{"use strict";Object.defineProperty(Qg,"__esModule",{value:!0});Qg.Updater=Qg.BaseFetcher=Qg.TargetFile=void 0;var qvt=eL();Object.defineProperty(Qg,"TargetFile",{enumerable:!0,get:function(){return qvt.TargetFile}});var Wvt=qJ();Object.defineProperty(Qg,"BaseFetcher",{enumerable:!0,get:function(){return Wvt.BaseFetcher}});var Yvt=ZPe();Object.defineProperty(Qg,"Updater",{enumerable:!0,get:function(){return Yvt.Updater}})});var XJ=_(AL=>{"use strict";Object.defineProperty(AL,"__esModule",{value:!0});AL.TUFError=void 0;var zJ=class extends Error{constructor({code:e,message:r,cause:s}){super(r),this.code=e,this.cause=s,this.name=this.constructor.name}};AL.TUFError=zJ});var exe=_(Gb=>{"use strict";var Vvt=Gb&&Gb.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(Gb,"__esModule",{value:!0});Gb.readTarget=Kvt;var Jvt=Vvt(Ie("fs")),pL=XJ();async function Kvt(t,e){let r=await zvt(t,e);return new Promise((s,a)=>{Jvt.default.readFile(r,"utf-8",(n,c)=>{n?a(new pL.TUFError({code:"TUF_READ_TARGET_ERROR",message:`error reading target ${r}`,cause:n})):s(c)})})}async function zvt(t,e){let r;try{r=await t.getTargetInfo(e)}catch(a){throw new pL.TUFError({code:"TUF_REFRESH_METADATA_ERROR",message:"error refreshing TUF metadata",cause:a})}if(!r)throw new pL.TUFError({code:"TUF_FIND_TARGET_ERROR",message:`target ${e} not found`});let s=await t.findCachedTarget(r);if(!s)try{s=await t.downloadTarget(r)}catch(a){throw new pL.TUFError({code:"TUF_DOWNLOAD_TARGET_ERROR",message:`error downloading target ${s}`,cause:a})}return s}});var txe=_((Uir,Xvt)=>{Xvt.exports={"https://tuf-repo-cdn.sigstore.dev":{"root.json":"ewogInNpZ25hdHVyZXMiOiBbCiAgewogICAia2V5aWQiOiAiNmYyNjAwODlkNTkyM2RhZjIwMTY2Y2E2NTdjNTQzYWY2MTgzNDZhYjk3MTg4NGE5OTk2MmIwMTk4OGJiZTBjMyIsCiAgICJzaWciOiAiMzA0NjAyMjEwMDhhYjFmNmYxN2Q0ZjllNmQ3ZGNmMWM4ODkxMmI2YjUzY2MxMDM4ODY0NGFlMWYwOWJjMzdhMDgyY2QwNjAwM2UwMjIxMDBlMTQ1ZWY0YzdiNzgyZDRlODEwN2I1MzQzN2U2NjlkMDQ3Njg5MmNlOTk5OTAzYWUzM2QxNDQ0ODM2Njk5NmU3IgogIH0sCiAgewogICAia2V5aWQiOiAiZTcxYTU0ZDU0MzgzNWJhODZhZGFkOTQ2MDM3OWM3NjQxZmI4NzI2ZDE2NGVhNzY2ODAxYTFjNTIyYWJhN2VhMiIsCiAgICJzaWciOiAiMzA0NTAyMjEwMGM3NjhiMmY4NmRhOTk1NjkwMTljMTYwYTA4MWRhNTRhZTM2YzM0YzBhMzEyMGQzY2I2OWI1M2I3ZDExMzc1OGUwMjIwNGY2NzE1MThmNjE3YjIwZDQ2NTM3ZmFlNmMzYjYzYmFlODkxM2Y0ZjE5NjIxNTYxMDVjYzRmMDE5YWMzNWM2YSIKICB9LAogIHsKICAgImtleWlkIjogIjIyZjRjYWVjNmQ4ZTZmOTU1NWFmNjZiM2Q0YzNjYjA2YTNiYjIzZmRjN2UzOWM5MTZjNjFmNDYyZTZmNTJiMDYiLAogICAic2lnIjogIjMwNDUwMjIxMDBiNDQzNGU2OTk1ZDM2OGQyM2U3NDc1OWFjZDBjYjkwMTNjODNhNWQzNTExZjBmOTk3ZWM1NGM0NTZhZTQzNTBhMDIyMDE1YjBlMjY1ZDE4MmQyYjYxZGM3NGUxNTVkOThiM2MzZmJlNTY0YmEwNTI4NmFhMTRjOGRmMDJjOWI3NTY1MTYiCiAgfSwKICB7CiAgICJrZXlpZCI6ICI2MTY0MzgzODEyNWI0NDBiNDBkYjY5NDJmNWNiNWEzMWMwZGMwNDM2ODMxNmViMmFhYTU4Yjk1OTA0YTU4MjIyIiwKICAgInNpZyI6ICIzMDQ1MDIyMTAwODJjNTg0MTFkOTg5ZWI5Zjg2MTQxMDg1N2Q0MjM4MTU5MGVjOTQyNGRiZGFhNTFlNzhlZDEzNTE1NDMxOTA0ZTAyMjAxMTgxODVkYTZhNmMyOTQ3MTMxYzE3Nzk3ZTJiYjc2MjBjZTI2ZTVmMzAxZDFjZWFjNWYyYTdlNThmOWRjZjJlIgogIH0sCiAgewogICAia2V5aWQiOiAiYTY4N2U1YmY0ZmFiODJiMGVlNThkNDZlMDVjOTUzNTE0NWEyYzlhZmI0NThmNDNkNDJiNDVjYTBmZGNlMmE3MCIsCiAgICJzaWciOiAiMzA0NjAyMjEwMGM3ODUxMzg1NGNhZTljMzJlYWE2Yjg4ZTE4OTEyZjQ4MDA2YzI3NTdhMjU4ZjkxNzMxMmNhYmE3NTk0OGViOWUwMjIxMDBkOWUxYjRjZTBhZGZlOWZkMmUyMTQ4ZDdmYTI3YTJmNDBiYTExMjJiZDY5ZGE3NjEyZDhkMTc3NmIwMTNjOTFkIgogIH0sCiAgewogICAia2V5aWQiOiAiZmRmYTgzYTA3YjVhODM1ODliODdkZWQ0MWY3N2YzOWQyMzJhZDkxZjdjY2U1Mjg2OGRhY2QwNmJhMDg5ODQ5ZiIsCiAgICJzaWciOiAiMzA0NTAyMjA1NjQ4M2EyZDVkOWVhOWNlYzZlMTFlYWRmYjMzYzQ4NGI2MTQyOThmYWNhMTVhY2YxYzQzMWIxMWVkN2Y3MzRjMDIyMTAwZDBjMWQ3MjZhZjkyYTg3ZTRlNjY0NTljYTVhZGYzOGEwNWI0NGUxZjk0MzE4NDIzZjk1NGJhZThiY2E1YmIyZSIKICB9LAogIHsKICAgImtleWlkIjogImUyZjU5YWNiOTQ4ODUxOTQwN2UxOGNiZmM5MzI5NTEwYmUwM2MwNGFjYTk5MjlkMmYwMzAxMzQzZmVjODU1MjMiLAogICAic2lnIjogIjMwNDYwMjIxMDBkMDA0ZGU4ODAyNGMzMmRjNTY1M2E5ZjQ4NDNjZmM1MjE1NDI3MDQ4YWQ5NjAwZDJjZjljOTY5ZTZlZGZmM2QyMDIyMTAwZDllYmI3OThmNWZjNjZhZjEwODk5ZGVjZTAxNGE4NjI4Y2NmM2M1NDAyY2Q0YTQyNzAyMDc0NzJmOGY2ZTcxMiIKICB9LAogIHsKICAgImtleWlkIjogIjNjMzQ0YWEwNjhmZDRjYzRlODdkYzUwYjYxMmMwMjQzMWZiYzc3MWU5NTAwMzk5MzY4M2EyYjBiZjI2MGNmMGUiLAogICAic2lnIjogIjMwNDYwMjIxMDBiN2IwOTk5NmM0NWNhMmQ0YjA1NjAzZTU2YmFlZmEyOTcxOGEwYjcxMTQ3Y2Y4YzZlNjYzNDliYWE2MTQ3N2RmMDIyMTAwYzRkYTgwYzcxN2I0ZmE3YmJhMGZkNWM3MmRhOGEwNDk5MzU4YjAxMzU4YjIzMDlmNDFkMTQ1NmVhMWU3ZTFkOSIKICB9LAogIHsKICAgImtleWlkIjogImVjODE2Njk3MzRlMDE3OTk2YzViODVmM2QwMmMzZGUxZGQ0NjM3YTE1MjAxOWZlMWFmMTI1ZDJmOTM2OGI5NWUiLAogICAic2lnIjogIjMwNDYwMjIxMDBiZTk3ODJjMzA3NDRlNDExYTgyZmE4NWI1MTM4ZDYwMWNlMTQ4YmMxOTI1OGFlYzY0ZTdlYzI0NDc4ZjM4ODEyMDIyMTAwY2FlZjYzZGNhZjFhNGI5YTUwMGQzYmQwZTNmMTY0ZWMxOGYxYjYzZDdhOTQ2MGQ5YWNhYjEwNjZkYjBmMDE2ZCIKICB9LAogIHsKICAgImtleWlkIjogIjFlMWQ2NWNlOThiMTBhZGRhZDQ3NjRmZWJmN2RkYTJkMDQzNmIzZDNhMzg5MzU3OWMwZGRkYWVhMjBlNTQ4NDkiLAogICAic2lnIjogIjMwNDUwMjIwNzQ2ZWMzZjg1MzRjZTU1NTMxZDBkMDFmZjY0OTY0ZWY0NDBkMWU3ZDJjNGMxNDI0MDliOGU5NzY5ZjFhZGE2ZjAyMjEwMGUzYjkyOWZjZDkzZWExOGZlYWEwODI1ODg3YTcyMTA0ODk4NzlhNjY3ODBjMDdhODNmNGJkNDZlMmYwOWFiM2IiCiAgfQogXSwKICJzaWduZWQiOiB7CiAgIl90eXBlIjogInJvb3QiLAogICJjb25zaXN0ZW50X3NuYXBzaG90IjogdHJ1ZSwKICAiZXhwaXJlcyI6ICIyMDI1LTAyLTE5VDA4OjA0OjMyWiIsCiAgImtleXMiOiB7CiAgICIyMmY0Y2FlYzZkOGU2Zjk1NTVhZjY2YjNkNGMzY2IwNmEzYmIyM2ZkYzdlMzljOTE2YzYxZjQ2MmU2ZjUyYjA2IjogewogICAgImtleWlkX2hhc2hfYWxnb3JpdGhtcyI6IFsKICAgICAic2hhMjU2IiwKICAgICAic2hhNTEyIgogICAgXSwKICAgICJrZXl0eXBlIjogImVjZHNhIiwKICAgICJrZXl2YWwiOiB7CiAgICAgInB1YmxpYyI6ICItLS0tLUJFR0lOIFBVQkxJQyBLRVktLS0tLVxuTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFekJ6Vk9tSENQb2pNVkxTSTM2NFdpaVY4TlByRFxuNklnUnhWbGlza3ovdit5M0pFUjVtY1ZHY09ObGlEY1dNQzVKMmxmSG1qUE5QaGI0SDd4bThMemZTQT09XG4tLS0tLUVORCBQVUJMSUMgS0VZLS0tLS1cbiIKICAgIH0sCiAgICAic2NoZW1lIjogImVjZHNhLXNoYTItbmlzdHAyNTYiLAogICAgIngtdHVmLW9uLWNpLWtleW93bmVyIjogIkBzYW50aWFnb3RvcnJlcyIKICAgfSwKICAgIjYxNjQzODM4MTI1YjQ0MGI0MGRiNjk0MmY1Y2I1YTMxYzBkYzA0MzY4MzE2ZWIyYWFhNThiOTU5MDRhNTgyMjIiOiB7CiAgICAia2V5aWRfaGFzaF9hbGdvcml0aG1zIjogWwogICAgICJzaGEyNTYiLAogICAgICJzaGE1MTIiCiAgICBdLAogICAgImtleXR5cGUiOiAiZWNkc2EiLAogICAgImtleXZhbCI6IHsKICAgICAicHVibGljIjogIi0tLS0tQkVHSU4gUFVCTElDIEtFWS0tLS0tXG5NRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVpbmlrU3NBUW1Za05lSDVlWXEvQ25JekxhYWNPXG54bFNhYXdRRE93cUt5L3RDcXhxNXh4UFNKYzIxSzRXSWhzOUd5T2tLZnp1ZVkzR0lMemNNSlo0Y1d3PT1cbi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLVxuIgogICAgfSwKICAgICJzY2hlbWUiOiAiZWNkc2Etc2hhMi1uaXN0cDI1NiIsCiAgICAieC10dWYtb24tY2kta2V5b3duZXIiOiAiQGJvYmNhbGxhd2F5IgogICB9LAogICAiNmYyNjAwODlkNTkyM2RhZjIwMTY2Y2E2NTdjNTQzYWY2MTgzNDZhYjk3MTg4NGE5OTk2MmIwMTk4OGJiZTBjMyI6IHsKICAgICJrZXlpZF9oYXNoX2FsZ29yaXRobXMiOiBbCiAgICAgInNoYTI1NiIsCiAgICAgInNoYTUxMiIKICAgIF0sCiAgICAia2V5dHlwZSI6ICJlY2RzYSIsCiAgICAia2V5dmFsIjogewogICAgICJwdWJsaWMiOiAiLS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS1cbk1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRXk4WEtzbWhCWURJOEpjMEd3ekJ4ZUtheDBjbTVcblNUS0VVNjVIUEZ1blVuNDFzVDhwaTBGak00SWtIei9ZVW13bUxVTzBXdDdseGhqNkJrTElLNHFZQXc9PVxuLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tXG4iCiAgICB9LAogICAgInNjaGVtZSI6ICJlY2RzYS1zaGEyLW5pc3RwMjU2IiwKICAgICJ4LXR1Zi1vbi1jaS1rZXlvd25lciI6ICJAZGxvcmVuYyIKICAgfSwKICAgIjcyNDdmMGRiYWQ4NWIxNDdlMTg2M2JhZGU3NjEyNDNjYzc4NWRjYjdhYTQxMGU3MTA1ZGQzZDJiNjFhMzZkMmMiOiB7CiAgICAia2V5aWRfaGFzaF9hbGdvcml0aG1zIjogWwogICAgICJzaGEyNTYiLAogICAgICJzaGE1MTIiCiAgICBdLAogICAgImtleXR5cGUiOiAiZWNkc2EiLAogICAgImtleXZhbCI6IHsKICAgICAicHVibGljIjogIi0tLS0tQkVHSU4gUFVCTElDIEtFWS0tLS0tXG5NRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVXUmlHcjUraiszSjVTc0grWnRyNW5FMkgyd083XG5CVituTzNzOTNnTGNhMThxVE96SFkxb1d5QUdEeWtNU3NHVFVCU3Q5RCtBbjBLZktzRDJtZlNNNDJRPT1cbi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLVxuIgogICAgfSwKICAgICJzY2hlbWUiOiAiZWNkc2Etc2hhMi1uaXN0cDI1NiIsCiAgICAieC10dWYtb24tY2ktb25saW5lLXVyaSI6ICJnY3BrbXM6Ly9wcm9qZWN0cy9zaWdzdG9yZS1yb290LXNpZ25pbmcvbG9jYXRpb25zL2dsb2JhbC9rZXlSaW5ncy9yb290L2NyeXB0b0tleXMvdGltZXN0YW1wIgogICB9LAogICAiYTY4N2U1YmY0ZmFiODJiMGVlNThkNDZlMDVjOTUzNTE0NWEyYzlhZmI0NThmNDNkNDJiNDVjYTBmZGNlMmE3MCI6IHsKICAgICJrZXlpZF9oYXNoX2FsZ29yaXRobXMiOiBbCiAgICAgInNoYTI1NiIsCiAgICAgInNoYTUxMiIKICAgIF0sCiAgICAia2V5dHlwZSI6ICJlY2RzYSIsCiAgICAia2V5dmFsIjogewogICAgICJwdWJsaWMiOiAiLS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS1cbk1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRTBnaHJoOTJMdzFZcjNpZEdWNVdxQ3RNREI4Q3hcbitEOGhkQzR3MlpMTklwbFZSb1ZHTHNrWWEzZ2hlTXlPamlKOGtQaTE1YVEyLy83UCtvajdVdkpQR3c9PVxuLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tXG4iCiAgICB9LAogICAgInNjaGVtZSI6ICJlY2RzYS1zaGEyLW5pc3RwMjU2IiwKICAgICJ4LXR1Zi1vbi1jaS1rZXlvd25lciI6ICJAam9zaHVhZ2wiCiAgIH0sCiAgICJlNzFhNTRkNTQzODM1YmE4NmFkYWQ5NDYwMzc5Yzc2NDFmYjg3MjZkMTY0ZWE3NjY4MDFhMWM1MjJhYmE3ZWEyIjogewogICAgImtleWlkX2hhc2hfYWxnb3JpdGhtcyI6IFsKICAgICAic2hhMjU2IiwKICAgICAic2hhNTEyIgogICAgXSwKICAgICJrZXl0eXBlIjogImVjZHNhIiwKICAgICJrZXl2YWwiOiB7CiAgICAgInB1YmxpYyI6ICItLS0tLUJFR0lOIFBVQkxJQyBLRVktLS0tLVxuTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFRVhzejNTWlhGYjhqTVY0Mmo2cEpseWpialI4S1xuTjNCd29jZXhxNkxNSWI1cXNXS09RdkxOMTZOVWVmTGM0SHN3T291bVJzVlZhYWpTcFFTNmZvYmtSdz09XG4tLS0tLUVORCBQVUJMSUMgS0VZLS0tLS1cbiIKICAgIH0sCiAgICAic2NoZW1lIjogImVjZHNhLXNoYTItbmlzdHAyNTYiLAogICAgIngtdHVmLW9uLWNpLWtleW93bmVyIjogIkBtbm02NzgiCiAgIH0KICB9LAogICJyb2xlcyI6IHsKICAgInJvb3QiOiB7CiAgICAia2V5aWRzIjogWwogICAgICI2ZjI2MDA4OWQ1OTIzZGFmMjAxNjZjYTY1N2M1NDNhZjYxODM0NmFiOTcxODg0YTk5OTYyYjAxOTg4YmJlMGMzIiwKICAgICAiZTcxYTU0ZDU0MzgzNWJhODZhZGFkOTQ2MDM3OWM3NjQxZmI4NzI2ZDE2NGVhNzY2ODAxYTFjNTIyYWJhN2VhMiIsCiAgICAgIjIyZjRjYWVjNmQ4ZTZmOTU1NWFmNjZiM2Q0YzNjYjA2YTNiYjIzZmRjN2UzOWM5MTZjNjFmNDYyZTZmNTJiMDYiLAogICAgICI2MTY0MzgzODEyNWI0NDBiNDBkYjY5NDJmNWNiNWEzMWMwZGMwNDM2ODMxNmViMmFhYTU4Yjk1OTA0YTU4MjIyIiwKICAgICAiYTY4N2U1YmY0ZmFiODJiMGVlNThkNDZlMDVjOTUzNTE0NWEyYzlhZmI0NThmNDNkNDJiNDVjYTBmZGNlMmE3MCIKICAgIF0sCiAgICAidGhyZXNob2xkIjogMwogICB9LAogICAic25hcHNob3QiOiB7CiAgICAia2V5aWRzIjogWwogICAgICI3MjQ3ZjBkYmFkODViMTQ3ZTE4NjNiYWRlNzYxMjQzY2M3ODVkY2I3YWE0MTBlNzEwNWRkM2QyYjYxYTM2ZDJjIgogICAgXSwKICAgICJ0aHJlc2hvbGQiOiAxLAogICAgIngtdHVmLW9uLWNpLWV4cGlyeS1wZXJpb2QiOiAzNjUwLAogICAgIngtdHVmLW9uLWNpLXNpZ25pbmctcGVyaW9kIjogMzY1CiAgIH0sCiAgICJ0YXJnZXRzIjogewogICAgImtleWlkcyI6IFsKICAgICAiNmYyNjAwODlkNTkyM2RhZjIwMTY2Y2E2NTdjNTQzYWY2MTgzNDZhYjk3MTg4NGE5OTk2MmIwMTk4OGJiZTBjMyIsCiAgICAgImU3MWE1NGQ1NDM4MzViYTg2YWRhZDk0NjAzNzljNzY0MWZiODcyNmQxNjRlYTc2NjgwMWExYzUyMmFiYTdlYTIiLAogICAgICIyMmY0Y2FlYzZkOGU2Zjk1NTVhZjY2YjNkNGMzY2IwNmEzYmIyM2ZkYzdlMzljOTE2YzYxZjQ2MmU2ZjUyYjA2IiwKICAgICAiNjE2NDM4MzgxMjViNDQwYjQwZGI2OTQyZjVjYjVhMzFjMGRjMDQzNjgzMTZlYjJhYWE1OGI5NTkwNGE1ODIyMiIsCiAgICAgImE2ODdlNWJmNGZhYjgyYjBlZTU4ZDQ2ZTA1Yzk1MzUxNDVhMmM5YWZiNDU4ZjQzZDQyYjQ1Y2EwZmRjZTJhNzAiCiAgICBdLAogICAgInRocmVzaG9sZCI6IDMKICAgfSwKICAgInRpbWVzdGFtcCI6IHsKICAgICJrZXlpZHMiOiBbCiAgICAgIjcyNDdmMGRiYWQ4NWIxNDdlMTg2M2JhZGU3NjEyNDNjYzc4NWRjYjdhYTQxMGU3MTA1ZGQzZDJiNjFhMzZkMmMiCiAgICBdLAogICAgInRocmVzaG9sZCI6IDEsCiAgICAieC10dWYtb24tY2ktZXhwaXJ5LXBlcmlvZCI6IDcsCiAgICAieC10dWYtb24tY2ktc2lnbmluZy1wZXJpb2QiOiA0CiAgIH0KICB9LAogICJzcGVjX3ZlcnNpb24iOiAiMS4wIiwKICAidmVyc2lvbiI6IDEwLAogICJ4LXR1Zi1vbi1jaS1leHBpcnktcGVyaW9kIjogMTgyLAogICJ4LXR1Zi1vbi1jaS1zaWduaW5nLXBlcmlvZCI6IDMxCiB9Cn0=",targets:{"trusted_root.json":"ewogICJtZWRpYVR5cGUiOiAiYXBwbGljYXRpb24vdm5kLmRldi5zaWdzdG9yZS50cnVzdGVkcm9vdCtqc29uO3ZlcnNpb249MC4xIiwKICAidGxvZ3MiOiBbCiAgICB7CiAgICAgICJiYXNlVXJsIjogImh0dHBzOi8vcmVrb3Iuc2lnc3RvcmUuZGV2IiwKICAgICAgImhhc2hBbGdvcml0aG0iOiAiU0hBMl8yNTYiLAogICAgICAicHVibGljS2V5IjogewogICAgICAgICJyYXdCeXRlcyI6ICJNRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUUyRzJZKzJ0YWJkVFY1QmNHaUJJeDBhOWZBRndya0JibUxTR3RrczRMM3FYNnlZWTB6dWZCbmhDOFVyL2l5NTVHaFdQLzlBL2JZMkxoQzMwTTkrUll0dz09IiwKICAgICAgICAia2V5RGV0YWlscyI6ICJQS0lYX0VDRFNBX1AyNTZfU0hBXzI1NiIsCiAgICAgICAgInZhbGlkRm9yIjogewogICAgICAgICAgInN0YXJ0IjogIjIwMjEtMDEtMTJUMTE6NTM6MjcuMDAwWiIKICAgICAgICB9CiAgICAgIH0sCiAgICAgICJsb2dJZCI6IHsKICAgICAgICAia2V5SWQiOiAid05JOWF0UUdseitWV2ZPNkxSeWdINFFVZlkvOFc0UkZ3aVQ1aTVXUmdCMD0iCiAgICAgIH0KICAgIH0KICBdLAogICJjZXJ0aWZpY2F0ZUF1dGhvcml0aWVzIjogWwogICAgewogICAgICAic3ViamVjdCI6IHsKICAgICAgICAib3JnYW5pemF0aW9uIjogInNpZ3N0b3JlLmRldiIsCiAgICAgICAgImNvbW1vbk5hbWUiOiAic2lnc3RvcmUiCiAgICAgIH0sCiAgICAgICJ1cmkiOiAiaHR0cHM6Ly9mdWxjaW8uc2lnc3RvcmUuZGV2IiwKICAgICAgImNlcnRDaGFpbiI6IHsKICAgICAgICAiY2VydGlmaWNhdGVzIjogWwogICAgICAgICAgewogICAgICAgICAgICAicmF3Qnl0ZXMiOiAiTUlJQitEQ0NBWDZnQXdJQkFnSVROVmtEWm9DaW9mUERzeTdkZm02Z2VMYnVoekFLQmdncWhrak9QUVFEQXpBcU1SVXdFd1lEVlFRS0V3eHphV2R6ZEc5eVpTNWtaWFl4RVRBUEJnTlZCQU1UQ0hOcFozTjBiM0psTUI0WERUSXhNRE13TnpBek1qQXlPVm9YRFRNeE1ESXlNekF6TWpBeU9Wb3dLakVWTUJNR0ExVUVDaE1NYzJsbmMzUnZjbVV1WkdWMk1SRXdEd1lEVlFRREV3aHphV2R6ZEc5eVpUQjJNQkFHQnlxR1NNNDlBZ0VHQlN1QkJBQWlBMklBQkxTeUE3SWk1aytwTk84WkVXWTB5bGVtV0Rvd09rTmEza0wrR1pFNVo1R1dlaEw5L0E5YlJOQTNSYnJzWjVpMEpjYXN0YVJMN1NwNWZwL2pENWR4cWMvVWRUVm5sdlMxNmFuKzJZZnN3ZS9RdUxvbFJVQ3JjT0UyKzJpQTUrdHpkNk5tTUdRd0RnWURWUjBQQVFIL0JBUURBZ0VHTUJJR0ExVWRFd0VCL3dRSU1BWUJBZjhDQVFFd0hRWURWUjBPQkJZRUZNakZIUUJCbWlRcE1sRWs2dzJ1U3UxS0J0UHNNQjhHQTFVZEl3UVlNQmFBRk1qRkhRQkJtaVFwTWxFazZ3MnVTdTFLQnRQc01Bb0dDQ3FHU000OUJBTURBMmdBTUdVQ01IOGxpV0pmTXVpNnZYWEJoakRnWTRNd3NsbU4vVEp4VmUvODNXckZvbXdtTmYwNTZ5MVg0OEY5YzRtM2Ezb3pYQUl4QUtqUmF5NS9hai9qc0tLR0lrbVFhdGpJOHV1cEhyLytDeEZ2YUpXbXBZcU5rTERHUlUrOW9yemg1aEkyUnJjdWFRPT0iCiAgICAgICAgICB9CiAgICAgICAgXQogICAgICB9LAogICAgICAidmFsaWRGb3IiOiB7CiAgICAgICAgInN0YXJ0IjogIjIwMjEtMDMtMDdUMDM6MjA6MjkuMDAwWiIsCiAgICAgICAgImVuZCI6ICIyMDIyLTEyLTMxVDIzOjU5OjU5Ljk5OVoiCiAgICAgIH0KICAgIH0sCiAgICB7CiAgICAgICJzdWJqZWN0IjogewogICAgICAgICJvcmdhbml6YXRpb24iOiAic2lnc3RvcmUuZGV2IiwKICAgICAgICAiY29tbW9uTmFtZSI6ICJzaWdzdG9yZSIKICAgICAgfSwKICAgICAgInVyaSI6ICJodHRwczovL2Z1bGNpby5zaWdzdG9yZS5kZXYiLAogICAgICAiY2VydENoYWluIjogewogICAgICAgICJjZXJ0aWZpY2F0ZXMiOiBbCiAgICAgICAgICB7CiAgICAgICAgICAgICJyYXdCeXRlcyI6ICJNSUlDR2pDQ0FhR2dBd0lCQWdJVUFMblZpVmZuVTBickphc21Sa0hybi9VbmZhUXdDZ1lJS29aSXpqMEVBd013S2pFVk1CTUdBMVVFQ2hNTWMybG5jM1J2Y21VdVpHVjJNUkV3RHdZRFZRUURFd2h6YVdkemRHOXlaVEFlRncweU1qQTBNVE15TURBMk1UVmFGdzB6TVRFd01EVXhNelUyTlRoYU1EY3hGVEFUQmdOVkJBb1RESE5wWjNOMGIzSmxMbVJsZGpFZU1Cd0dBMVVFQXhNVmMybG5jM1J2Y21VdGFXNTBaWEp0WldScFlYUmxNSFl3RUFZSEtvWkl6ajBDQVFZRks0RUVBQ0lEWWdBRThSVlMveXNIK05PdnVEWnlQSVp0aWxnVUY5TmxhcllwQWQ5SFAxdkJCSDFVNUNWNzdMU1M3czBaaUg0bkU3SHY3cHRTNkx2dlIvU1RrNzk4TFZnTXpMbEo0SGVJZkYzdEhTYWV4TGNZcFNBU3Ixa1MwTi9SZ0JKei85aldDaVhubzNzd2VUQU9CZ05WSFE4QkFmOEVCQU1DQVFZd0V3WURWUjBsQkF3d0NnWUlLd1lCQlFVSEF3TXdFZ1lEVlIwVEFRSC9CQWd3QmdFQi93SUJBREFkQmdOVkhRNEVGZ1FVMzlQcHoxWWtFWmI1cU5qcEtGV2l4aTRZWkQ4d0h3WURWUjBqQkJnd0ZvQVVXTUFlWDVGRnBXYXBlc3lRb1pNaTBDckZ4Zm93Q2dZSUtvWkl6ajBFQXdNRFp3QXdaQUl3UENzUUs0RFlpWllEUElhRGk1SEZLbmZ4WHg2QVNTVm1FUmZzeW5ZQmlYMlg2U0pSblpVODQvOURaZG5GdnZ4bUFqQk90NlFwQmxjNEovMER4dmtUQ3FwY2x2emlMNkJDQ1BuamRsSUIzUHUzQnhzUG15Z1VZN0lpMnpiZENkbGlpb3c9IgogICAgICAgICAgfSwKICAgICAgICAgIHsKICAgICAgICAgICAgInJhd0J5dGVzIjogIk1JSUI5ekNDQVh5Z0F3SUJBZ0lVQUxaTkFQRmR4SFB3amVEbG9Ed3lZQ2hBTy80d0NnWUlLb1pJemowRUF3TXdLakVWTUJNR0ExVUVDaE1NYzJsbmMzUnZjbVV1WkdWMk1SRXdEd1lEVlFRREV3aHphV2R6ZEc5eVpUQWVGdzB5TVRFd01EY3hNelUyTlRsYUZ3MHpNVEV3TURVeE16VTJOVGhhTUNveEZUQVRCZ05WQkFvVERITnBaM04wYjNKbExtUmxkakVSTUE4R0ExVUVBeE1JYzJsbmMzUnZjbVV3ZGpBUUJnY3Foa2pPUFFJQkJnVXJnUVFBSWdOaUFBVDdYZUZUNHJiM1BRR3dTNElhanRMazMvT2xucGdhbmdhQmNsWXBzWUJyNWkrNHluQjA3Y2ViM0xQME9JT1pkeGV4WDY5YzVpVnV5SlJRK0h6MDV5aStVRjN1QldBbEhwaVM1c2gwK0gyR0hFN1NYcmsxRUM1bTFUcjE5TDlnZzkyall6QmhNQTRHQTFVZER3RUIvd1FFQXdJQkJqQVBCZ05WSFJNQkFmOEVCVEFEQVFIL01CMEdBMVVkRGdRV0JCUll3QjVma1VXbFpxbDZ6SkNoa3lMUUtzWEYrakFmQmdOVkhTTUVHREFXZ0JSWXdCNWZrVVdsWnFsNnpKQ2hreUxRS3NYRitqQUtCZ2dxaGtqT1BRUURBd05wQURCbUFqRUFqMW5IZVhacCsxM05XQk5hK0VEc0RQOEcxV1dnMXRDTVdQL1dIUHFwYVZvMGpoc3dlTkZaZ1NzMGVFN3dZSTRxQWpFQTJXQjlvdDk4c0lrb0YzdlpZZGQzL1Z0V0I1YjlUTk1lYTdJeC9zdEo1VGZjTExlQUJMRTRCTkpPc1E0dm5CSEoiCiAgICAgICAgICB9CiAgICAgICAgXQogICAgICB9LAogICAgICAidmFsaWRGb3IiOiB7CiAgICAgICAgInN0YXJ0IjogIjIwMjItMDQtMTNUMjA6MDY6MTUuMDAwWiIKICAgICAgfQogICAgfQogIF0sCiAgImN0bG9ncyI6IFsKICAgIHsKICAgICAgImJhc2VVcmwiOiAiaHR0cHM6Ly9jdGZlLnNpZ3N0b3JlLmRldi90ZXN0IiwKICAgICAgImhhc2hBbGdvcml0aG0iOiAiU0hBMl8yNTYiLAogICAgICAicHVibGljS2V5IjogewogICAgICAgICJyYXdCeXRlcyI6ICJNRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUViZndSK1JKdWRYc2NnUkJScEtYMVhGRHkzUHl1ZER4ei9TZm5SaTFmVDhla3BmQmQyTzF1b3o3anIzWjhuS3p4QTY5RVVRK2VGQ0ZJM3pldWJQV1U3dz09IiwKICAgICAgICAia2V5RGV0YWlscyI6ICJQS0lYX0VDRFNBX1AyNTZfU0hBXzI1NiIsCiAgICAgICAgInZhbGlkRm9yIjogewogICAgICAgICAgInN0YXJ0IjogIjIwMjEtMDMtMTRUMDA6MDA6MDAuMDAwWiIsCiAgICAgICAgICAiZW5kIjogIjIwMjItMTAtMzFUMjM6NTk6NTkuOTk5WiIKICAgICAgICB9CiAgICAgIH0sCiAgICAgICJsb2dJZCI6IHsKICAgICAgICAia2V5SWQiOiAiQ0dDUzhDaFMvMmhGMGRGcko0U2NSV2NZckJZOXd6alNiZWE4SWdZMmIzST0iCiAgICAgIH0KICAgIH0sCiAgICB7CiAgICAgICJiYXNlVXJsIjogImh0dHBzOi8vY3RmZS5zaWdzdG9yZS5kZXYvMjAyMiIsCiAgICAgICJoYXNoQWxnb3JpdGhtIjogIlNIQTJfMjU2IiwKICAgICAgInB1YmxpY0tleSI6IHsKICAgICAgICAicmF3Qnl0ZXMiOiAiTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFaVBTbEZpMENtRlRmRWpDVXFGOUh1Q0VjWVhOS0FhWWFsSUptQlo4eXllelBqVHFoeHJLQnBNbmFvY1Z0TEpCSTFlTTN1WG5RelFHQUpkSjRnczlGeXc9PSIsCiAgICAgICAgImtleURldGFpbHMiOiAiUEtJWF9FQ0RTQV9QMjU2X1NIQV8yNTYiLAogICAgICAgICJ2YWxpZEZvciI6IHsKICAgICAgICAgICJzdGFydCI6ICIyMDIyLTEwLTIwVDAwOjAwOjAwLjAwMFoiCiAgICAgICAgfQogICAgICB9LAogICAgICAibG9nSWQiOiB7CiAgICAgICAgImtleUlkIjogIjNUMHdhc2JIRVRKakdSNGNtV2MzQXFKS1hyamVQSzMvaDRweWdDOHA3bzQ9IgogICAgICB9CiAgICB9CiAgXSwKICAidGltZXN0YW1wQXV0aG9yaXRpZXMiOiBbCiAgICB7CiAgICAgICJzdWJqZWN0IjogewogICAgICAgICJvcmdhbml6YXRpb24iOiAiR2l0SHViLCBJbmMuIiwKICAgICAgICAiY29tbW9uTmFtZSI6ICJJbnRlcm5hbCBTZXJ2aWNlcyBSb290IgogICAgICB9LAogICAgICAiY2VydENoYWluIjogewogICAgICAgICJjZXJ0aWZpY2F0ZXMiOiBbCiAgICAgICAgICB7CiAgICAgICAgICAgICJyYXdCeXRlcyI6ICJNSUlCM0RDQ0FXS2dBd0lCQWdJVWNoa05zSDM2WGEwNGIxTHFJYytxcjlEVmVjTXdDZ1lJS29aSXpqMEVBd013TWpFVk1CTUdBMVVFQ2hNTVIybDBTSFZpTENCSmJtTXVNUmt3RndZRFZRUURFeEJVVTBFZ2FXNTBaWEp0WldScFlYUmxNQjRYRFRJek1EUXhOREF3TURBd01Gb1hEVEkwTURReE16QXdNREF3TUZvd01qRVZNQk1HQTFVRUNoTU1SMmwwU0hWaUxDQkpibU11TVJrd0Z3WURWUVFERXhCVVUwRWdWR2x0WlhOMFlXMXdhVzVuTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFVUQ1Wk5iU3FZTWQ2cjhxcE9PRVg5aWJHblpUOUdzdVhPaHIvZjhVOUZKdWdCR0V4S1lwNDBPVUxTMGVyalpXN3hWOXhWNTJObkpmNU9lRHE0ZTVaS3FOV01GUXdEZ1lEVlIwUEFRSC9CQVFEQWdlQU1CTUdBMVVkSlFRTU1Bb0dDQ3NHQVFVRkJ3TUlNQXdHQTFVZEV3RUIvd1FDTUFBd0h3WURWUjBqQkJnd0ZvQVVhVzFSdWRPZ1Z0MGxlcVkwV0tZYnVQcjQ3d0F3Q2dZSUtvWkl6ajBFQXdNRGFBQXdaUUl3YlVIOUh2RDRlakNaSk9XUW5xQWxrcVVSbGx2dTlNOCtWcUxiaVJLK3pTZlpDWndzaWxqUm44TVFRUlNrWEVFNUFqRUFnK1Z4cXRvamZWZnU4RGh6emhDeDlHS0VUYkpIYjE5aVY3Mm1NS1ViREFGbXpaNmJROGI1NFpiOHRpZHk1YVdlIgogICAgICAgICAgfSwKICAgICAgICAgIHsKICAgICAgICAgICAgInJhd0J5dGVzIjogIk1JSUNFRENDQVpXZ0F3SUJBZ0lVWDhaTzVRWFA3dk40ZE1RNWU5c1UzbnViOE9nd0NnWUlLb1pJemowRUF3TXdPREVWTUJNR0ExVUVDaE1NUjJsMFNIVmlMQ0JKYm1NdU1SOHdIUVlEVlFRREV4WkpiblJsY201aGJDQlRaWEoyYVdObGN5QlNiMjkwTUI0WERUSXpNRFF4TkRBd01EQXdNRm9YRFRJNE1EUXhNakF3TURBd01Gb3dNakVWTUJNR0ExVUVDaE1NUjJsMFNIVmlMQ0JKYm1NdU1Sa3dGd1lEVlFRREV4QlVVMEVnYVc1MFpYSnRaV1JwWVhSbE1IWXdFQVlIS29aSXpqMENBUVlGSzRFRUFDSURZZ0FFdk1MWS9kVFZidklKWUFOQXVzekV3Sm5RRTFsbGZ0eW55TUtJTWhoNDhIbXFiVnI1eWd5YnpzTFJMVktiQldPZFoyMWFlSnorZ1ppeXRaZXRxY3lGOVdsRVI1TkVNZjZKVjdaTm9qUXB4SHE0UkhHb0dTY2VRdi9xdlRpWnhFREtvMll3WkRBT0JnTlZIUThCQWY4RUJBTUNBUVl3RWdZRFZSMFRBUUgvQkFnd0JnRUIvd0lCQURBZEJnTlZIUTRFRmdRVWFXMVJ1ZE9nVnQwbGVxWTBXS1lidVByNDd3QXdId1lEVlIwakJCZ3dGb0FVOU5ZWWxvYm5BRzRjMC9xanh5SC9scS93eitRd0NnWUlLb1pJemowRUF3TURhUUF3WmdJeEFLMUIxODV5Z0NySVlGbElzM0dqc3dqbndTTUc2TFk4d29MVmRha0tEWnhWYThmOGNxTXMxRGhjeEowKzA5dzk1UUl4QU8rdEJ6Wms3dmpVSjlpSmdENFI2WldUeFFXS3FObTc0ak85OW8rbzlzdjRGSS9TWlRaVEZ5TW4wSUpFSGRObXlBPT0iCiAgICAgICAgICB9LAogICAgICAgICAgewogICAgICAgICAgICAicmF3Qnl0ZXMiOiAiTUlJQjlEQ0NBWHFnQXdJQkFnSVVhL0pBa2RVaks0SlV3c3F0YWlSSkdXaHFMU293Q2dZSUtvWkl6ajBFQXdNd09ERVZNQk1HQTFVRUNoTU1SMmwwU0hWaUxDQkpibU11TVI4d0hRWURWUVFERXhaSmJuUmxjbTVoYkNCVFpYSjJhV05sY3lCU2IyOTBNQjRYRFRJek1EUXhOREF3TURBd01Gb1hEVE16TURReE1UQXdNREF3TUZvd09ERVZNQk1HQTFVRUNoTU1SMmwwU0hWaUxDQkpibU11TVI4d0hRWURWUVFERXhaSmJuUmxjbTVoYkNCVFpYSjJhV05sY3lCU2IyOTBNSFl3RUFZSEtvWkl6ajBDQVFZRks0RUVBQ0lEWWdBRWY5akZBWHh6NGt4NjhBSFJNT2tGQmhmbERjTVR2emFYejR4L0ZDY1hqSi8xcUVLb24vcVBJR25hVVJza0R0eU5iTkRPcGVKVERERnF0NDhpTVBybnpweDZJWndxZW1mVUpONHhCRVpmemErcFl0L2l5b2QrOXRacjIwUlJXU3YvbzBVd1F6QU9CZ05WSFE4QkFmOEVCQU1DQVFZd0VnWURWUjBUQVFIL0JBZ3dCZ0VCL3dJQkFqQWRCZ05WSFE0RUZnUVU5TllZbG9ibkFHNGMwL3FqeHlIL2xxL3d6K1F3Q2dZSUtvWkl6ajBFQXdNRGFBQXdaUUl4QUxaTFo4QmdSWHpLeExNTU45VklsTytlNGhyQm5OQmdGN3R6N0hucm93djJOZXRaRXJJQUNLRnltQmx2V0R2dE1BSXdaTytraTZzc1ExYnNabzk4TzhtRUFmMk5aN2lpQ2dERFUwVndqZWNvNnp5ZWgwekJUczkvN2dWNkFITlE1M3hEIgogICAgICAgICAgfQogICAgICAgIF0KICAgICAgfSwKICAgICAgInZhbGlkRm9yIjogewogICAgICAgICJzdGFydCI6ICIyMDIzLTA0LTE0VDAwOjAwOjAwLjAwMFoiCiAgICAgIH0KICAgIH0KICBdCn0K","registry.npmjs.org%2Fkeys.json":"ewogICAgImtleXMiOiBbCiAgICAgICAgewogICAgICAgICAgICAia2V5SWQiOiAiU0hBMjU2OmpsM2J3c3d1ODBQampva0NnaDBvMnc1YzJVNExoUUFFNTdnajljejFrekEiLAogICAgICAgICAgICAia2V5VXNhZ2UiOiAibnBtOnNpZ25hdHVyZXMiLAogICAgICAgICAgICAicHVibGljS2V5IjogewogICAgICAgICAgICAgICAgInJhd0J5dGVzIjogIk1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRTFPbGIzek1BRkZ4WEtIaUlrUU81Y0ozWWhsNWk2VVBwK0lodXRlQkpidUhjQTVVb2dLbzBFV3RsV3dXNktTYUtvVE5FWUw3SmxDUWlWbmtoQmt0VWdnPT0iLAogICAgICAgICAgICAgICAgImtleURldGFpbHMiOiAiUEtJWF9FQ0RTQV9QMjU2X1NIQV8yNTYiLAogICAgICAgICAgICAgICAgInZhbGlkRm9yIjogewogICAgICAgICAgICAgICAgICAgICJzdGFydCI6ICIxOTk5LTAxLTAxVDAwOjAwOjAwLjAwMFoiLAogICAgICAgICAgICAgICAgICAgICJlbmQiOiAiMjAyNS0wMS0yOVQwMDowMDowMC4wMDBaIgogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAgICJrZXlJZCI6ICJTSEEyNTY6amwzYndzd3U4MFBqam9rQ2doMG8ydzVjMlU0TGhRQUU1N2dqOWN6MWt6QSIsCiAgICAgICAgICAgICJrZXlVc2FnZSI6ICJucG06YXR0ZXN0YXRpb25zIiwKICAgICAgICAgICAgInB1YmxpY0tleSI6IHsKICAgICAgICAgICAgICAgICJyYXdCeXRlcyI6ICJNRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUUxT2xiM3pNQUZGeFhLSGlJa1FPNWNKM1lobDVpNlVQcCtJaHV0ZUJKYnVIY0E1VW9nS28wRVd0bFd3VzZLU2FLb1RORVlMN0psQ1FpVm5raEJrdFVnZz09IiwKICAgICAgICAgICAgICAgICJrZXlEZXRhaWxzIjogIlBLSVhfRUNEU0FfUDI1Nl9TSEFfMjU2IiwKICAgICAgICAgICAgICAgICJ2YWxpZEZvciI6IHsKICAgICAgICAgICAgICAgICAgICAic3RhcnQiOiAiMjAyMi0xMi0wMVQwMDowMDowMC4wMDBaIiwKICAgICAgICAgICAgICAgICAgICAiZW5kIjogIjIwMjUtMDEtMjlUMDA6MDA6MDAuMDAwWiIKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgICAia2V5SWQiOiAiU0hBMjU2OkRoUTh3UjVBUEJ2RkhMRi8rVGMrQVl2UE9kVHBjSURxT2h4c0JIUndDN1UiLAogICAgICAgICAgICAia2V5VXNhZ2UiOiAibnBtOnNpZ25hdHVyZXMiLAogICAgICAgICAgICAicHVibGljS2V5IjogewogICAgICAgICAgICAgICAgInJhd0J5dGVzIjogIk1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRVk2WWE3VysrN2FVUHp2TVRyZXpINlljeDNjK0hPS1lDY05HeWJKWlNDSnEvZmQ3UWE4dXVBS3RkSWtVUXRRaUVLRVJoQW1FNWxNTUpoUDhPa0RPYTJnPT0iLAogICAgICAgICAgICAgICAgImtleURldGFpbHMiOiAiUEtJWF9FQ0RTQV9QMjU2X1NIQV8yNTYiLAogICAgICAgICAgICAgICAgInZhbGlkRm9yIjogewogICAgICAgICAgICAgICAgICAgICJzdGFydCI6ICIyMDI1LTAxLTEzVDAwOjAwOjAwLjAwMFoiCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICAgImtleUlkIjogIlNIQTI1NjpEaFE4d1I1QVBCdkZITEYvK1RjK0FZdlBPZFRwY0lEcU9oeHNCSFJ3QzdVIiwKICAgICAgICAgICAgImtleVVzYWdlIjogIm5wbTphdHRlc3RhdGlvbnMiLAogICAgICAgICAgICAicHVibGljS2V5IjogewogICAgICAgICAgICAgICAgInJhd0J5dGVzIjogIk1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRVk2WWE3VysrN2FVUHp2TVRyZXpINlljeDNjK0hPS1lDY05HeWJKWlNDSnEvZmQ3UWE4dXVBS3RkSWtVUXRRaUVLRVJoQW1FNWxNTUpoUDhPa0RPYTJnPT0iLAogICAgICAgICAgICAgICAgImtleURldGFpbHMiOiAiUEtJWF9FQ0RTQV9QMjU2X1NIQV8yNTYiLAogICAgICAgICAgICAgICAgInZhbGlkRm9yIjogewogICAgICAgICAgICAgICAgICAgICJzdGFydCI6ICIyMDI1LTAxLTEzVDAwOjAwOjAwLjAwMFoiCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICBdCn0K"}}}});var nxe=_(y1=>{"use strict";var rxe=y1&&y1.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(y1,"__esModule",{value:!0});y1.TUFClient=void 0;var Tg=rxe(Ie("fs")),qb=rxe(Ie("path")),Zvt=$Pe(),$vt=hL(),eSt=exe(),$J="targets",ZJ=class{constructor(e){let r=new URL(e.mirrorURL),s=encodeURIComponent(r.host+r.pathname.replace(/\/$/,"")),a=qb.default.join(e.cachePath,s);tSt(a),rSt({cachePath:a,mirrorURL:e.mirrorURL,tufRootPath:e.rootPath,forceInit:e.forceInit}),this.updater=nSt({mirrorURL:e.mirrorURL,cachePath:a,forceCache:e.forceCache,retry:e.retry,timeout:e.timeout})}async refresh(){return this.updater.refresh()}getTarget(e){return(0,eSt.readTarget)(this.updater,e)}};y1.TUFClient=ZJ;function tSt(t){let e=qb.default.join(t,$J);Tg.default.existsSync(t)||Tg.default.mkdirSync(t,{recursive:!0}),Tg.default.existsSync(e)||Tg.default.mkdirSync(e)}function rSt({cachePath:t,mirrorURL:e,tufRootPath:r,forceInit:s}){let a=qb.default.join(t,"root.json");if(!Tg.default.existsSync(a)||s)if(r)Tg.default.copyFileSync(r,a);else{let c=txe()[e];if(!c)throw new $vt.TUFError({code:"TUF_INIT_CACHE_ERROR",message:`No root.json found for mirror: ${e}`});Tg.default.writeFileSync(a,Buffer.from(c["root.json"],"base64")),Object.entries(c.targets).forEach(([f,p])=>{Tg.default.writeFileSync(qb.default.join(t,$J,f),Buffer.from(p,"base64"))})}}function nSt(t){let e={fetchTimeout:t.timeout,fetchRetry:t.retry};return new Zvt.Updater({metadataBaseUrl:t.mirrorURL,targetBaseUrl:`${t.mirrorURL}/targets`,metadataDir:t.cachePath,targetDir:qb.default.join(t.cachePath,$J),forceCache:t.forceCache,config:e})}});var hL=_(gh=>{"use strict";Object.defineProperty(gh,"__esModule",{value:!0});gh.TUFError=gh.DEFAULT_MIRROR_URL=void 0;gh.getTrustedRoot=fSt;gh.initTUF=ASt;var iSt=yb(),sSt=Obe(),oSt=nxe();gh.DEFAULT_MIRROR_URL="https://tuf-repo-cdn.sigstore.dev";var aSt="sigstore-js",lSt={retries:2},cSt=5e3,uSt="trusted_root.json";async function fSt(t={}){let r=await ixe(t).getTarget(uSt);return iSt.TrustedRoot.fromJSON(JSON.parse(r))}async function ASt(t={}){let e=ixe(t);return e.refresh().then(()=>e)}function ixe(t){return new oSt.TUFClient({cachePath:t.cachePath||(0,sSt.appDataPath)(aSt),rootPath:t.rootPath,mirrorURL:t.mirrorURL||gh.DEFAULT_MIRROR_URL,retry:t.retry??lSt,timeout:t.timeout??cSt,forceCache:t.forceCache??!1,forceInit:t.forceInit??t.force??!1})}var pSt=XJ();Object.defineProperty(gh,"TUFError",{enumerable:!0,get:function(){return pSt.TUFError}})});var sxe=_(gL=>{"use strict";Object.defineProperty(gL,"__esModule",{value:!0});gL.DSSESignatureContent=void 0;var Wb=Cl(),eK=class{constructor(e){this.env=e}compareDigest(e){return Wb.crypto.bufferEqual(e,Wb.crypto.digest("sha256",this.env.payload))}compareSignature(e){return Wb.crypto.bufferEqual(e,this.signature)}verifySignature(e){return Wb.crypto.verify(this.preAuthEncoding,e,this.signature)}get signature(){return this.env.signatures.length>0?this.env.signatures[0].sig:Buffer.from("")}get preAuthEncoding(){return Wb.dsse.preAuthEncoding(this.env.payloadType,this.env.payload)}};gL.DSSESignatureContent=eK});var oxe=_(dL=>{"use strict";Object.defineProperty(dL,"__esModule",{value:!0});dL.MessageSignatureContent=void 0;var tK=Cl(),rK=class{constructor(e,r){this.signature=e.signature,this.messageDigest=e.messageDigest.digest,this.artifact=r}compareSignature(e){return tK.crypto.bufferEqual(e,this.signature)}compareDigest(e){return tK.crypto.bufferEqual(e,this.messageDigest)}verifySignature(e){return tK.crypto.verify(this.artifact,e,this.signature)}};dL.MessageSignatureContent=rK});var lxe=_(mL=>{"use strict";Object.defineProperty(mL,"__esModule",{value:!0});mL.toSignedEntity=dSt;mL.signatureContent=axe;var nK=Cl(),hSt=sxe(),gSt=oxe();function dSt(t,e){let{tlogEntries:r,timestampVerificationData:s}=t.verificationMaterial,a=[];for(let n of r)a.push({$case:"transparency-log",tlogEntry:n});for(let n of s?.rfc3161Timestamps??[])a.push({$case:"timestamp-authority",timestamp:nK.RFC3161Timestamp.parse(n.signedTimestamp)});return{signature:axe(t,e),key:mSt(t),tlogEntries:r,timestamps:a}}function axe(t,e){switch(t.content.$case){case"dsseEnvelope":return new hSt.DSSESignatureContent(t.content.dsseEnvelope);case"messageSignature":return new gSt.MessageSignatureContent(t.content.messageSignature,e)}}function mSt(t){switch(t.verificationMaterial.content.$case){case"publicKey":return{$case:"public-key",hint:t.verificationMaterial.content.publicKey.hint};case"x509CertificateChain":return{$case:"certificate",certificate:nK.X509Certificate.parse(t.verificationMaterial.content.x509CertificateChain.certificates[0].rawBytes)};case"certificate":return{$case:"certificate",certificate:nK.X509Certificate.parse(t.verificationMaterial.content.certificate.rawBytes)}}}});var Eo=_(E1=>{"use strict";Object.defineProperty(E1,"__esModule",{value:!0});E1.PolicyError=E1.VerificationError=void 0;var yL=class extends Error{constructor({code:e,message:r,cause:s}){super(r),this.code=e,this.cause=s,this.name=this.constructor.name}},iK=class extends yL{};E1.VerificationError=iK;var sK=class extends yL{};E1.PolicyError=sK});var cxe=_(EL=>{"use strict";Object.defineProperty(EL,"__esModule",{value:!0});EL.filterCertAuthorities=ySt;EL.filterTLogAuthorities=ESt;function ySt(t,e){return t.filter(r=>r.validFor.start<=e.start&&r.validFor.end>=e.end)}function ESt(t,e){return t.filter(r=>e.logID&&!r.logID.equals(e.logID)?!1:r.validFor.start<=e.targetDate&&e.targetDate<=r.validFor.end)}});var py=_(Ay=>{"use strict";Object.defineProperty(Ay,"__esModule",{value:!0});Ay.filterTLogAuthorities=Ay.filterCertAuthorities=void 0;Ay.toTrustMaterial=CSt;var oK=Cl(),Yb=yb(),ISt=Eo(),aK=new Date(0),lK=new Date(864e13),Axe=cxe();Object.defineProperty(Ay,"filterCertAuthorities",{enumerable:!0,get:function(){return Axe.filterCertAuthorities}});Object.defineProperty(Ay,"filterTLogAuthorities",{enumerable:!0,get:function(){return Axe.filterTLogAuthorities}});function CSt(t,e){let r=typeof e=="function"?e:wSt(e);return{certificateAuthorities:t.certificateAuthorities.map(fxe),timestampAuthorities:t.timestampAuthorities.map(fxe),tlogs:t.tlogs.map(uxe),ctlogs:t.ctlogs.map(uxe),publicKey:r}}function uxe(t){let e=t.publicKey.keyDetails,r=e===Yb.PublicKeyDetails.PKCS1_RSA_PKCS1V5||e===Yb.PublicKeyDetails.PKIX_RSA_PKCS1V5||e===Yb.PublicKeyDetails.PKIX_RSA_PKCS1V15_2048_SHA256||e===Yb.PublicKeyDetails.PKIX_RSA_PKCS1V15_3072_SHA256||e===Yb.PublicKeyDetails.PKIX_RSA_PKCS1V15_4096_SHA256?"pkcs1":"spki";return{logID:t.logId.keyId,publicKey:oK.crypto.createPublicKey(t.publicKey.rawBytes,r),validFor:{start:t.publicKey.validFor?.start||aK,end:t.publicKey.validFor?.end||lK}}}function fxe(t){return{certChain:t.certChain.certificates.map(e=>oK.X509Certificate.parse(e.rawBytes)),validFor:{start:t.validFor?.start||aK,end:t.validFor?.end||lK}}}function wSt(t){return e=>{let r=(t||{})[e];if(!r)throw new ISt.VerificationError({code:"PUBLIC_KEY_ERROR",message:`key not found: ${e}`});return{publicKey:oK.crypto.createPublicKey(r.rawBytes),validFor:s=>(r.validFor?.start||aK)<=s&&(r.validFor?.end||lK)>=s}}}});var cK=_(Vb=>{"use strict";Object.defineProperty(Vb,"__esModule",{value:!0});Vb.CertificateChainVerifier=void 0;Vb.verifyCertificateChain=vSt;var hy=Eo(),BSt=py();function vSt(t,e){let r=(0,BSt.filterCertAuthorities)(e,{start:t.notBefore,end:t.notAfter}),s;for(let a of r)try{return new IL({trustedCerts:a.certChain,untrustedCert:t}).verify()}catch(n){s=n}throw new hy.VerificationError({code:"CERTIFICATE_ERROR",message:"Failed to verify certificate chain",cause:s})}var IL=class{constructor(e){this.untrustedCert=e.untrustedCert,this.trustedCerts=e.trustedCerts,this.localCerts=SSt([...e.trustedCerts,e.untrustedCert])}verify(){let e=this.sort();return this.checkPath(e),e}sort(){let e=this.untrustedCert,r=this.buildPaths(e);if(r=r.filter(a=>a.some(n=>this.trustedCerts.includes(n))),r.length===0)throw new hy.VerificationError({code:"CERTIFICATE_ERROR",message:"no trusted certificate path found"});let s=r.reduce((a,n)=>a.length{if(s&&a.extSubjectKeyID){a.extSubjectKeyID.keyIdentifier.equals(s)&&r.push(a);return}a.subject.equals(e.issuer)&&r.push(a)}),r=r.filter(a=>{try{return e.verify(a)}catch{return!1}}),r)}checkPath(e){if(e.length<1)throw new hy.VerificationError({code:"CERTIFICATE_ERROR",message:"certificate chain must contain at least one certificate"});if(!e.slice(1).every(s=>s.isCA))throw new hy.VerificationError({code:"CERTIFICATE_ERROR",message:"intermediate certificate is not a CA"});for(let s=e.length-2;s>=0;s--)if(!e[s].issuer.equals(e[s+1].subject))throw new hy.VerificationError({code:"CERTIFICATE_ERROR",message:"incorrect certificate name chaining"});for(let s=0;s{"use strict";Object.defineProperty(uK,"__esModule",{value:!0});uK.verifySCTs=PSt;var CL=Cl(),DSt=Eo(),bSt=py();function PSt(t,e,r){let s,a=t.clone();for(let p=0;p{if(!(0,bSt.filterTLogAuthorities)(r,{logID:p.logID,targetDate:p.datetime}).some(C=>p.verify(n.buffer,C.publicKey)))throw new DSt.VerificationError({code:"CERTIFICATE_ERROR",message:"SCT verification failed"});return p.logID})}});var gxe=_(wL=>{"use strict";Object.defineProperty(wL,"__esModule",{value:!0});wL.verifyPublicKey=FSt;wL.verifyCertificate=NSt;var xSt=Cl(),hxe=Eo(),kSt=cK(),QSt=pxe(),TSt="1.3.6.1.4.1.57264.1.1",RSt="1.3.6.1.4.1.57264.1.8";function FSt(t,e,r){let s=r.publicKey(t);return e.forEach(a=>{if(!s.validFor(a))throw new hxe.VerificationError({code:"PUBLIC_KEY_ERROR",message:`Public key is not valid for timestamp: ${a.toISOString()}`})}),{key:s.publicKey}}function NSt(t,e,r){let s=(0,kSt.verifyCertificateChain)(t,r.certificateAuthorities);if(!e.every(n=>s.every(c=>c.validForDate(n))))throw new hxe.VerificationError({code:"CERTIFICATE_ERROR",message:"certificate is not valid or expired at the specified date"});return{scts:(0,QSt.verifySCTs)(s[0],s[1],r.ctlogs),signer:OSt(s[0])}}function OSt(t){let e,r=t.extension(RSt);r?e=r.valueObj.subs?.[0]?.value.toString("ascii"):e=t.extension(TSt)?.value.toString("ascii");let s={extensions:{issuer:e},subjectAlternativeName:t.subjectAltName};return{key:xSt.crypto.createPublicKey(t.publicKey),identity:s}}});var mxe=_(BL=>{"use strict";Object.defineProperty(BL,"__esModule",{value:!0});BL.verifySubjectAlternativeName=LSt;BL.verifyExtensions=MSt;var dxe=Eo();function LSt(t,e){if(e===void 0||!e.match(t))throw new dxe.PolicyError({code:"UNTRUSTED_SIGNER_ERROR",message:`certificate identity error - expected ${t}, got ${e}`})}function MSt(t,e={}){let r;for(r in t)if(e[r]!==t[r])throw new dxe.PolicyError({code:"UNTRUSTED_SIGNER_ERROR",message:`invalid certificate extension - expected ${r}=${t[r]}, got ${r}=${e[r]}`})}});var yxe=_(gK=>{"use strict";Object.defineProperty(gK,"__esModule",{value:!0});gK.verifyCheckpoint=HSt;var AK=Cl(),I1=Eo(),USt=py(),fK=` + +`,_St=/\u2014 (\S+) (\S+)\n/g;function HSt(t,e){let r=(0,USt.filterTLogAuthorities)(e,{targetDate:new Date(Number(t.integratedTime)*1e3)}),s=t.inclusionProof,a=pK.fromString(s.checkpoint.envelope),n=hK.fromString(a.note);if(!jSt(a,r))throw new I1.VerificationError({code:"TLOG_INCLUSION_PROOF_ERROR",message:"invalid checkpoint signature"});if(!AK.crypto.bufferEqual(n.logHash,s.rootHash))throw new I1.VerificationError({code:"TLOG_INCLUSION_PROOF_ERROR",message:"root hash mismatch"})}function jSt(t,e){let r=Buffer.from(t.note,"utf-8");return t.signatures.every(s=>{let a=e.find(n=>AK.crypto.bufferEqual(n.logID.subarray(0,4),s.keyHint));return a?AK.crypto.verify(r,a.publicKey,s.signature):!1})}var pK=class t{constructor(e,r){this.note=e,this.signatures=r}static fromString(e){if(!e.includes(fK))throw new I1.VerificationError({code:"TLOG_INCLUSION_PROOF_ERROR",message:"missing checkpoint separator"});let r=e.indexOf(fK),s=e.slice(0,r+1),n=e.slice(r+fK.length).matchAll(_St),c=Array.from(n,f=>{let[,p,h]=f,E=Buffer.from(h,"base64");if(E.length<5)throw new I1.VerificationError({code:"TLOG_INCLUSION_PROOF_ERROR",message:"malformed checkpoint signature"});return{name:p,keyHint:E.subarray(0,4),signature:E.subarray(4)}});if(c.length===0)throw new I1.VerificationError({code:"TLOG_INCLUSION_PROOF_ERROR",message:"no signatures found in checkpoint"});return new t(s,c)}},hK=class t{constructor(e,r,s,a){this.origin=e,this.logSize=r,this.logHash=s,this.rest=a}static fromString(e){let r=e.trimEnd().split(` +`);if(r.length<3)throw new I1.VerificationError({code:"TLOG_INCLUSION_PROOF_ERROR",message:"too few lines in checkpoint header"});let s=r[0],a=BigInt(r[1]),n=Buffer.from(r[2],"base64"),c=r.slice(3);return new t(s,a,n,c)}}});var Exe=_(EK=>{"use strict";Object.defineProperty(EK,"__esModule",{value:!0});EK.verifyMerkleInclusion=WSt;var yK=Cl(),dK=Eo(),GSt=Buffer.from([0]),qSt=Buffer.from([1]);function WSt(t){let e=t.inclusionProof,r=BigInt(e.logIndex),s=BigInt(e.treeSize);if(r<0n||r>=s)throw new dK.VerificationError({code:"TLOG_INCLUSION_PROOF_ERROR",message:`invalid index: ${r}`});let{inner:a,border:n}=YSt(r,s);if(e.hashes.length!==a+n)throw new dK.VerificationError({code:"TLOG_INCLUSION_PROOF_ERROR",message:"invalid hash count"});let c=e.hashes.slice(0,a),f=e.hashes.slice(a),p=ZSt(t.canonicalizedBody),h=JSt(VSt(p,c,r),f);if(!yK.crypto.bufferEqual(h,e.rootHash))throw new dK.VerificationError({code:"TLOG_INCLUSION_PROOF_ERROR",message:"calculated root hash does not match inclusion proof"})}function YSt(t,e){let r=KSt(t,e),s=zSt(t>>BigInt(r));return{inner:r,border:s}}function VSt(t,e,r){return e.reduce((s,a,n)=>r>>BigInt(n)&BigInt(1)?mK(a,s):mK(s,a),t)}function JSt(t,e){return e.reduce((r,s)=>mK(s,r),t)}function KSt(t,e){return XSt(t^e-BigInt(1))}function zSt(t){return t.toString(2).split("1").length-1}function XSt(t){return t===0n?0:t.toString(2).length}function mK(t,e){return yK.crypto.digest("sha256",qSt,t,e)}function ZSt(t){return yK.crypto.digest("sha256",GSt,t)}});var Cxe=_(IK=>{"use strict";Object.defineProperty(IK,"__esModule",{value:!0});IK.verifyTLogSET=tDt;var Ixe=Cl(),$St=Eo(),eDt=py();function tDt(t,e){if(!(0,eDt.filterTLogAuthorities)(e,{logID:t.logId.keyId,targetDate:new Date(Number(t.integratedTime)*1e3)}).some(a=>{let n=rDt(t),c=Buffer.from(Ixe.json.canonicalize(n),"utf8"),f=t.inclusionPromise.signedEntryTimestamp;return Ixe.crypto.verify(c,a.publicKey,f)}))throw new $St.VerificationError({code:"TLOG_INCLUSION_PROMISE_ERROR",message:"inclusion promise could not be verified"})}function rDt(t){let{integratedTime:e,logIndex:r,logId:s,canonicalizedBody:a}=t;return{body:a.toString("base64"),integratedTime:Number(e),logIndex:Number(r),logID:s.keyId.toString("hex")}}});var wxe=_(BK=>{"use strict";Object.defineProperty(BK,"__esModule",{value:!0});BK.verifyRFC3161Timestamp=sDt;var CK=Cl(),wK=Eo(),nDt=cK(),iDt=py();function sDt(t,e,r){let s=t.signingTime;if(r=(0,iDt.filterCertAuthorities)(r,{start:s,end:s}),r=aDt(r,{serialNumber:t.signerSerialNumber,issuer:t.signerIssuer}),!r.some(n=>{try{return oDt(t,e,n),!0}catch{return!1}}))throw new wK.VerificationError({code:"TIMESTAMP_ERROR",message:"timestamp could not be verified"})}function oDt(t,e,r){let[s,...a]=r.certChain,n=CK.crypto.createPublicKey(s.publicKey),c=t.signingTime;try{new nDt.CertificateChainVerifier({untrustedCert:s,trustedCerts:a}).verify()}catch{throw new wK.VerificationError({code:"TIMESTAMP_ERROR",message:"invalid certificate chain"})}if(!r.certChain.every(p=>p.validForDate(c)))throw new wK.VerificationError({code:"TIMESTAMP_ERROR",message:"timestamp was signed with an expired certificate"});t.verify(e,n)}function aDt(t,e){return t.filter(r=>r.certChain.length>0&&CK.crypto.bufferEqual(r.certChain[0].serialNumber,e.serialNumber)&&CK.crypto.bufferEqual(r.certChain[0].issuer,e.issuer))}});var Bxe=_(vL=>{"use strict";Object.defineProperty(vL,"__esModule",{value:!0});vL.verifyTSATimestamp=pDt;vL.verifyTLogTimestamp=hDt;var lDt=Eo(),cDt=yxe(),uDt=Exe(),fDt=Cxe(),ADt=wxe();function pDt(t,e,r){return(0,ADt.verifyRFC3161Timestamp)(t,e,r),{type:"timestamp-authority",logID:t.signerSerialNumber,timestamp:t.signingTime}}function hDt(t,e){let r=!1;if(gDt(t)&&((0,fDt.verifyTLogSET)(t,e),r=!0),dDt(t)&&((0,uDt.verifyMerkleInclusion)(t),(0,cDt.verifyCheckpoint)(t,e),r=!0),!r)throw new lDt.VerificationError({code:"TLOG_MISSING_INCLUSION_ERROR",message:"inclusion could not be verified"});return{type:"transparency-log",logID:t.logId.keyId,timestamp:new Date(Number(t.integratedTime)*1e3)}}function gDt(t){return t.inclusionPromise!==void 0}function dDt(t){return t.inclusionProof!==void 0}});var vxe=_(vK=>{"use strict";Object.defineProperty(vK,"__esModule",{value:!0});vK.verifyDSSETLogBody=mDt;var SL=Eo();function mDt(t,e){switch(t.apiVersion){case"0.0.1":return yDt(t,e);default:throw new SL.VerificationError({code:"TLOG_BODY_ERROR",message:`unsupported dsse version: ${t.apiVersion}`})}}function yDt(t,e){if(t.spec.signatures?.length!==1)throw new SL.VerificationError({code:"TLOG_BODY_ERROR",message:"signature count mismatch"});let r=t.spec.signatures[0].signature;if(!e.compareSignature(Buffer.from(r,"base64")))throw new SL.VerificationError({code:"TLOG_BODY_ERROR",message:"tlog entry signature mismatch"});let s=t.spec.payloadHash?.value||"";if(!e.compareDigest(Buffer.from(s,"hex")))throw new SL.VerificationError({code:"TLOG_BODY_ERROR",message:"DSSE payload hash mismatch"})}});var Sxe=_(DK=>{"use strict";Object.defineProperty(DK,"__esModule",{value:!0});DK.verifyHashedRekordTLogBody=EDt;var SK=Eo();function EDt(t,e){switch(t.apiVersion){case"0.0.1":return IDt(t,e);default:throw new SK.VerificationError({code:"TLOG_BODY_ERROR",message:`unsupported hashedrekord version: ${t.apiVersion}`})}}function IDt(t,e){let r=t.spec.signature.content||"";if(!e.compareSignature(Buffer.from(r,"base64")))throw new SK.VerificationError({code:"TLOG_BODY_ERROR",message:"signature mismatch"});let s=t.spec.data.hash?.value||"";if(!e.compareDigest(Buffer.from(s,"hex")))throw new SK.VerificationError({code:"TLOG_BODY_ERROR",message:"digest mismatch"})}});var Dxe=_(bK=>{"use strict";Object.defineProperty(bK,"__esModule",{value:!0});bK.verifyIntotoTLogBody=CDt;var DL=Eo();function CDt(t,e){switch(t.apiVersion){case"0.0.2":return wDt(t,e);default:throw new DL.VerificationError({code:"TLOG_BODY_ERROR",message:`unsupported intoto version: ${t.apiVersion}`})}}function wDt(t,e){if(t.spec.content.envelope.signatures?.length!==1)throw new DL.VerificationError({code:"TLOG_BODY_ERROR",message:"signature count mismatch"});let r=BDt(t.spec.content.envelope.signatures[0].sig);if(!e.compareSignature(Buffer.from(r,"base64")))throw new DL.VerificationError({code:"TLOG_BODY_ERROR",message:"tlog entry signature mismatch"});let s=t.spec.content.payloadHash?.value||"";if(!e.compareDigest(Buffer.from(s,"hex")))throw new DL.VerificationError({code:"TLOG_BODY_ERROR",message:"DSSE payload hash mismatch"})}function BDt(t){return Buffer.from(t,"base64").toString("utf-8")}});var Pxe=_(PK=>{"use strict";Object.defineProperty(PK,"__esModule",{value:!0});PK.verifyTLogBody=bDt;var bxe=Eo(),vDt=vxe(),SDt=Sxe(),DDt=Dxe();function bDt(t,e){let{kind:r,version:s}=t.kindVersion,a=JSON.parse(t.canonicalizedBody.toString("utf8"));if(r!==a.kind||s!==a.apiVersion)throw new bxe.VerificationError({code:"TLOG_BODY_ERROR",message:`kind/version mismatch - expected: ${r}/${s}, received: ${a.kind}/${a.apiVersion}`});switch(a.kind){case"dsse":return(0,vDt.verifyDSSETLogBody)(a,e);case"intoto":return(0,DDt.verifyIntotoTLogBody)(a,e);case"hashedrekord":return(0,SDt.verifyHashedRekordTLogBody)(a,e);default:throw new bxe.VerificationError({code:"TLOG_BODY_ERROR",message:`unsupported kind: ${r}`})}}});var Rxe=_(bL=>{"use strict";Object.defineProperty(bL,"__esModule",{value:!0});bL.Verifier=void 0;var PDt=Ie("util"),C1=Eo(),xxe=gxe(),kxe=mxe(),Qxe=Bxe(),xDt=Pxe(),xK=class{constructor(e,r={}){this.trustMaterial=e,this.options={ctlogThreshold:r.ctlogThreshold??1,tlogThreshold:r.tlogThreshold??1,tsaThreshold:r.tsaThreshold??0}}verify(e,r){let s=this.verifyTimestamps(e),a=this.verifySigningKey(e,s);return this.verifyTLogs(e),this.verifySignature(e,a),r&&this.verifyPolicy(r,a.identity||{}),a}verifyTimestamps(e){let r=0,s=0,a=e.timestamps.map(n=>{switch(n.$case){case"timestamp-authority":return s++,(0,Qxe.verifyTSATimestamp)(n.timestamp,e.signature.signature,this.trustMaterial.timestampAuthorities);case"transparency-log":return r++,(0,Qxe.verifyTLogTimestamp)(n.tlogEntry,this.trustMaterial.tlogs)}});if(Txe(a))throw new C1.VerificationError({code:"TIMESTAMP_ERROR",message:"duplicate timestamp"});if(rn.timestamp)}verifySigningKey({key:e},r){switch(e.$case){case"public-key":return(0,xxe.verifyPublicKey)(e.hint,r,this.trustMaterial);case"certificate":{let s=(0,xxe.verifyCertificate)(e.certificate,r,this.trustMaterial);if(Txe(s.scts))throw new C1.VerificationError({code:"CERTIFICATE_ERROR",message:"duplicate SCT"});if(s.scts.length(0,xDt.verifyTLogBody)(s,e))}verifySignature(e,r){if(!e.signature.verifySignature(r.key))throw new C1.VerificationError({code:"SIGNATURE_ERROR",message:"signature verification failed"})}verifyPolicy(e,r){e.subjectAlternativeName&&(0,kxe.verifySubjectAlternativeName)(e.subjectAlternativeName,r.subjectAlternativeName),e.extensions&&(0,kxe.verifyExtensions)(e.extensions,r.extensions)}};bL.Verifier=xK;function Txe(t){for(let e=0;e{"use strict";Object.defineProperty(iu,"__esModule",{value:!0});iu.Verifier=iu.toTrustMaterial=iu.VerificationError=iu.PolicyError=iu.toSignedEntity=void 0;var kDt=lxe();Object.defineProperty(iu,"toSignedEntity",{enumerable:!0,get:function(){return kDt.toSignedEntity}});var Fxe=Eo();Object.defineProperty(iu,"PolicyError",{enumerable:!0,get:function(){return Fxe.PolicyError}});Object.defineProperty(iu,"VerificationError",{enumerable:!0,get:function(){return Fxe.VerificationError}});var QDt=py();Object.defineProperty(iu,"toTrustMaterial",{enumerable:!0,get:function(){return QDt.toTrustMaterial}});var TDt=Rxe();Object.defineProperty(iu,"Verifier",{enumerable:!0,get:function(){return TDt.Verifier}})});var Nxe=_(Fa=>{"use strict";Object.defineProperty(Fa,"__esModule",{value:!0});Fa.DEFAULT_TIMEOUT=Fa.DEFAULT_RETRY=void 0;Fa.createBundleBuilder=NDt;Fa.createKeyFinder=ODt;Fa.createVerificationPolicy=LDt;var RDt=Cl(),w1=H7(),FDt=PL();Fa.DEFAULT_RETRY={retries:2};Fa.DEFAULT_TIMEOUT=5e3;function NDt(t,e){let r={signer:MDt(e),witnesses:_Dt(e)};switch(t){case"messageSignature":return new w1.MessageSignatureBundleBuilder(r);case"dsseEnvelope":return new w1.DSSEBundleBuilder({...r,certificateChain:e.legacyCompatibility})}}function ODt(t){return e=>{let r=t(e);if(!r)throw new FDt.VerificationError({code:"PUBLIC_KEY_ERROR",message:`key not found: ${e}`});return{publicKey:RDt.crypto.createPublicKey(r),validFor:()=>!0}}}function LDt(t){let e={},r=t.certificateIdentityEmail||t.certificateIdentityURI;return r&&(e.subjectAlternativeName=r),t.certificateIssuer&&(e.extensions={issuer:t.certificateIssuer}),e}function MDt(t){return new w1.FulcioSigner({fulcioBaseURL:t.fulcioURL,identityProvider:t.identityProvider||UDt(t),retry:t.retry??Fa.DEFAULT_RETRY,timeout:t.timeout??Fa.DEFAULT_TIMEOUT})}function UDt(t){let e=t.identityToken;return e?{getToken:()=>Promise.resolve(e)}:new w1.CIContextProvider("sigstore")}function _Dt(t){let e=[];return HDt(t)&&e.push(new w1.RekorWitness({rekorBaseURL:t.rekorURL,entryType:t.legacyCompatibility?"intoto":"dsse",fetchOnConflict:!1,retry:t.retry??Fa.DEFAULT_RETRY,timeout:t.timeout??Fa.DEFAULT_TIMEOUT})),jDt(t)&&e.push(new w1.TSAWitness({tsaBaseURL:t.tsaServerURL,retry:t.retry??Fa.DEFAULT_RETRY,timeout:t.timeout??Fa.DEFAULT_TIMEOUT})),e}function HDt(t){return t.tlogUpload!==!1}function jDt(t){return t.tsaServerURL!==void 0}});var Mxe=_(su=>{"use strict";var GDt=su&&su.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r);var a=Object.getOwnPropertyDescriptor(e,r);(!a||("get"in a?!e.__esModule:a.writable||a.configurable))&&(a={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(t,s,a)}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),qDt=su&&su.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),Oxe=su&&su.__importStar||function(){var t=function(e){return t=Object.getOwnPropertyNames||function(r){var s=[];for(var a in r)Object.prototype.hasOwnProperty.call(r,a)&&(s[s.length]=a);return s},t(e)};return function(e){if(e&&e.__esModule)return e;var r={};if(e!=null)for(var s=t(e),a=0;aa.verify(t,s))}async function Lxe(t={}){let e=await WDt.getTrustedRoot({mirrorURL:t.tufMirrorURL,rootPath:t.tufRootPath,cachePath:t.tufCachePath,forceCache:t.tufForceCache,retry:t.retry??B1.DEFAULT_RETRY,timeout:t.timeout??B1.DEFAULT_TIMEOUT}),r=t.keySelector?B1.createKeyFinder(t.keySelector):void 0,s=(0,kK.toTrustMaterial)(e,r),a={ctlogThreshold:t.ctLogThreshold,tlogThreshold:t.tlogThreshold},n=new kK.Verifier(s,a),c=B1.createVerificationPolicy(t);return{verify:(f,p)=>{let h=(0,QK.bundleFromJSON)(f),E=(0,kK.toSignedEntity)(h,p);n.verify(E,c)}}}});var _xe=_(Ni=>{"use strict";Object.defineProperty(Ni,"__esModule",{value:!0});Ni.verify=Ni.sign=Ni.createVerifier=Ni.attest=Ni.VerificationError=Ni.PolicyError=Ni.TUFError=Ni.InternalError=Ni.DEFAULT_REKOR_URL=Ni.DEFAULT_FULCIO_URL=Ni.ValidationError=void 0;var KDt=Ib();Object.defineProperty(Ni,"ValidationError",{enumerable:!0,get:function(){return KDt.ValidationError}});var TK=H7();Object.defineProperty(Ni,"DEFAULT_FULCIO_URL",{enumerable:!0,get:function(){return TK.DEFAULT_FULCIO_URL}});Object.defineProperty(Ni,"DEFAULT_REKOR_URL",{enumerable:!0,get:function(){return TK.DEFAULT_REKOR_URL}});Object.defineProperty(Ni,"InternalError",{enumerable:!0,get:function(){return TK.InternalError}});var zDt=hL();Object.defineProperty(Ni,"TUFError",{enumerable:!0,get:function(){return zDt.TUFError}});var Uxe=PL();Object.defineProperty(Ni,"PolicyError",{enumerable:!0,get:function(){return Uxe.PolicyError}});Object.defineProperty(Ni,"VerificationError",{enumerable:!0,get:function(){return Uxe.VerificationError}});var xL=Mxe();Object.defineProperty(Ni,"attest",{enumerable:!0,get:function(){return xL.attest}});Object.defineProperty(Ni,"createVerifier",{enumerable:!0,get:function(){return xL.createVerifier}});Object.defineProperty(Ni,"sign",{enumerable:!0,get:function(){return xL.sign}});Object.defineProperty(Ni,"verify",{enumerable:!0,get:function(){return xL.verify}})});Dt();Ge();Dt();var dke=Ie("child_process"),mke=ut(Fd());Yt();var $I=new Map([]);var Gv={};Vt(Gv,{BaseCommand:()=>ft,WorkspaceRequiredError:()=>ar,getCli:()=>bde,getDynamicLibs:()=>Dde,getPluginConfiguration:()=>tC,openWorkspace:()=>eC,pluginCommands:()=>$I,runExit:()=>VR});Yt();var ft=class extends ot{constructor(){super(...arguments);this.cwd=ge.String("--cwd",{hidden:!0})}validateAndExecute(){if(typeof this.cwd<"u")throw new nt("The --cwd option is ambiguous when used anywhere else than the very first parameter provided in the command line, before even the command path");return super.validateAndExecute()}};Ge();Dt();Yt();var ar=class extends nt{constructor(e,r){let s=J.relative(e,r),a=J.join(e,Ut.fileName);super(`This command can only be run from within a workspace of your project (${s} isn't a workspace of ${a}).`)}};Ge();Dt();eA();wc();pv();Yt();var yat=ut(Ai());Ul();var Dde=()=>new Map([["@yarnpkg/cli",Gv],["@yarnpkg/core",jv],["@yarnpkg/fslib",_2],["@yarnpkg/libzip",fv],["@yarnpkg/parsers",J2],["@yarnpkg/shell",mv],["clipanion",oB],["semver",yat],["typanion",Ea]]);Ge();async function eC(t,e){let{project:r,workspace:s}=await Tt.find(t,e);if(!s)throw new ar(r.cwd,e);return s}Ge();Dt();eA();wc();pv();Yt();var IPt=ut(Ai());Ul();var hq={};Vt(hq,{AddCommand:()=>sC,BinCommand:()=>oC,CacheCleanCommand:()=>aC,ClipanionCommand:()=>pC,ConfigCommand:()=>fC,ConfigGetCommand:()=>lC,ConfigSetCommand:()=>cC,ConfigUnsetCommand:()=>uC,DedupeCommand:()=>AC,EntryCommand:()=>gC,ExecCommand:()=>mC,ExplainCommand:()=>IC,ExplainPeerRequirementsCommand:()=>yC,HelpCommand:()=>hC,InfoCommand:()=>CC,LinkCommand:()=>BC,NodeCommand:()=>vC,PluginCheckCommand:()=>SC,PluginImportCommand:()=>PC,PluginImportSourcesCommand:()=>xC,PluginListCommand:()=>DC,PluginRemoveCommand:()=>kC,PluginRuntimeCommand:()=>QC,RebuildCommand:()=>TC,RemoveCommand:()=>RC,RunCommand:()=>NC,RunIndexCommand:()=>FC,SetResolutionCommand:()=>OC,SetVersionCommand:()=>EC,SetVersionSourcesCommand:()=>bC,UnlinkCommand:()=>LC,UpCommand:()=>MC,VersionCommand:()=>dC,WhyCommand:()=>UC,WorkspaceCommand:()=>qC,WorkspacesListCommand:()=>GC,YarnCommand:()=>wC,dedupeUtils:()=>rF,default:()=>Tct,suggestUtils:()=>Xu});var zye=ut(Fd());Ge();Ge();Ge();Yt();var hye=ut(Vv());Ul();var Xu={};Vt(Xu,{Modifier:()=>W5,Strategy:()=>eF,Target:()=>Jv,WorkspaceModifier:()=>cye,applyModifier:()=>Mlt,extractDescriptorFromPath:()=>Y5,extractRangeModifier:()=>uye,fetchDescriptorFrom:()=>V5,findProjectDescriptors:()=>pye,getModifier:()=>Kv,getSuggestedDescriptors:()=>zv,makeWorkspaceDescriptor:()=>Aye,toWorkspaceModifier:()=>fye});Ge();Ge();Dt();var q5=ut(Ai()),Olt="workspace:",Jv=(s=>(s.REGULAR="dependencies",s.DEVELOPMENT="devDependencies",s.PEER="peerDependencies",s))(Jv||{}),W5=(s=>(s.CARET="^",s.TILDE="~",s.EXACT="",s))(W5||{}),cye=(s=>(s.CARET="^",s.TILDE="~",s.EXACT="*",s))(cye||{}),eF=(n=>(n.KEEP="keep",n.REUSE="reuse",n.PROJECT="project",n.LATEST="latest",n.CACHE="cache",n))(eF||{});function Kv(t,e){return t.exact?"":t.caret?"^":t.tilde?"~":e.configuration.get("defaultSemverRangePrefix")}var Llt=/^([\^~]?)[0-9]+(?:\.[0-9]+){0,2}(?:-\S+)?$/;function uye(t,{project:e}){let r=t.match(Llt);return r?r[1]:e.configuration.get("defaultSemverRangePrefix")}function Mlt(t,e){let{protocol:r,source:s,params:a,selector:n}=G.parseRange(t.range);return q5.default.valid(n)&&(n=`${e}${t.range}`),G.makeDescriptor(t,G.makeRange({protocol:r,source:s,params:a,selector:n}))}function fye(t){switch(t){case"^":return"^";case"~":return"~";case"":return"*";default:throw new Error(`Assertion failed: Unknown modifier: "${t}"`)}}function Aye(t,e){return G.makeDescriptor(t.anchoredDescriptor,`${Olt}${fye(e)}`)}async function pye(t,{project:e,target:r}){let s=new Map,a=n=>{let c=s.get(n.descriptorHash);return c||s.set(n.descriptorHash,c={descriptor:n,locators:[]}),c};for(let n of e.workspaces)if(r==="peerDependencies"){let c=n.manifest.peerDependencies.get(t.identHash);c!==void 0&&a(c).locators.push(n.anchoredLocator)}else{let c=n.manifest.dependencies.get(t.identHash),f=n.manifest.devDependencies.get(t.identHash);r==="devDependencies"?f!==void 0?a(f).locators.push(n.anchoredLocator):c!==void 0&&a(c).locators.push(n.anchoredLocator):c!==void 0?a(c).locators.push(n.anchoredLocator):f!==void 0&&a(f).locators.push(n.anchoredLocator)}return s}async function Y5(t,{cwd:e,workspace:r}){return await _lt(async s=>{J.isAbsolute(t)||(t=J.relative(r.cwd,J.resolve(e,t)),t.match(/^\.{0,2}\//)||(t=`./${t}`));let{project:a}=r,n=await V5(G.makeIdent(null,"archive"),t,{project:r.project,cache:s,workspace:r});if(!n)throw new Error("Assertion failed: The descriptor should have been found");let c=new ki,f=a.configuration.makeResolver(),p=a.configuration.makeFetcher(),h={checksums:a.storedChecksums,project:a,cache:s,fetcher:p,report:c,resolver:f},E=f.bindDescriptor(n,r.anchoredLocator,h),C=G.convertDescriptorToLocator(E),S=await p.fetch(C,h),P=await Ut.find(S.prefixPath,{baseFs:S.packageFs});if(!P.name)throw new Error("Target path doesn't have a name");return G.makeDescriptor(P.name,t)})}function Ult(t){if(t.range==="unknown")return{type:"resolve",range:"latest"};if(Fr.validRange(t.range))return{type:"fixed",range:t.range};if(Mp.test(t.range))return{type:"resolve",range:t.range};let e=t.range.match(/^(?:jsr:|npm:)(.*)/);if(!e)return{type:"fixed",range:t.range};let[,r]=e,s=`${G.stringifyIdent(t)}@`;return r.startsWith(s)&&(r=r.slice(s.length)),Fr.validRange(r)?{type:"fixed",range:t.range}:Mp.test(r)?{type:"resolve",range:t.range}:{type:"fixed",range:t.range}}async function zv(t,{project:e,workspace:r,cache:s,target:a,fixed:n,modifier:c,strategies:f,maxResults:p=1/0}){if(!(p>=0))throw new Error(`Invalid maxResults (${p})`);let h=!n||t.range==="unknown"?Ult(t):{type:"fixed",range:t.range};if(h.type==="fixed")return{suggestions:[{descriptor:t,name:`Use ${G.prettyDescriptor(e.configuration,t)}`,reason:"(unambiguous explicit request)"}],rejections:[]};let E=typeof r<"u"&&r!==null&&r.manifest[a].get(t.identHash)||null,C=[],S=[],P=async I=>{try{await I()}catch(R){S.push(R)}};for(let I of f){if(C.length>=p)break;switch(I){case"keep":await P(async()=>{E&&C.push({descriptor:E,name:`Keep ${G.prettyDescriptor(e.configuration,E)}`,reason:"(no changes)"})});break;case"reuse":await P(async()=>{for(let{descriptor:R,locators:N}of(await pye(t,{project:e,target:a})).values()){if(N.length===1&&N[0].locatorHash===r.anchoredLocator.locatorHash&&f.includes("keep"))continue;let U=`(originally used by ${G.prettyLocator(e.configuration,N[0])}`;U+=N.length>1?` and ${N.length-1} other${N.length>2?"s":""})`:")",C.push({descriptor:R,name:`Reuse ${G.prettyDescriptor(e.configuration,R)}`,reason:U})}});break;case"cache":await P(async()=>{for(let R of e.storedDescriptors.values())R.identHash===t.identHash&&C.push({descriptor:R,name:`Reuse ${G.prettyDescriptor(e.configuration,R)}`,reason:"(already used somewhere in the lockfile)"})});break;case"project":await P(async()=>{if(r.manifest.name!==null&&t.identHash===r.manifest.name.identHash)return;let R=e.tryWorkspaceByIdent(t);if(R===null)return;let N=Aye(R,c);C.push({descriptor:N,name:`Attach ${G.prettyDescriptor(e.configuration,N)}`,reason:`(local workspace at ${he.pretty(e.configuration,R.relativeCwd,he.Type.PATH)})`})});break;case"latest":{let R=e.configuration.get("enableNetwork"),N=e.configuration.get("enableOfflineMode");await P(async()=>{if(a==="peerDependencies")C.push({descriptor:G.makeDescriptor(t,"*"),name:"Use *",reason:"(catch-all peer dependency pattern)"});else if(!R&&!N)C.push({descriptor:null,name:"Resolve from latest",reason:he.pretty(e.configuration,"(unavailable because enableNetwork is toggled off)","grey")});else{let U=await V5(t,h.range,{project:e,cache:s,workspace:r,modifier:c});U&&C.push({descriptor:U,name:`Use ${G.prettyDescriptor(e.configuration,U)}`,reason:`(resolved from ${N?"the cache":"latest"})`})}})}break}}return{suggestions:C.slice(0,p),rejections:S.slice(0,p)}}async function V5(t,e,{project:r,cache:s,workspace:a,preserveModifier:n=!0,modifier:c}){let f=r.configuration.normalizeDependency(G.makeDescriptor(t,e)),p=new ki,h=r.configuration.makeFetcher(),E=r.configuration.makeResolver(),C={project:r,fetcher:h,cache:s,checksums:r.storedChecksums,report:p,cacheOptions:{skipIntegrityCheck:!0}},S={...C,resolver:E,fetchOptions:C},P=E.bindDescriptor(f,a.anchoredLocator,S),I=await E.getCandidates(P,{},S);if(I.length===0)return null;let R=I[0],{protocol:N,source:U,params:W,selector:ee}=G.parseRange(G.convertToManifestRange(R.reference));if(N===r.configuration.get("defaultProtocol")&&(N=null),q5.default.valid(ee)){let ie=ee;if(typeof c<"u")ee=c+ee;else if(n!==!1){let me=typeof n=="string"?n:f.range;ee=uye(me,{project:r})+ee}let ue=G.makeDescriptor(R,G.makeRange({protocol:N,source:U,params:W,selector:ee}));(await E.getCandidates(r.configuration.normalizeDependency(ue),{},S)).length!==1&&(ee=ie)}return G.makeDescriptor(R,G.makeRange({protocol:N,source:U,params:W,selector:ee}))}async function _lt(t){return await ce.mktempPromise(async e=>{let r=ze.create(e);return r.useWithSource(e,{enableMirror:!1,compressionLevel:0},e,{overwrite:!0}),await t(new Kr(e,{configuration:r,check:!1,immutable:!1}))})}var sC=class extends ft{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.fixed=ge.Boolean("-F,--fixed",!1,{description:"Store dependency tags as-is instead of resolving them"});this.exact=ge.Boolean("-E,--exact",!1,{description:"Don't use any semver modifier on the resolved range"});this.tilde=ge.Boolean("-T,--tilde",!1,{description:"Use the `~` semver modifier on the resolved range"});this.caret=ge.Boolean("-C,--caret",!1,{description:"Use the `^` semver modifier on the resolved range"});this.dev=ge.Boolean("-D,--dev",!1,{description:"Add a package as a dev dependency"});this.peer=ge.Boolean("-P,--peer",!1,{description:"Add a package as a peer dependency"});this.optional=ge.Boolean("-O,--optional",!1,{description:"Add / upgrade a package to an optional regular / peer dependency"});this.preferDev=ge.Boolean("--prefer-dev",!1,{description:"Add / upgrade a package to a dev dependency"});this.interactive=ge.Boolean("-i,--interactive",{description:"Reuse the specified package from other workspaces in the project"});this.cached=ge.Boolean("--cached",!1,{description:"Reuse the highest version already used somewhere within the project"});this.mode=ge.String("--mode",{description:"Change what artifacts installs generate",validator:fo($l)});this.silent=ge.Boolean("--silent",{hidden:!0});this.packages=ge.Rest()}static{this.paths=[["add"]]}static{this.usage=ot.Usage({description:"add dependencies to the project",details:"\n This command adds a package to the package.json for the nearest workspace.\n\n - If it didn't exist before, the package will by default be added to the regular `dependencies` field, but this behavior can be overriden thanks to the `-D,--dev` flag (which will cause the dependency to be added to the `devDependencies` field instead) and the `-P,--peer` flag (which will do the same but for `peerDependencies`).\n\n - If the package was already listed in your dependencies, it will by default be upgraded whether it's part of your `dependencies` or `devDependencies` (it won't ever update `peerDependencies`, though).\n\n - If set, the `--prefer-dev` flag will operate as a more flexible `-D,--dev` in that it will add the package to your `devDependencies` if it isn't already listed in either `dependencies` or `devDependencies`, but it will also happily upgrade your `dependencies` if that's what you already use (whereas `-D,--dev` would throw an exception).\n\n - If set, the `-O,--optional` flag will add the package to the `optionalDependencies` field and, in combination with the `-P,--peer` flag, it will add the package as an optional peer dependency. If the package was already listed in your `dependencies`, it will be upgraded to `optionalDependencies`. If the package was already listed in your `peerDependencies`, in combination with the `-P,--peer` flag, it will be upgraded to an optional peer dependency: `\"peerDependenciesMeta\": { \"\": { \"optional\": true } }`\n\n - If the added package doesn't specify a range at all its `latest` tag will be resolved and the returned version will be used to generate a new semver range (using the `^` modifier by default unless otherwise configured via the `defaultSemverRangePrefix` configuration, or the `~` modifier if `-T,--tilde` is specified, or no modifier at all if `-E,--exact` is specified). Two exceptions to this rule: the first one is that if the package is a workspace then its local version will be used, and the second one is that if you use `-P,--peer` the default range will be `*` and won't be resolved at all.\n\n - If the added package specifies a range (such as `^1.0.0`, `latest`, or `rc`), Yarn will add this range as-is in the resulting package.json entry (in particular, tags such as `rc` will be encoded as-is rather than being converted into a semver range).\n\n If the `--cached` option is used, Yarn will preferably reuse the highest version already used somewhere within the project, even if through a transitive dependency.\n\n If the `-i,--interactive` option is used (or if the `preferInteractive` settings is toggled on) the command will first try to check whether other workspaces in the project use the specified package and, if so, will offer to reuse them.\n\n If the `--mode=` option is set, Yarn will change which artifacts are generated. The modes currently supported are:\n\n - `skip-build` will not run the build scripts at all. Note that this is different from setting `enableScripts` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run.\n\n - `update-lockfile` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost.\n\n For a compilation of all the supported protocols, please consult the dedicated page from our website: https://yarnpkg.com/protocols.\n ",examples:[["Add a regular package to the current workspace","$0 add lodash"],["Add a specific version for a package to the current workspace","$0 add lodash@1.2.3"],["Add a package from a GitHub repository (the master branch) to the current workspace using a URL","$0 add lodash@https://github.com/lodash/lodash"],["Add a package from a GitHub repository (the master branch) to the current workspace using the GitHub protocol","$0 add lodash@github:lodash/lodash"],["Add a package from a GitHub repository (the master branch) to the current workspace using the GitHub protocol (shorthand)","$0 add lodash@lodash/lodash"],["Add a package from a specific branch of a GitHub repository to the current workspace using the GitHub protocol (shorthand)","$0 add lodash-es@lodash/lodash#es"],["Add a local package (gzipped tarball format) to the current workspace","$0 add local-package-name@file:../path/to/local-package-name-v0.1.2.tgz"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Tt.find(r,this.context.cwd),n=await Kr.find(r);if(!a)throw new ar(s.cwd,this.context.cwd);await s.restoreInstallState({restoreResolutions:!1});let c=this.fixed,f=r.isInteractive({interactive:this.interactive,stdout:this.context.stdout}),p=f||r.get("preferReuse"),h=Kv(this,s),E=[p?"reuse":void 0,"project",this.cached?"cache":void 0,"latest"].filter(W=>typeof W<"u"),C=f?1/0:1,S=W=>{let ee=G.tryParseDescriptor(W.slice(4));return ee?ee.range==="unknown"?G.makeDescriptor(ee,`jsr:${G.stringifyIdent(ee)}@latest`):G.makeDescriptor(ee,`jsr:${ee.range}`):null},P=await Promise.all(this.packages.map(async W=>{let ee=W.match(/^\.{0,2}\//)?await Y5(W,{cwd:this.context.cwd,workspace:a}):W.startsWith("jsr:")?S(W):G.tryParseDescriptor(W),ie=W.match(/^(https?:|git@github)/);if(ie)throw new nt(`It seems you are trying to add a package using a ${he.pretty(r,`${ie[0]}...`,he.Type.RANGE)} url; we now require package names to be explicitly specified. +Try running the command again with the package name prefixed: ${he.pretty(r,"yarn add",he.Type.CODE)} ${he.pretty(r,G.makeDescriptor(G.makeIdent(null,"my-package"),`${ie[0]}...`),he.Type.DESCRIPTOR)}`);if(!ee)throw new nt(`The ${he.pretty(r,W,he.Type.CODE)} string didn't match the required format (package-name@range). Did you perhaps forget to explicitly reference the package name?`);let ue=Hlt(a,ee,{dev:this.dev,peer:this.peer,preferDev:this.preferDev,optional:this.optional});return await Promise.all(ue.map(async me=>{let pe=await zv(ee,{project:s,workspace:a,cache:n,fixed:c,target:me,modifier:h,strategies:E,maxResults:C});return{request:ee,suggestedDescriptors:pe,target:me}}))})).then(W=>W.flat()),I=await lA.start({configuration:r,stdout:this.context.stdout,suggestInstall:!1},async W=>{for(let{request:ee,suggestedDescriptors:{suggestions:ie,rejections:ue}}of P)if(ie.filter(me=>me.descriptor!==null).length===0){let[me]=ue;if(typeof me>"u")throw new Error("Assertion failed: Expected an error to have been set");s.configuration.get("enableNetwork")?W.reportError(27,`${G.prettyDescriptor(r,ee)} can't be resolved to a satisfying range`):W.reportError(27,`${G.prettyDescriptor(r,ee)} can't be resolved to a satisfying range (note: network resolution has been disabled)`),W.reportSeparator(),W.reportExceptionOnce(me)}});if(I.hasErrors())return I.exitCode();let R=!1,N=[],U=[];for(let{suggestedDescriptors:{suggestions:W},target:ee}of P){let ie,ue=W.filter(Be=>Be.descriptor!==null),le=ue[0].descriptor,me=ue.every(Be=>G.areDescriptorsEqual(Be.descriptor,le));ue.length===1||me?ie=le:(R=!0,{answer:ie}=await(0,hye.prompt)({type:"select",name:"answer",message:"Which range do you want to use?",choices:W.map(({descriptor:Be,name:Ce,reason:g})=>Be?{name:Ce,hint:g,descriptor:Be}:{name:Ce,hint:g,disabled:!0}),onCancel:()=>process.exit(130),result(Be){return this.find(Be,"descriptor")},stdin:this.context.stdin,stdout:this.context.stdout}));let pe=a.manifest[ee].get(ie.identHash);(typeof pe>"u"||pe.descriptorHash!==ie.descriptorHash)&&(a.manifest[ee].set(ie.identHash,ie),this.optional&&(ee==="dependencies"?a.manifest.ensureDependencyMeta({...ie,range:"unknown"}).optional=!0:ee==="peerDependencies"&&(a.manifest.ensurePeerDependencyMeta({...ie,range:"unknown"}).optional=!0)),typeof pe>"u"?N.push([a,ee,ie,E]):U.push([a,ee,pe,ie]))}return await r.triggerMultipleHooks(W=>W.afterWorkspaceDependencyAddition,N),await r.triggerMultipleHooks(W=>W.afterWorkspaceDependencyReplacement,U),R&&this.context.stdout.write(` +`),await s.installWithNewReport({json:this.json,stdout:this.context.stdout,quiet:this.context.quiet},{cache:n,mode:this.mode})}};function Hlt(t,e,{dev:r,peer:s,preferDev:a,optional:n}){let c=t.manifest.dependencies.has(e.identHash),f=t.manifest.devDependencies.has(e.identHash),p=t.manifest.peerDependencies.has(e.identHash);if((r||s)&&c)throw new nt(`Package "${G.prettyIdent(t.project.configuration,e)}" is already listed as a regular dependency - remove the -D,-P flags or remove it from your dependencies first`);if(!r&&!s&&p)throw new nt(`Package "${G.prettyIdent(t.project.configuration,e)}" is already listed as a peer dependency - use either of -D or -P, or remove it from your peer dependencies first`);if(n&&f)throw new nt(`Package "${G.prettyIdent(t.project.configuration,e)}" is already listed as a dev dependency - remove the -O flag or remove it from your dev dependencies first`);if(n&&!s&&p)throw new nt(`Package "${G.prettyIdent(t.project.configuration,e)}" is already listed as a peer dependency - remove the -O flag or add the -P flag or remove it from your peer dependencies first`);if((r||a)&&n)throw new nt(`Package "${G.prettyIdent(t.project.configuration,e)}" cannot simultaneously be a dev dependency and an optional dependency`);let h=[];return s&&h.push("peerDependencies"),(r||a)&&h.push("devDependencies"),n&&h.push("dependencies"),h.length>0?h:f?["devDependencies"]:p?["peerDependencies"]:["dependencies"]}Ge();Ge();Yt();var oC=class extends ft{constructor(){super(...arguments);this.verbose=ge.Boolean("-v,--verbose",!1,{description:"Print both the binary name and the locator of the package that provides the binary"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.name=ge.String({required:!1})}static{this.paths=[["bin"]]}static{this.usage=ot.Usage({description:"get the path to a binary script",details:` + When used without arguments, this command will print the list of all the binaries available in the current workspace. Adding the \`-v,--verbose\` flag will cause the output to contain both the binary name and the locator of the package that provides the binary. + + When an argument is specified, this command will just print the path to the binary on the standard output and exit. Note that the reported path may be stored within a zip archive. + `,examples:[["List all the available binaries","$0 bin"],["Print the path to a specific binary","$0 bin eslint"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,locator:a}=await Tt.find(r,this.context.cwd);if(await s.restoreInstallState(),this.name){let f=(await In.getPackageAccessibleBinaries(a,{project:s})).get(this.name);if(!f)throw new nt(`Couldn't find a binary named "${this.name}" for package "${G.prettyLocator(r,a)}"`);let[,p]=f;return this.context.stdout.write(`${p} +`),0}return(await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout},async c=>{let f=await In.getPackageAccessibleBinaries(a,{project:s}),h=Array.from(f.keys()).reduce((E,C)=>Math.max(E,C.length),0);for(let[E,[C,S]]of f)c.reportJson({name:E,source:G.stringifyIdent(C),path:S});if(this.verbose)for(let[E,[C]]of f)c.reportInfo(null,`${E.padEnd(h," ")} ${G.prettyLocator(r,C)}`);else for(let E of f.keys())c.reportInfo(null,E)})).exitCode()}};Ge();Dt();Yt();var aC=class extends ft{constructor(){super(...arguments);this.mirror=ge.Boolean("--mirror",!1,{description:"Remove the global cache files instead of the local cache files"});this.all=ge.Boolean("--all",!1,{description:"Remove both the global cache files and the local cache files of the current project"})}static{this.paths=[["cache","clean"],["cache","clear"]]}static{this.usage=ot.Usage({description:"remove the shared cache files",details:` + This command will remove all the files from the cache. + `,examples:[["Remove all the local archives","$0 cache clean"],["Remove all the archives stored in the ~/.yarn directory","$0 cache clean --mirror"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins);if(!r.get("enableCacheClean"))throw new nt("Cache cleaning is currently disabled. To enable it, set `enableCacheClean: true` in your configuration file. Note: Cache cleaning is typically not required and should be avoided when using Zero-Installs.");let s=await Kr.find(r);return(await Ot.start({configuration:r,stdout:this.context.stdout},async()=>{let n=(this.all||this.mirror)&&s.mirrorCwd!==null,c=!this.mirror;n&&(await ce.removePromise(s.mirrorCwd),await r.triggerHook(f=>f.cleanGlobalArtifacts,r)),c&&await ce.removePromise(s.cwd)})).exitCode()}};Ge();Yt();ql();var J5=Ie("util"),lC=class extends ft{constructor(){super(...arguments);this.why=ge.Boolean("--why",!1,{description:"Print the explanation for why a setting has its value"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.unsafe=ge.Boolean("--no-redacted",!1,{description:"Don't redact secrets (such as tokens) from the output"});this.name=ge.String()}static{this.paths=[["config","get"]]}static{this.usage=ot.Usage({description:"read a configuration settings",details:` + This command will print a configuration setting. + + Secrets (such as tokens) will be redacted from the output by default. If this behavior isn't desired, set the \`--no-redacted\` to get the untransformed value. + `,examples:[["Print a simple configuration setting","yarn config get yarnPath"],["Print a complex configuration setting","yarn config get packageExtensions"],["Print a nested field from the configuration",`yarn config get 'npmScopes["my-company"].npmRegistryServer'`],["Print a token from the configuration","yarn config get npmAuthToken --no-redacted"],["Print a configuration setting as JSON","yarn config get packageExtensions --json"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),s=this.name.replace(/[.[].*$/,""),a=this.name.replace(/^[^.[]*/,"");if(typeof r.settings.get(s)>"u")throw new nt(`Couldn't find a configuration settings named "${s}"`);let c=r.getSpecial(s,{hideSecrets:!this.unsafe,getNativePaths:!0}),f=je.convertMapsToIndexableObjects(c),p=a?va(f,a):f,h=await Ot.start({configuration:r,includeFooter:!1,json:this.json,stdout:this.context.stdout},async E=>{E.reportJson(p)});if(!this.json){if(typeof p=="string")return this.context.stdout.write(`${p} +`),h.exitCode();J5.inspect.styles.name="cyan",this.context.stdout.write(`${(0,J5.inspect)(p,{depth:1/0,colors:r.get("enableColors"),compact:!1})} +`)}return h.exitCode()}};Ge();Yt();ql();var K5=Ie("util"),cC=class extends ft{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Set complex configuration settings to JSON values"});this.home=ge.Boolean("-H,--home",!1,{description:"Update the home configuration instead of the project configuration"});this.name=ge.String();this.value=ge.String()}static{this.paths=[["config","set"]]}static{this.usage=ot.Usage({description:"change a configuration settings",details:` + This command will set a configuration setting. + + When used without the \`--json\` flag, it can only set a simple configuration setting (a string, a number, or a boolean). + + When used with the \`--json\` flag, it can set both simple and complex configuration settings, including Arrays and Objects. + `,examples:[["Set a simple configuration setting (a string, a number, or a boolean)","yarn config set initScope myScope"],["Set a simple configuration setting (a string, a number, or a boolean) using the `--json` flag",'yarn config set initScope --json \\"myScope\\"'],["Set a complex configuration setting (an Array) using the `--json` flag",`yarn config set unsafeHttpWhitelist --json '["*.example.com", "example.com"]'`],["Set a complex configuration setting (an Object) using the `--json` flag",`yarn config set packageExtensions --json '{ "@babel/parser@*": { "dependencies": { "@babel/types": "*" } } }'`],["Set a nested configuration setting",'yarn config set npmScopes.company.npmRegistryServer "https://npm.example.com"'],["Set a nested configuration setting using indexed access for non-simple keys",`yarn config set 'npmRegistries["//npm.example.com"].npmAuthToken' "ffffffff-ffff-ffff-ffff-ffffffffffff"`]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),s=()=>{if(!r.projectCwd)throw new nt("This command must be run from within a project folder");return r.projectCwd},a=this.name.replace(/[.[].*$/,""),n=this.name.replace(/^[^.[]*\.?/,"");if(typeof r.settings.get(a)>"u")throw new nt(`Couldn't find a configuration settings named "${a}"`);if(a==="enableStrictSettings")throw new nt("This setting only affects the file it's in, and thus cannot be set from the CLI");let f=this.json?JSON.parse(this.value):this.value;await(this.home?I=>ze.updateHomeConfiguration(I):I=>ze.updateConfiguration(s(),I))(I=>{if(n){let R=f0(I);return Jd(R,this.name,f),R}else return{...I,[a]:f}});let E=(await ze.find(this.context.cwd,this.context.plugins)).getSpecial(a,{hideSecrets:!0,getNativePaths:!0}),C=je.convertMapsToIndexableObjects(E),S=n?va(C,n):C;return(await Ot.start({configuration:r,includeFooter:!1,stdout:this.context.stdout},async I=>{K5.inspect.styles.name="cyan",I.reportInfo(0,`Successfully set ${this.name} to ${(0,K5.inspect)(S,{depth:1/0,colors:r.get("enableColors"),compact:!1})}`)})).exitCode()}};Ge();Yt();ql();var uC=class extends ft{constructor(){super(...arguments);this.home=ge.Boolean("-H,--home",!1,{description:"Update the home configuration instead of the project configuration"});this.name=ge.String()}static{this.paths=[["config","unset"]]}static{this.usage=ot.Usage({description:"unset a configuration setting",details:` + This command will unset a configuration setting. + `,examples:[["Unset a simple configuration setting","yarn config unset initScope"],["Unset a complex configuration setting","yarn config unset packageExtensions"],["Unset a nested configuration setting","yarn config unset npmScopes.company.npmRegistryServer"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),s=()=>{if(!r.projectCwd)throw new nt("This command must be run from within a project folder");return r.projectCwd},a=this.name.replace(/[.[].*$/,""),n=this.name.replace(/^[^.[]*\.?/,"");if(typeof r.settings.get(a)>"u")throw new nt(`Couldn't find a configuration settings named "${a}"`);let f=this.home?h=>ze.updateHomeConfiguration(h):h=>ze.updateConfiguration(s(),h);return(await Ot.start({configuration:r,includeFooter:!1,stdout:this.context.stdout},async h=>{let E=!1;await f(C=>{if(!vB(C,this.name))return h.reportWarning(0,`Configuration doesn't contain setting ${this.name}; there is nothing to unset`),E=!0,C;let S=n?f0(C):{...C};return A0(S,this.name),S}),E||h.reportInfo(0,`Successfully unset ${this.name}`)})).exitCode()}};Ge();Dt();Yt();var tF=Ie("util"),fC=class extends ft{constructor(){super(...arguments);this.noDefaults=ge.Boolean("--no-defaults",!1,{description:"Omit the default values from the display"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.verbose=ge.Boolean("-v,--verbose",{hidden:!0});this.why=ge.Boolean("--why",{hidden:!0});this.names=ge.Rest()}static{this.paths=[["config"]]}static{this.usage=ot.Usage({description:"display the current configuration",details:` + This command prints the current active configuration settings. + `,examples:[["Print the active configuration settings","$0 config"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins,{strict:!1}),s=await SI({configuration:r,stdout:this.context.stdout,forceError:this.json},[{option:this.verbose,message:"The --verbose option is deprecated, the settings' descriptions are now always displayed"},{option:this.why,message:"The --why option is deprecated, the settings' sources are now always displayed"}]);if(s!==null)return s;let a=this.names.length>0?[...new Set(this.names)].sort():[...r.settings.keys()].sort(),n,c=await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout,includeFooter:!1},async f=>{if(r.invalid.size>0&&!this.json){for(let[p,h]of r.invalid)f.reportError(34,`Invalid configuration key "${p}" in ${h}`);f.reportSeparator()}if(this.json)for(let p of a){if(this.noDefaults&&!r.sources.has(p))continue;let h=r.settings.get(p);typeof h>"u"&&f.reportError(34,`No configuration key named "${p}"`);let E=r.getSpecial(p,{hideSecrets:!0,getNativePaths:!0}),C=r.sources.get(p)??"",S=C&&C[0]!=="<"?fe.fromPortablePath(C):C;f.reportJson({key:p,effective:E,source:S,...h})}else{let p={breakLength:1/0,colors:r.get("enableColors"),maxArrayLength:2},h={},E={children:h};for(let C of a){if(this.noDefaults&&!r.sources.has(C))continue;let S=r.settings.get(C),P=r.sources.get(C)??"",I=r.getSpecial(C,{hideSecrets:!0,getNativePaths:!0}),R={Description:{label:"Description",value:he.tuple(he.Type.MARKDOWN,{text:S.description,format:this.cli.format(),paragraphs:!1})},Source:{label:"Source",value:he.tuple(P[0]==="<"?he.Type.CODE:he.Type.PATH,P)}};h[C]={value:he.tuple(he.Type.CODE,C),children:R};let N=(U,W)=>{for(let[ee,ie]of W)if(ie instanceof Map){let ue={};U[ee]={children:ue},N(ue,ie)}else U[ee]={label:ee,value:he.tuple(he.Type.NO_HINT,(0,tF.inspect)(ie,p))}};I instanceof Map?N(R,I):R.Value={label:"Value",value:he.tuple(he.Type.NO_HINT,(0,tF.inspect)(I,p))}}a.length!==1&&(n=void 0),xs.emitTree(E,{configuration:r,json:this.json,stdout:this.context.stdout,separators:2})}});if(!this.json&&typeof n<"u"){let f=a[0],p=(0,tF.inspect)(r.getSpecial(f,{hideSecrets:!0,getNativePaths:!0}),{colors:r.get("enableColors")});this.context.stdout.write(` +`),this.context.stdout.write(`${p} +`)}return c.exitCode()}};Ge();Yt();Ul();var rF={};Vt(rF,{Strategy:()=>Xv,acceptedStrategies:()=>jlt,dedupe:()=>z5});Ge();Ge();var gye=ut(Go()),Xv=(e=>(e.HIGHEST="highest",e))(Xv||{}),jlt=new Set(Object.values(Xv)),Glt={highest:async(t,e,{resolver:r,fetcher:s,resolveOptions:a,fetchOptions:n})=>{let c=new Map;for(let[p,h]of t.storedResolutions){let E=t.storedDescriptors.get(p);if(typeof E>"u")throw new Error(`Assertion failed: The descriptor (${p}) should have been registered`);je.getSetWithDefault(c,E.identHash).add(h)}let f=new Map(je.mapAndFilter(t.storedDescriptors.values(),p=>G.isVirtualDescriptor(p)?je.mapAndFilter.skip:[p.descriptorHash,je.makeDeferred()]));for(let p of t.storedDescriptors.values()){let h=f.get(p.descriptorHash);if(typeof h>"u")throw new Error(`Assertion failed: The descriptor (${p.descriptorHash}) should have been registered`);let E=t.storedResolutions.get(p.descriptorHash);if(typeof E>"u")throw new Error(`Assertion failed: The resolution (${p.descriptorHash}) should have been registered`);let C=t.originalPackages.get(E);if(typeof C>"u")throw new Error(`Assertion failed: The package (${E}) should have been registered`);Promise.resolve().then(async()=>{let S=r.getResolutionDependencies(p,a),P=Object.fromEntries(await je.allSettledSafe(Object.entries(S).map(async([ee,ie])=>{let ue=f.get(ie.descriptorHash);if(typeof ue>"u")throw new Error(`Assertion failed: The descriptor (${ie.descriptorHash}) should have been registered`);let le=await ue.promise;if(!le)throw new Error("Assertion failed: Expected the dependency to have been through the dedupe process itself");return[ee,le.updatedPackage]})));if(e.length&&!gye.default.isMatch(G.stringifyIdent(p),e)||!r.shouldPersistResolution(C,a))return C;let I=c.get(p.identHash);if(typeof I>"u")throw new Error(`Assertion failed: The resolutions (${p.identHash}) should have been registered`);if(I.size===1)return C;let R=[...I].map(ee=>{let ie=t.originalPackages.get(ee);if(typeof ie>"u")throw new Error(`Assertion failed: The package (${ee}) should have been registered`);return ie}),N=await r.getSatisfying(p,P,R,a),U=N.locators?.[0];if(typeof U>"u"||!N.sorted)return C;let W=t.originalPackages.get(U.locatorHash);if(typeof W>"u")throw new Error(`Assertion failed: The package (${U.locatorHash}) should have been registered`);return W}).then(async S=>{let P=await t.preparePackage(S,{resolver:r,resolveOptions:a});h.resolve({descriptor:p,currentPackage:C,updatedPackage:S,resolvedPackage:P})}).catch(S=>{h.reject(S)})}return[...f.values()].map(p=>p.promise)}};async function z5(t,{strategy:e,patterns:r,cache:s,report:a}){let{configuration:n}=t,c=new ki,f=n.makeResolver(),p=n.makeFetcher(),h={cache:s,checksums:t.storedChecksums,fetcher:p,project:t,report:c,cacheOptions:{skipIntegrityCheck:!0}},E={project:t,resolver:f,report:c,fetchOptions:h};return await a.startTimerPromise("Deduplication step",async()=>{let C=Glt[e],S=await C(t,r,{resolver:f,resolveOptions:E,fetcher:p,fetchOptions:h}),P=Ao.progressViaCounter(S.length);await a.reportProgress(P);let I=0;await Promise.all(S.map(U=>U.then(W=>{if(W===null||W.currentPackage.locatorHash===W.updatedPackage.locatorHash)return;I++;let{descriptor:ee,currentPackage:ie,updatedPackage:ue}=W;a.reportInfo(0,`${G.prettyDescriptor(n,ee)} can be deduped from ${G.prettyLocator(n,ie)} to ${G.prettyLocator(n,ue)}`),a.reportJson({descriptor:G.stringifyDescriptor(ee),currentResolution:G.stringifyLocator(ie),updatedResolution:G.stringifyLocator(ue)}),t.storedResolutions.set(ee.descriptorHash,ue.locatorHash)}).finally(()=>P.tick())));let R;switch(I){case 0:R="No packages";break;case 1:R="One package";break;default:R=`${I} packages`}let N=he.pretty(n,e,he.Type.CODE);return a.reportInfo(0,`${R} can be deduped using the ${N} strategy`),I})}var AC=class extends ft{constructor(){super(...arguments);this.strategy=ge.String("-s,--strategy","highest",{description:"The strategy to use when deduping dependencies",validator:fo(Xv)});this.check=ge.Boolean("-c,--check",!1,{description:"Exit with exit code 1 when duplicates are found, without persisting the dependency tree"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.mode=ge.String("--mode",{description:"Change what artifacts installs generate",validator:fo($l)});this.patterns=ge.Rest()}static{this.paths=[["dedupe"]]}static{this.usage=ot.Usage({description:"deduplicate dependencies with overlapping ranges",details:"\n Duplicates are defined as descriptors with overlapping ranges being resolved and locked to different locators. They are a natural consequence of Yarn's deterministic installs, but they can sometimes pile up and unnecessarily increase the size of your project.\n\n This command dedupes dependencies in the current project using different strategies (only one is implemented at the moment):\n\n - `highest`: Reuses (where possible) the locators with the highest versions. This means that dependencies can only be upgraded, never downgraded. It's also guaranteed that it never takes more than a single pass to dedupe the entire dependency tree.\n\n **Note:** Even though it never produces a wrong dependency tree, this command should be used with caution, as it modifies the dependency tree, which can sometimes cause problems when packages don't strictly follow semver recommendations. Because of this, it is recommended to also review the changes manually.\n\n If set, the `-c,--check` flag will only report the found duplicates, without persisting the modified dependency tree. If changes are found, the command will exit with a non-zero exit code, making it suitable for CI purposes.\n\n If the `--mode=` option is set, Yarn will change which artifacts are generated. The modes currently supported are:\n\n - `skip-build` will not run the build scripts at all. Note that this is different from setting `enableScripts` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run.\n\n - `update-lockfile` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost.\n\n This command accepts glob patterns as arguments (if valid Idents and supported by [micromatch](https://github.com/micromatch/micromatch)). Make sure to escape the patterns, to prevent your own shell from trying to expand them.\n\n ### In-depth explanation:\n\n Yarn doesn't deduplicate dependencies by default, otherwise installs wouldn't be deterministic and the lockfile would be useless. What it actually does is that it tries to not duplicate dependencies in the first place.\n\n **Example:** If `foo@^2.3.4` (a dependency of a dependency) has already been resolved to `foo@2.3.4`, running `yarn add foo@*`will cause Yarn to reuse `foo@2.3.4`, even if the latest `foo` is actually `foo@2.10.14`, thus preventing unnecessary duplication.\n\n Duplication happens when Yarn can't unlock dependencies that have already been locked inside the lockfile.\n\n **Example:** If `foo@^2.3.4` (a dependency of a dependency) has already been resolved to `foo@2.3.4`, running `yarn add foo@2.10.14` will cause Yarn to install `foo@2.10.14` because the existing resolution doesn't satisfy the range `2.10.14`. This behavior can lead to (sometimes) unwanted duplication, since now the lockfile contains 2 separate resolutions for the 2 `foo` descriptors, even though they have overlapping ranges, which means that the lockfile can be simplified so that both descriptors resolve to `foo@2.10.14`.\n ",examples:[["Dedupe all packages","$0 dedupe"],["Dedupe all packages using a specific strategy","$0 dedupe --strategy highest"],["Dedupe a specific package","$0 dedupe lodash"],["Dedupe all packages with the `@babel/*` scope","$0 dedupe '@babel/*'"],["Check for duplicates (can be used as a CI step)","$0 dedupe --check"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s}=await Tt.find(r,this.context.cwd),a=await Kr.find(r);await s.restoreInstallState({restoreResolutions:!1});let n=0,c=await Ot.start({configuration:r,includeFooter:!1,stdout:this.context.stdout,json:this.json},async f=>{n=await z5(s,{strategy:this.strategy,patterns:this.patterns,cache:a,report:f})});return c.hasErrors()?c.exitCode():this.check?n?1:0:await s.installWithNewReport({json:this.json,stdout:this.context.stdout},{cache:a,mode:this.mode})}};Ge();Yt();var pC=class extends ft{static{this.paths=[["--clipanion=definitions"]]}async execute(){let{plugins:e}=await ze.find(this.context.cwd,this.context.plugins),r=[];for(let c of e){let{commands:f}=c[1];if(f){let h=Ca.from(f).definitions();r.push([c[0],h])}}let s=this.cli.definitions(),a=(c,f)=>c.split(" ").slice(1).join()===f.split(" ").slice(1).join(),n=dye()["@yarnpkg/builder"].bundles.standard;for(let c of r){let f=c[1];for(let p of f)s.find(h=>a(h.path,p.path)).plugin={name:c[0],isDefault:n.includes(c[0])}}this.context.stdout.write(`${JSON.stringify(s,null,2)} +`)}};var hC=class extends ft{static{this.paths=[["help"],["--help"],["-h"]]}async execute(){this.context.stdout.write(this.cli.usage(null))}};Ge();Dt();Yt();var gC=class extends ft{constructor(){super(...arguments);this.leadingArgument=ge.String();this.args=ge.Proxy()}async execute(){if(this.leadingArgument.match(/[\\/]/)&&!G.tryParseIdent(this.leadingArgument)){let r=J.resolve(this.context.cwd,fe.toPortablePath(this.leadingArgument));return await this.cli.run(this.args,{cwd:r})}else return await this.cli.run(["run",this.leadingArgument,...this.args])}};Ge();var dC=class extends ft{static{this.paths=[["-v"],["--version"]]}async execute(){this.context.stdout.write(`${fn||""} +`)}};Ge();Ge();Yt();var mC=class extends ft{constructor(){super(...arguments);this.commandName=ge.String();this.args=ge.Proxy()}static{this.paths=[["exec"]]}static{this.usage=ot.Usage({description:"execute a shell script",details:` + This command simply executes a shell script within the context of the root directory of the active workspace using the portable shell. + + It also makes sure to call it in a way that's compatible with the current project (for example, on PnP projects the environment will be setup in such a way that PnP will be correctly injected into the environment). + `,examples:[["Execute a single shell command","$0 exec echo Hello World"],["Execute a shell script",'$0 exec "tsc & babel src --out-dir lib"']]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,locator:a}=await Tt.find(r,this.context.cwd);return await s.restoreInstallState(),await In.executePackageShellcode(a,this.commandName,this.args,{cwd:this.context.cwd,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr,project:s})}};Ge();Yt();Ul();var yC=class extends ft{constructor(){super(...arguments);this.hash=ge.String({required:!1,validator:Nx(wE(),[Z2(/^p[0-9a-f]{6}$/)])})}static{this.paths=[["explain","peer-requirements"]]}static{this.usage=ot.Usage({description:"explain a set of peer requirements",details:` + A peer requirement represents all peer requests that a subject must satisfy when providing a requested package to requesters. + + When the hash argument is specified, this command prints a detailed explanation of the peer requirement corresponding to the hash and whether it is satisfied or not. + + When used without arguments, this command lists all peer requirements and the corresponding hash that can be used to get detailed information about a given requirement. + + **Note:** A hash is a seven-letter code consisting of the letter 'p' followed by six characters that can be obtained from peer dependency warnings or from the list of all peer requirements(\`yarn explain peer-requirements\`). + `,examples:[["Explain the corresponding peer requirement for a hash","$0 explain peer-requirements p1a4ed"],["List all peer requirements","$0 explain peer-requirements"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s}=await Tt.find(r,this.context.cwd);return await s.restoreInstallState({restoreResolutions:!1}),await s.applyLightResolution(),typeof this.hash<"u"?await Wlt(this.hash,s,{stdout:this.context.stdout}):await Ylt(s,{stdout:this.context.stdout})}};async function Wlt(t,e,r){let s=e.peerRequirementNodes.get(t);if(typeof s>"u")throw new Error(`No peerDependency requirements found for hash: "${t}"`);let a=new Set,n=p=>a.has(p.requester.locatorHash)?{value:he.tuple(he.Type.DEPENDENT,{locator:p.requester,descriptor:p.descriptor}),children:p.children.size>0?[{value:he.tuple(he.Type.NO_HINT,"...")}]:[]}:(a.add(p.requester.locatorHash),{value:he.tuple(he.Type.DEPENDENT,{locator:p.requester,descriptor:p.descriptor}),children:Object.fromEntries(Array.from(p.children.values(),h=>[G.stringifyLocator(h.requester),n(h)]))}),c=e.peerWarnings.find(p=>p.hash===t);return(await Ot.start({configuration:e.configuration,stdout:r.stdout,includeFooter:!1,includePrefix:!1},async p=>{let h=he.mark(e.configuration),E=c?h.Cross:h.Check;if(p.reportInfo(0,`Package ${he.pretty(e.configuration,s.subject,he.Type.LOCATOR)} is requested to provide ${he.pretty(e.configuration,s.ident,he.Type.IDENT)} by its descendants`),p.reportSeparator(),p.reportInfo(0,he.pretty(e.configuration,s.subject,he.Type.LOCATOR)),xs.emitTree({children:Object.fromEntries(Array.from(s.requests.values(),C=>[G.stringifyLocator(C.requester),n(C)]))},{configuration:e.configuration,stdout:r.stdout,json:!1}),p.reportSeparator(),s.provided.range==="missing:"){let C=c?"":" , but all peer requests are optional";p.reportInfo(0,`${E} Package ${he.pretty(e.configuration,s.subject,he.Type.LOCATOR)} does not provide ${he.pretty(e.configuration,s.ident,he.Type.IDENT)}${C}.`)}else{let C=e.storedResolutions.get(s.provided.descriptorHash);if(!C)throw new Error("Assertion failed: Expected the descriptor to be registered");let S=e.storedPackages.get(C);if(!S)throw new Error("Assertion failed: Expected the package to be registered");p.reportInfo(0,`${E} Package ${he.pretty(e.configuration,s.subject,he.Type.LOCATOR)} provides ${he.pretty(e.configuration,s.ident,he.Type.IDENT)} with version ${G.prettyReference(e.configuration,S.version??"0.0.0")}, ${c?"which does not satisfy all requests.":"which satisfies all requests"}`),c?.type===3&&(c.range?p.reportInfo(0,` The combined requested range is ${he.pretty(e.configuration,c.range,he.Type.RANGE)}`):p.reportInfo(0," Unfortunately, the requested ranges have no overlap"))}})).exitCode()}async function Ylt(t,e){return(await Ot.start({configuration:t.configuration,stdout:e.stdout,includeFooter:!1,includePrefix:!1},async s=>{let a=he.mark(t.configuration),n=je.sortMap(t.peerRequirementNodes,[([,c])=>G.stringifyLocator(c.subject),([,c])=>G.stringifyIdent(c.ident)]);for(let[,c]of n.values()){if(!c.root)continue;let f=t.peerWarnings.find(E=>E.hash===c.hash),p=[...G.allPeerRequests(c)],h;if(p.length>2?h=` and ${p.length-1} other dependencies`:p.length===2?h=" and 1 other dependency":h="",c.provided.range!=="missing:"){let E=t.storedResolutions.get(c.provided.descriptorHash);if(!E)throw new Error("Assertion failed: Expected the resolution to have been registered");let C=t.storedPackages.get(E);if(!C)throw new Error("Assertion failed: Expected the provided package to have been registered");let S=`${he.pretty(t.configuration,c.hash,he.Type.CODE)} \u2192 ${f?a.Cross:a.Check} ${G.prettyLocator(t.configuration,c.subject)} provides ${G.prettyLocator(t.configuration,C)} to ${G.prettyLocator(t.configuration,p[0].requester)}${h}`;f?s.reportWarning(0,S):s.reportInfo(0,S)}else{let E=`${he.pretty(t.configuration,c.hash,he.Type.CODE)} \u2192 ${f?a.Cross:a.Check} ${G.prettyLocator(t.configuration,c.subject)} doesn't provide ${G.prettyIdent(t.configuration,c.ident)} to ${G.prettyLocator(t.configuration,p[0].requester)}${h}`;f?s.reportWarning(0,E):s.reportInfo(0,E)}}})).exitCode()}Ge();Yt();Ul();Ge();Ge();Dt();Yt();var mye=ut(Ai()),EC=class extends ft{constructor(){super(...arguments);this.useYarnPath=ge.Boolean("--yarn-path",{description:"Set the yarnPath setting even if the version can be accessed by Corepack"});this.onlyIfNeeded=ge.Boolean("--only-if-needed",!1,{description:"Only lock the Yarn version if it isn't already locked"});this.version=ge.String()}static{this.paths=[["set","version"]]}static{this.usage=ot.Usage({description:"lock the Yarn version used by the project",details:"\n This command will set a specific release of Yarn to be used by Corepack: https://nodejs.org/api/corepack.html.\n\n By default it only will set the `packageManager` field at the root of your project, but if the referenced release cannot be represented this way, if you already have `yarnPath` configured, or if you set the `--yarn-path` command line flag, then the release will also be downloaded from the Yarn GitHub repository, stored inside your project, and referenced via the `yarnPath` settings from your project `.yarnrc.yml` file.\n\n A very good use case for this command is to enforce the version of Yarn used by any single member of your team inside the same project - by doing this you ensure that you have control over Yarn upgrades and downgrades (including on your deployment servers), and get rid of most of the headaches related to someone using a slightly different version and getting different behavior.\n\n The version specifier can be:\n\n - a tag:\n - `latest` / `berry` / `stable` -> the most recent stable berry (`>=2.0.0`) release\n - `canary` -> the most recent canary (release candidate) berry (`>=2.0.0`) release\n - `classic` -> the most recent classic (`^0.x || ^1.x`) release\n\n - a semver range (e.g. `2.x`) -> the most recent version satisfying the range (limited to berry releases)\n\n - a semver version (e.g. `2.4.1`, `1.22.1`)\n\n - a local file referenced through either a relative or absolute path\n\n - `self` -> the version used to invoke the command\n ",examples:[["Download the latest release from the Yarn repository","$0 set version latest"],["Download the latest canary release from the Yarn repository","$0 set version canary"],["Download the latest classic release from the Yarn repository","$0 set version classic"],["Download the most recent Yarn 3 build","$0 set version 3.x"],["Download a specific Yarn 2 build","$0 set version 2.0.0-rc.30"],["Switch back to a specific Yarn 1 release","$0 set version 1.22.1"],["Use a release from the local filesystem","$0 set version ./yarn.cjs"],["Use a release from a URL","$0 set version https://repo.yarnpkg.com/3.1.0/packages/yarnpkg-cli/bin/yarn.js"],["Download the version used to invoke the command","$0 set version self"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins);if(this.onlyIfNeeded&&r.get("yarnPath")){let f=r.sources.get("yarnPath");if(!f)throw new Error("Assertion failed: Expected 'yarnPath' to have a source");let p=r.projectCwd??r.startingCwd;if(J.contains(p,f))return 0}let s=()=>{if(typeof fn>"u")throw new nt("The --install flag can only be used without explicit version specifier from the Yarn CLI");return`file://${process.argv[1]}`},a,n=(f,p)=>({version:p,url:f.replace(/\{\}/g,p)});if(this.version==="self")a={url:s(),version:fn??"self"};else if(this.version==="latest"||this.version==="berry"||this.version==="stable")a=n("https://repo.yarnpkg.com/{}/packages/yarnpkg-cli/bin/yarn.js",await Zv(r,"stable"));else if(this.version==="canary")a=n("https://repo.yarnpkg.com/{}/packages/yarnpkg-cli/bin/yarn.js",await Zv(r,"canary"));else if(this.version==="classic")a={url:"https://classic.yarnpkg.com/latest.js",version:"classic"};else if(this.version.match(/^https?:/))a={url:this.version,version:"remote"};else if(this.version.match(/^\.{0,2}[\\/]/)||fe.isAbsolute(this.version))a={url:`file://${J.resolve(fe.toPortablePath(this.version))}`,version:"file"};else if(Fr.satisfiesWithPrereleases(this.version,">=2.0.0"))a=n("https://repo.yarnpkg.com/{}/packages/yarnpkg-cli/bin/yarn.js",this.version);else if(Fr.satisfiesWithPrereleases(this.version,"^0.x || ^1.x"))a=n("https://github.com/yarnpkg/yarn/releases/download/v{}/yarn-{}.js",this.version);else if(Fr.validRange(this.version))a=n("https://repo.yarnpkg.com/{}/packages/yarnpkg-cli/bin/yarn.js",await Vlt(r,this.version));else throw new nt(`Invalid version descriptor "${this.version}"`);return(await Ot.start({configuration:r,stdout:this.context.stdout,includeLogs:!this.context.quiet},async f=>{let p=async()=>{let h="file://";return a.url.startsWith(h)?(f.reportInfo(0,`Retrieving ${he.pretty(r,a.url,he.Type.PATH)}`),await ce.readFilePromise(a.url.slice(h.length))):(f.reportInfo(0,`Downloading ${he.pretty(r,a.url,he.Type.URL)}`),await nn.get(a.url,{configuration:r}))};await X5(r,a.version,p,{report:f,useYarnPath:this.useYarnPath})})).exitCode()}};async function Vlt(t,e){let s=(await nn.get("https://repo.yarnpkg.com/tags",{configuration:t,jsonResponse:!0})).tags.filter(a=>Fr.satisfiesWithPrereleases(a,e));if(s.length===0)throw new nt(`No matching release found for range ${he.pretty(t,e,he.Type.RANGE)}.`);return s[0]}async function Zv(t,e){let r=await nn.get("https://repo.yarnpkg.com/tags",{configuration:t,jsonResponse:!0});if(!r.latest[e])throw new nt(`Tag ${he.pretty(t,e,he.Type.RANGE)} not found`);return r.latest[e]}async function X5(t,e,r,{report:s,useYarnPath:a}){let n,c=async()=>(typeof n>"u"&&(n=await r()),n);if(e===null){let ee=await c();await ce.mktempPromise(async ie=>{let ue=J.join(ie,"yarn.cjs");await ce.writeFilePromise(ue,ee);let{stdout:le}=await qr.execvp(process.execPath,[fe.fromPortablePath(ue),"--version"],{cwd:ie,env:{...t.env,YARN_IGNORE_PATH:"1"}});if(e=le.trim(),!mye.default.valid(e))throw new Error(`Invalid semver version. ${he.pretty(t,"yarn --version",he.Type.CODE)} returned: +${e}`)})}let f=t.projectCwd??t.startingCwd,p=J.resolve(f,".yarn/releases"),h=J.resolve(p,`yarn-${e}.cjs`),E=J.relative(t.startingCwd,h),C=je.isTaggedYarnVersion(e),S=t.get("yarnPath"),P=!C,I=P||!!S||!!a;if(a===!1){if(P)throw new jt(0,"You explicitly opted out of yarnPath usage in your command line, but the version you specified cannot be represented by Corepack");I=!1}else!I&&!process.env.COREPACK_ROOT&&(s.reportWarning(0,`You don't seem to have ${he.applyHyperlink(t,"Corepack","https://nodejs.org/api/corepack.html")} enabled; we'll have to rely on ${he.applyHyperlink(t,"yarnPath","https://yarnpkg.com/configuration/yarnrc#yarnPath")} instead`),I=!0);if(I){let ee=await c();s.reportInfo(0,`Saving the new release in ${he.pretty(t,E,"magenta")}`),await ce.removePromise(J.dirname(h)),await ce.mkdirPromise(J.dirname(h),{recursive:!0}),await ce.writeFilePromise(h,ee,{mode:493}),await ze.updateConfiguration(f,{yarnPath:J.relative(f,h)})}else await ce.removePromise(J.dirname(h)),await ze.updateConfiguration(f,{yarnPath:ze.deleteProperty});let R=await Ut.tryFind(f)||new Ut;R.packageManager=`yarn@${C?e:await Zv(t,"stable")}`;let N={};R.exportTo(N);let U=J.join(f,Ut.fileName),W=`${JSON.stringify(N,null,R.indent)} +`;return await ce.changeFilePromise(U,W,{automaticNewlines:!0}),{bundleVersion:e}}function yye(t){return Br[jx(t)]}var Jlt=/## (?YN[0-9]{4}) - `(?[A-Z_]+)`\n\n(?
(?:.(?!##))+)/gs;async function Klt(t){let r=`https://repo.yarnpkg.com/${je.isTaggedYarnVersion(fn)?fn:await Zv(t,"canary")}/packages/docusaurus/docs/advanced/01-general-reference/error-codes.mdx`,s=await nn.get(r,{configuration:t});return new Map(Array.from(s.toString().matchAll(Jlt),({groups:a})=>{if(!a)throw new Error("Assertion failed: Expected the match to have been successful");let n=yye(a.code);if(a.name!==n)throw new Error(`Assertion failed: Invalid error code data: Expected "${a.name}" to be named "${n}"`);return[a.code,a.details]}))}var IC=class extends ft{constructor(){super(...arguments);this.code=ge.String({required:!1,validator:$2(wE(),[Z2(/^YN[0-9]{4}$/)])});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"})}static{this.paths=[["explain"]]}static{this.usage=ot.Usage({description:"explain an error code",details:` + When the code argument is specified, this command prints its name and its details. + + When used without arguments, this command lists all error codes and their names. + `,examples:[["Explain an error code","$0 explain YN0006"],["List all error codes","$0 explain"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins);if(typeof this.code<"u"){let s=yye(this.code),a=he.pretty(r,s,he.Type.CODE),n=this.cli.format().header(`${this.code} - ${a}`),f=(await Klt(r)).get(this.code),p=typeof f<"u"?he.jsonOrPretty(this.json,r,he.tuple(he.Type.MARKDOWN,{text:f,format:this.cli.format(),paragraphs:!0})):`This error code does not have a description. + +You can help us by editing this page on GitHub \u{1F642}: +${he.jsonOrPretty(this.json,r,he.tuple(he.Type.URL,"https://github.com/yarnpkg/berry/blob/master/packages/docusaurus/docs/advanced/01-general-reference/error-codes.mdx"))} +`;this.json?this.context.stdout.write(`${JSON.stringify({code:this.code,name:s,details:p})} +`):this.context.stdout.write(`${n} + +${p} +`)}else{let s={children:je.mapAndFilter(Object.entries(Br),([a,n])=>Number.isNaN(Number(a))?je.mapAndFilter.skip:{label:Yf(Number(a)),value:he.tuple(he.Type.CODE,n)})};xs.emitTree(s,{configuration:r,stdout:this.context.stdout,json:this.json})}}};Ge();Dt();Yt();var Eye=ut(Go()),CC=class extends ft{constructor(){super(...arguments);this.all=ge.Boolean("-A,--all",!1,{description:"Print versions of a package from the whole project"});this.recursive=ge.Boolean("-R,--recursive",!1,{description:"Print information for all packages, including transitive dependencies"});this.extra=ge.Array("-X,--extra",[],{description:"An array of requests of extra data provided by plugins"});this.cache=ge.Boolean("--cache",!1,{description:"Print information about the cache entry of a package (path, size, checksum)"});this.dependents=ge.Boolean("--dependents",!1,{description:"Print all dependents for each matching package"});this.manifest=ge.Boolean("--manifest",!1,{description:"Print data obtained by looking at the package archive (license, homepage, ...)"});this.nameOnly=ge.Boolean("--name-only",!1,{description:"Only print the name for the matching packages"});this.virtuals=ge.Boolean("--virtuals",!1,{description:"Print each instance of the virtual packages"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.patterns=ge.Rest()}static{this.paths=[["info"]]}static{this.usage=ot.Usage({description:"see information related to packages",details:"\n This command prints various information related to the specified packages, accepting glob patterns.\n\n By default, if the locator reference is missing, Yarn will default to print the information about all the matching direct dependencies of the package for the active workspace. To instead print all versions of the package that are direct dependencies of any of your workspaces, use the `-A,--all` flag. Adding the `-R,--recursive` flag will also report transitive dependencies.\n\n Some fields will be hidden by default in order to keep the output readable, but can be selectively displayed by using additional options (`--dependents`, `--manifest`, `--virtuals`, ...) described in the option descriptions.\n\n Note that this command will only print the information directly related to the selected packages - if you wish to know why the package is there in the first place, use `yarn why` which will do just that (it also provides a `-R,--recursive` flag that may be of some help).\n ",examples:[["Show information about Lodash","$0 info lodash"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Tt.find(r,this.context.cwd),n=await Kr.find(r);if(!a&&!this.all)throw new ar(s.cwd,this.context.cwd);await s.restoreInstallState();let c=new Set(this.extra);this.cache&&c.add("cache"),this.dependents&&c.add("dependents"),this.manifest&&c.add("manifest");let f=(ie,{recursive:ue})=>{let le=ie.anchoredLocator.locatorHash,me=new Map,pe=[le];for(;pe.length>0;){let Be=pe.shift();if(me.has(Be))continue;let Ce=s.storedPackages.get(Be);if(typeof Ce>"u")throw new Error("Assertion failed: Expected the package to be registered");if(me.set(Be,Ce),G.isVirtualLocator(Ce)&&pe.push(G.devirtualizeLocator(Ce).locatorHash),!(!ue&&Be!==le))for(let g of Ce.dependencies.values()){let we=s.storedResolutions.get(g.descriptorHash);if(typeof we>"u")throw new Error("Assertion failed: Expected the resolution to be registered");pe.push(we)}}return me.values()},p=({recursive:ie})=>{let ue=new Map;for(let le of s.workspaces)for(let me of f(le,{recursive:ie}))ue.set(me.locatorHash,me);return ue.values()},h=({all:ie,recursive:ue})=>ie&&ue?s.storedPackages.values():ie?p({recursive:ue}):f(a,{recursive:ue}),E=({all:ie,recursive:ue})=>{let le=h({all:ie,recursive:ue}),me=this.patterns.map(Ce=>{let g=G.parseLocator(Ce),we=Eye.default.makeRe(G.stringifyIdent(g)),ye=G.isVirtualLocator(g),Ae=ye?G.devirtualizeLocator(g):g;return se=>{let Z=G.stringifyIdent(se);if(!we.test(Z))return!1;if(g.reference==="unknown")return!0;let De=G.isVirtualLocator(se),Re=De?G.devirtualizeLocator(se):se;return!(ye&&De&&g.reference!==se.reference||Ae.reference!==Re.reference)}}),pe=je.sortMap([...le],Ce=>G.stringifyLocator(Ce));return{selection:pe.filter(Ce=>me.length===0||me.some(g=>g(Ce))),sortedLookup:pe}},{selection:C,sortedLookup:S}=E({all:this.all,recursive:this.recursive});if(C.length===0)throw new nt("No package matched your request");let P=new Map;if(this.dependents)for(let ie of S)for(let ue of ie.dependencies.values()){let le=s.storedResolutions.get(ue.descriptorHash);if(typeof le>"u")throw new Error("Assertion failed: Expected the resolution to be registered");je.getArrayWithDefault(P,le).push(ie)}let I=new Map;for(let ie of S){if(!G.isVirtualLocator(ie))continue;let ue=G.devirtualizeLocator(ie);je.getArrayWithDefault(I,ue.locatorHash).push(ie)}let R={},N={children:R},U=r.makeFetcher(),W={project:s,fetcher:U,cache:n,checksums:s.storedChecksums,report:new ki,cacheOptions:{skipIntegrityCheck:!0}},ee=[async(ie,ue,le)=>{if(!ue.has("manifest"))return;let me=await U.fetch(ie,W),pe;try{pe=await Ut.find(me.prefixPath,{baseFs:me.packageFs})}finally{me.releaseFs?.()}le("Manifest",{License:he.tuple(he.Type.NO_HINT,pe.license),Homepage:he.tuple(he.Type.URL,pe.raw.homepage??null)})},async(ie,ue,le)=>{if(!ue.has("cache"))return;let me=s.storedChecksums.get(ie.locatorHash)??null,pe=n.getLocatorPath(ie,me),Be;if(pe!==null)try{Be=await ce.statPromise(pe)}catch{}let Ce=typeof Be<"u"?[Be.size,he.Type.SIZE]:void 0;le("Cache",{Checksum:he.tuple(he.Type.NO_HINT,me),Path:he.tuple(he.Type.PATH,pe),Size:Ce})}];for(let ie of C){let ue=G.isVirtualLocator(ie);if(!this.virtuals&&ue)continue;let le={},me={value:[ie,he.Type.LOCATOR],children:le};if(R[G.stringifyLocator(ie)]=me,this.nameOnly){delete me.children;continue}let pe=I.get(ie.locatorHash);typeof pe<"u"&&(le.Instances={label:"Instances",value:he.tuple(he.Type.NUMBER,pe.length)}),le.Version={label:"Version",value:he.tuple(he.Type.NO_HINT,ie.version)};let Be=(g,we)=>{let ye={};if(le[g]=ye,Array.isArray(we))ye.children=we.map(Ae=>({value:Ae}));else{let Ae={};ye.children=Ae;for(let[se,Z]of Object.entries(we))typeof Z>"u"||(Ae[se]={label:se,value:Z})}};if(!ue){for(let g of ee)await g(ie,c,Be);await r.triggerHook(g=>g.fetchPackageInfo,ie,c,Be)}ie.bin.size>0&&!ue&&Be("Exported Binaries",[...ie.bin.keys()].map(g=>he.tuple(he.Type.PATH,g)));let Ce=P.get(ie.locatorHash);typeof Ce<"u"&&Ce.length>0&&Be("Dependents",Ce.map(g=>he.tuple(he.Type.LOCATOR,g))),ie.dependencies.size>0&&!ue&&Be("Dependencies",[...ie.dependencies.values()].map(g=>{let we=s.storedResolutions.get(g.descriptorHash),ye=typeof we<"u"?s.storedPackages.get(we)??null:null;return he.tuple(he.Type.RESOLUTION,{descriptor:g,locator:ye})})),ie.peerDependencies.size>0&&ue&&Be("Peer dependencies",[...ie.peerDependencies.values()].map(g=>{let we=ie.dependencies.get(g.identHash),ye=typeof we<"u"?s.storedResolutions.get(we.descriptorHash)??null:null,Ae=ye!==null?s.storedPackages.get(ye)??null:null;return he.tuple(he.Type.RESOLUTION,{descriptor:g,locator:Ae})}))}xs.emitTree(N,{configuration:r,json:this.json,stdout:this.context.stdout,separators:this.nameOnly?0:2})}};Ge();Dt();wc();var nF=ut(Fd());Yt();var Z5=ut(Ai());Ul();var zlt=[{selector:t=>t===-1,name:"nodeLinker",value:"node-modules"},{selector:t=>t!==-1&&t<8,name:"enableGlobalCache",value:!1},{selector:t=>t!==-1&&t<8,name:"compressionLevel",value:"mixed"}],wC=class extends ft{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.immutable=ge.Boolean("--immutable",{description:"Abort with an error exit code if the lockfile was to be modified"});this.immutableCache=ge.Boolean("--immutable-cache",{description:"Abort with an error exit code if the cache folder was to be modified"});this.refreshLockfile=ge.Boolean("--refresh-lockfile",{description:"Refresh the package metadata stored in the lockfile"});this.checkCache=ge.Boolean("--check-cache",{description:"Always refetch the packages and ensure that their checksums are consistent"});this.checkResolutions=ge.Boolean("--check-resolutions",{description:"Validates that the package resolutions are coherent"});this.inlineBuilds=ge.Boolean("--inline-builds",{description:"Verbosely print the output of the build steps of dependencies"});this.mode=ge.String("--mode",{description:"Change what artifacts installs generate",validator:fo($l)});this.cacheFolder=ge.String("--cache-folder",{hidden:!0});this.frozenLockfile=ge.Boolean("--frozen-lockfile",{hidden:!0});this.ignoreEngines=ge.Boolean("--ignore-engines",{hidden:!0});this.nonInteractive=ge.Boolean("--non-interactive",{hidden:!0});this.preferOffline=ge.Boolean("--prefer-offline",{hidden:!0});this.production=ge.Boolean("--production",{hidden:!0});this.registry=ge.String("--registry",{hidden:!0});this.silent=ge.Boolean("--silent",{hidden:!0});this.networkTimeout=ge.String("--network-timeout",{hidden:!0})}static{this.paths=[["install"],ot.Default]}static{this.usage=ot.Usage({description:"install the project dependencies",details:"\n This command sets up your project if needed. The installation is split into four different steps that each have their own characteristics:\n\n - **Resolution:** First the package manager will resolve your dependencies. The exact way a dependency version is privileged over another isn't standardized outside of the regular semver guarantees. If a package doesn't resolve to what you would expect, check that all dependencies are correctly declared (also check our website for more information: ).\n\n - **Fetch:** Then we download all the dependencies if needed, and make sure that they're all stored within our cache (check the value of `cacheFolder` in `yarn config` to see where the cache files are stored).\n\n - **Link:** Then we send the dependency tree information to internal plugins tasked with writing them on the disk in some form (for example by generating the `.pnp.cjs` file you might know).\n\n - **Build:** Once the dependency tree has been written on the disk, the package manager will now be free to run the build scripts for all packages that might need it, in a topological order compatible with the way they depend on one another. See https://yarnpkg.com/advanced/lifecycle-scripts for detail.\n\n Note that running this command is not part of the recommended workflow. Yarn supports zero-installs, which means that as long as you store your cache and your `.pnp.cjs` file inside your repository, everything will work without requiring any install right after cloning your repository or switching branches.\n\n If the `--immutable` option is set (defaults to true on CI), Yarn will abort with an error exit code if the lockfile was to be modified (other paths can be added using the `immutablePatterns` configuration setting). For backward compatibility we offer an alias under the name of `--frozen-lockfile`, but it will be removed in a later release.\n\n If the `--immutable-cache` option is set, Yarn will abort with an error exit code if the cache folder was to be modified (either because files would be added, or because they'd be removed).\n\n If the `--refresh-lockfile` option is set, Yarn will keep the same resolution for the packages currently in the lockfile but will refresh their metadata. If used together with `--immutable`, it can validate that the lockfile information are consistent. This flag is enabled by default when Yarn detects it runs within a pull request context.\n\n If the `--check-cache` option is set, Yarn will always refetch the packages and will ensure that their checksum matches what's 1/ described in the lockfile 2/ inside the existing cache files (if present). This is recommended as part of your CI workflow if you're both following the Zero-Installs model and accepting PRs from third-parties, as they'd otherwise have the ability to alter the checked-in packages before submitting them.\n\n If the `--inline-builds` option is set, Yarn will verbosely print the output of the build steps of your dependencies (instead of writing them into individual files). This is likely useful mostly for debug purposes only when using Docker-like environments.\n\n If the `--mode=` option is set, Yarn will change which artifacts are generated. The modes currently supported are:\n\n - `skip-build` will not run the build scripts at all. Note that this is different from setting `enableScripts` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run.\n\n - `update-lockfile` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost.\n ",examples:[["Install the project","$0 install"],["Validate a project when using Zero-Installs","$0 install --immutable --immutable-cache"],["Validate a project when using Zero-Installs (slightly safer if you accept external PRs)","$0 install --immutable --immutable-cache --check-cache"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins);typeof this.inlineBuilds<"u"&&r.useWithSource("",{enableInlineBuilds:this.inlineBuilds},r.startingCwd,{overwrite:!0});let s=!!process.env.FUNCTION_TARGET||!!process.env.GOOGLE_RUNTIME,a=await SI({configuration:r,stdout:this.context.stdout},[{option:this.ignoreEngines,message:"The --ignore-engines option is deprecated; engine checking isn't a core feature anymore",error:!nF.default.VERCEL},{option:this.registry,message:"The --registry option is deprecated; prefer setting npmRegistryServer in your .yarnrc.yml file"},{option:this.preferOffline,message:"The --prefer-offline flag is deprecated; use the --cached flag with 'yarn add' instead",error:!nF.default.VERCEL},{option:this.production,message:"The --production option is deprecated on 'install'; use 'yarn workspaces focus' instead",error:!0},{option:this.nonInteractive,message:"The --non-interactive option is deprecated",error:!s},{option:this.frozenLockfile,message:"The --frozen-lockfile option is deprecated; use --immutable and/or --immutable-cache instead",callback:()=>this.immutable=this.frozenLockfile},{option:this.cacheFolder,message:"The cache-folder option has been deprecated; use rc settings instead",error:!nF.default.NETLIFY}]);if(a!==null)return a;let n=this.mode==="update-lockfile";if(n&&(this.immutable||this.immutableCache))throw new nt(`${he.pretty(r,"--immutable",he.Type.CODE)} and ${he.pretty(r,"--immutable-cache",he.Type.CODE)} cannot be used with ${he.pretty(r,"--mode=update-lockfile",he.Type.CODE)}`);let c=(this.immutable??r.get("enableImmutableInstalls"))&&!n,f=this.immutableCache&&!n;if(r.projectCwd!==null){let R=await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout,includeFooter:!1},async N=>{let U=!1;await $lt(r,c)&&(N.reportInfo(48,"Automatically removed core plugins that are now builtins \u{1F44D}"),U=!0),await Zlt(r,c)&&(N.reportInfo(48,"Automatically fixed merge conflicts \u{1F44D}"),U=!0),U&&N.reportSeparator()});if(R.hasErrors())return R.exitCode()}if(r.projectCwd!==null){let R=await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout,includeFooter:!1},async N=>{if(ze.telemetry?.isNew)ze.telemetry.commitTips(),N.reportInfo(65,"Yarn will periodically gather anonymous telemetry: https://yarnpkg.com/advanced/telemetry"),N.reportInfo(65,`Run ${he.pretty(r,"yarn config set --home enableTelemetry 0",he.Type.CODE)} to disable`),N.reportSeparator();else if(ze.telemetry?.shouldShowTips){let U=await nn.get("https://repo.yarnpkg.com/tags",{configuration:r,jsonResponse:!0}).catch(()=>null);if(U!==null){let W=null;if(fn!==null){let ie=Z5.default.prerelease(fn)?"canary":"stable",ue=U.latest[ie];Z5.default.gt(ue,fn)&&(W=[ie,ue])}if(W)ze.telemetry.commitTips(),N.reportInfo(88,`${he.applyStyle(r,`A new ${W[0]} version of Yarn is available:`,he.Style.BOLD)} ${G.prettyReference(r,W[1])}!`),N.reportInfo(88,`Upgrade now by running ${he.pretty(r,`yarn set version ${W[1]}`,he.Type.CODE)}`),N.reportSeparator();else{let ee=ze.telemetry.selectTip(U.tips);ee&&(N.reportInfo(89,he.pretty(r,ee.message,he.Type.MARKDOWN_INLINE)),ee.url&&N.reportInfo(89,`Learn more at ${ee.url}`),N.reportSeparator())}}}});if(R.hasErrors())return R.exitCode()}let{project:p,workspace:h}=await Tt.find(r,this.context.cwd),E=p.lockfileLastVersion;if(E!==null){let R=await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout,includeFooter:!1},async N=>{let U={};for(let W of zlt)W.selector(E)&&typeof r.sources.get(W.name)>"u"&&(r.use("",{[W.name]:W.value},p.cwd,{overwrite:!0}),U[W.name]=W.value);Object.keys(U).length>0&&(await ze.updateConfiguration(p.cwd,U),N.reportInfo(87,"Migrated your project to the latest Yarn version \u{1F680}"),N.reportSeparator())});if(R.hasErrors())return R.exitCode()}let C=await Kr.find(r,{immutable:f,check:this.checkCache});if(!h)throw new ar(p.cwd,this.context.cwd);await p.restoreInstallState({restoreResolutions:!1});let S=r.get("enableHardenedMode");S&&typeof r.sources.get("enableHardenedMode")>"u"&&await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout,includeFooter:!1},async R=>{R.reportWarning(0,"Yarn detected that the current workflow is executed from a public pull request. For safety the hardened mode has been enabled."),R.reportWarning(0,`It will prevent malicious lockfile manipulations, in exchange for a slower install time. You can opt-out if necessary; check our ${he.applyHyperlink(r,"documentation","https://yarnpkg.com/features/security#hardened-mode")} for more details.`),R.reportSeparator()}),(this.refreshLockfile??S)&&(p.lockfileNeedsRefresh=!0);let P=this.checkResolutions??S;return(await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout,forceSectionAlignment:!0,includeLogs:!0,includeVersion:!0},async R=>{await p.install({cache:C,report:R,immutable:c,checkResolutions:P,mode:this.mode})})).exitCode()}},Xlt="<<<<<<<";async function Zlt(t,e){if(!t.projectCwd)return!1;let r=J.join(t.projectCwd,Er.lockfile);if(!await ce.existsPromise(r)||!(await ce.readFilePromise(r,"utf8")).includes(Xlt))return!1;if(e)throw new jt(47,"Cannot autofix a lockfile when running an immutable install");let a=await qr.execvp("git",["rev-parse","MERGE_HEAD","HEAD"],{cwd:t.projectCwd});if(a.code!==0&&(a=await qr.execvp("git",["rev-parse","REBASE_HEAD","HEAD"],{cwd:t.projectCwd})),a.code!==0&&(a=await qr.execvp("git",["rev-parse","CHERRY_PICK_HEAD","HEAD"],{cwd:t.projectCwd})),a.code!==0)throw new jt(83,"Git returned an error when trying to find the commits pertaining to the conflict");let n=await Promise.all(a.stdout.trim().split(/\n/).map(async f=>{let p=await qr.execvp("git",["show",`${f}:./${Er.lockfile}`],{cwd:t.projectCwd});if(p.code!==0)throw new jt(83,`Git returned an error when trying to access the lockfile content in ${f}`);try{return ls(p.stdout)}catch{throw new jt(46,"A variant of the conflicting lockfile failed to parse")}}));n=n.filter(f=>!!f.__metadata);for(let f of n){if(f.__metadata.version<7)for(let p of Object.keys(f)){if(p==="__metadata")continue;let h=G.parseDescriptor(p,!0),E=t.normalizeDependency(h),C=G.stringifyDescriptor(E);C!==p&&(f[C]=f[p],delete f[p])}for(let p of Object.keys(f)){if(p==="__metadata")continue;let h=f[p].checksum;typeof h>"u"||h.includes("/")||(f[p].checksum=`${f.__metadata.cacheKey}/${h}`)}}let c=Object.assign({},...n);c.__metadata.version=`${Math.min(...n.map(f=>parseInt(f.__metadata.version??0)))}`,c.__metadata.cacheKey="merged";for(let[f,p]of Object.entries(c))typeof p=="string"&&delete c[f];return await ce.changeFilePromise(r,nl(c),{automaticNewlines:!0}),!0}async function $lt(t,e){if(!t.projectCwd)return!1;let r=[],s=J.join(t.projectCwd,".yarn/plugins/@yarnpkg");return await ze.updateConfiguration(t.projectCwd,{plugins:n=>{if(!Array.isArray(n))return n;let c=n.filter(f=>{if(!f.path)return!0;let p=J.resolve(t.projectCwd,f.path),h=ov.has(f.spec)&&J.contains(s,p);return h&&r.push(p),!h});return c.length===0?ze.deleteProperty:c.length===n.length?n:c}},{immutable:e})?(await Promise.all(r.map(async n=>{await ce.removePromise(n)})),!0):!1}Ge();Dt();Yt();var BC=class extends ft{constructor(){super(...arguments);this.all=ge.Boolean("-A,--all",!1,{description:"Link all workspaces belonging to the target projects to the current one"});this.private=ge.Boolean("-p,--private",!1,{description:"Also link private workspaces belonging to the target projects to the current one"});this.relative=ge.Boolean("-r,--relative",!1,{description:"Link workspaces using relative paths instead of absolute paths"});this.destinations=ge.Rest()}static{this.paths=[["link"]]}static{this.usage=ot.Usage({description:"connect the local project to another one",details:"\n This command will set a new `resolutions` field in the project-level manifest and point it to the workspace at the specified location (even if part of another project).\n ",examples:[["Register one or more remote workspaces for use in the current project","$0 link ~/ts-loader ~/jest"],["Register all workspaces from a remote project for use in the current project","$0 link ~/jest --all"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Tt.find(r,this.context.cwd),n=await Kr.find(r);if(!a)throw new ar(s.cwd,this.context.cwd);await s.restoreInstallState({restoreResolutions:!1});let c=s.topLevelWorkspace,f=[];for(let p of this.destinations){let h=J.resolve(this.context.cwd,fe.toPortablePath(p)),E=await ze.find(h,this.context.plugins,{useRc:!1,strict:!1}),{project:C,workspace:S}=await Tt.find(E,h);if(s.cwd===C.cwd)throw new nt(`Invalid destination '${p}'; Can't link the project to itself`);if(!S)throw new ar(C.cwd,h);if(this.all){let P=!1;for(let I of C.workspaces)I.manifest.name&&(!I.manifest.private||this.private)&&(f.push(I),P=!0);if(!P)throw new nt(`No workspace found to be linked in the target project: ${p}`)}else{if(!S.manifest.name)throw new nt(`The target workspace at '${p}' doesn't have a name and thus cannot be linked`);if(S.manifest.private&&!this.private)throw new nt(`The target workspace at '${p}' is marked private - use the --private flag to link it anyway`);f.push(S)}}for(let p of f){let h=G.stringifyIdent(p.anchoredLocator),E=this.relative?J.relative(s.cwd,p.cwd):p.cwd;c.manifest.resolutions.push({pattern:{descriptor:{fullName:h}},reference:`portal:${E}`})}return await s.installWithNewReport({stdout:this.context.stdout},{cache:n})}};Yt();var vC=class extends ft{constructor(){super(...arguments);this.args=ge.Proxy()}static{this.paths=[["node"]]}static{this.usage=ot.Usage({description:"run node with the hook already setup",details:` + This command simply runs Node. It also makes sure to call it in a way that's compatible with the current project (for example, on PnP projects the environment will be setup in such a way that PnP will be correctly injected into the environment). + + The Node process will use the exact same version of Node as the one used to run Yarn itself, which might be a good way to ensure that your commands always use a consistent Node version. + `,examples:[["Run a Node script","$0 node ./my-script.js"]]})}async execute(){return this.cli.run(["exec","node",...this.args])}};Ge();Yt();var SC=class extends ft{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"})}static{this.paths=[["plugin","check"]]}static{this.usage=ot.Usage({category:"Plugin-related commands",description:"find all third-party plugins that differ from their own spec",details:` + Check only the plugins from https. + + If this command detects any plugin differences in the CI environment, it will throw an error. + `,examples:[["find all third-party plugins that differ from their own spec","$0 plugin check"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),s=await ze.findRcFiles(this.context.cwd);return(await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout},async n=>{for(let c of s)if(c.data?.plugins)for(let f of c.data.plugins){if(!f.checksum||!f.spec.match(/^https?:/))continue;let p=await nn.get(f.spec,{configuration:r}),h=Nn.makeHash(p);if(f.checksum===h)continue;let E=he.pretty(r,f.path,he.Type.PATH),C=he.pretty(r,f.spec,he.Type.URL),S=`${E} is different from the file provided by ${C}`;n.reportJson({...f,newChecksum:h}),n.reportError(0,S)}})).exitCode()}};Ge();Ge();Dt();Yt();var vye=Ie("os");Ge();Dt();Yt();var Iye=Ie("os");Ge();wc();Yt();var ect="https://raw.githubusercontent.com/yarnpkg/berry/master/plugins.yml";async function Sm(t,e){let r=await nn.get(ect,{configuration:t}),s=ls(r.toString());return Object.fromEntries(Object.entries(s).filter(([a,n])=>!e||Fr.satisfiesWithPrereleases(e,n.range??"<4.0.0-rc.1")))}var DC=class extends ft{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"})}static{this.paths=[["plugin","list"]]}static{this.usage=ot.Usage({category:"Plugin-related commands",description:"list the available official plugins",details:"\n This command prints the plugins available directly from the Yarn repository. Only those plugins can be referenced by name in `yarn plugin import`.\n ",examples:[["List the official plugins","$0 plugin list"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins);return(await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout},async a=>{let n=await Sm(r,fn);for(let[c,{experimental:f,...p}]of Object.entries(n)){let h=c;f&&(h+=" [experimental]"),a.reportJson({name:c,experimental:f,...p}),a.reportInfo(null,h)}})).exitCode()}};var tct=/^[0-9]+$/,rct=process.platform==="win32";function Cye(t){return tct.test(t)?`pull/${t}/head`:t}var nct=({repository:t,branch:e},r)=>[["git","init",fe.fromPortablePath(r)],["git","remote","add","origin",t],["git","fetch","origin","--depth=1",Cye(e)],["git","reset","--hard","FETCH_HEAD"]],ict=({branch:t})=>[["git","fetch","origin","--depth=1",Cye(t),"--force"],["git","reset","--hard","FETCH_HEAD"],["git","clean","-dfx","-e","packages/yarnpkg-cli/bundles"]],sct=({plugins:t,noMinify:e},r,s)=>[["yarn","build:cli",...new Array().concat(...t.map(a=>["--plugin",J.resolve(s,a)])),...e?["--no-minify"]:[],"|"],[rct?"move":"mv","packages/yarnpkg-cli/bundles/yarn.js",fe.fromPortablePath(r),"|"]],bC=class extends ft{constructor(){super(...arguments);this.installPath=ge.String("--path",{description:"The path where the repository should be cloned to"});this.repository=ge.String("--repository","https://github.com/yarnpkg/berry.git",{description:"The repository that should be cloned"});this.branch=ge.String("--branch","master",{description:"The branch of the repository that should be cloned"});this.plugins=ge.Array("--plugin",[],{description:"An array of additional plugins that should be included in the bundle"});this.dryRun=ge.Boolean("-n,--dry-run",!1,{description:"If set, the bundle will be built but not added to the project"});this.noMinify=ge.Boolean("--no-minify",!1,{description:"Build a bundle for development (debugging) - non-minified and non-mangled"});this.force=ge.Boolean("-f,--force",!1,{description:"Always clone the repository instead of trying to fetch the latest commits"});this.skipPlugins=ge.Boolean("--skip-plugins",!1,{description:"Skip updating the contrib plugins"})}static{this.paths=[["set","version","from","sources"]]}static{this.usage=ot.Usage({description:"build Yarn from master",details:` + This command will clone the Yarn repository into a temporary folder, then build it. The resulting bundle will then be copied into the local project. + + By default, it also updates all contrib plugins to the same commit the bundle is built from. This behavior can be disabled by using the \`--skip-plugins\` flag. + `,examples:[["Build Yarn from master","$0 set version from sources"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s}=await Tt.find(r,this.context.cwd),a=typeof this.installPath<"u"?J.resolve(this.context.cwd,fe.toPortablePath(this.installPath)):J.resolve(fe.toPortablePath((0,Iye.tmpdir)()),"yarnpkg-sources",Nn.makeHash(this.repository).slice(0,6));return(await Ot.start({configuration:r,stdout:this.context.stdout},async c=>{await $5(this,{configuration:r,report:c,target:a}),c.reportSeparator(),c.reportInfo(0,"Building a fresh bundle"),c.reportSeparator();let f=await qr.execvp("git",["rev-parse","--short","HEAD"],{cwd:a,strict:!0}),p=J.join(a,`packages/yarnpkg-cli/bundles/yarn-${f.stdout.trim()}.js`);ce.existsSync(p)||(await $v(sct(this,p,a),{configuration:r,context:this.context,target:a}),c.reportSeparator());let h=await ce.readFilePromise(p);if(!this.dryRun){let{bundleVersion:E}=await X5(r,null,async()=>h,{report:c});this.skipPlugins||await oct(this,E,{project:s,report:c,target:a})}})).exitCode()}};async function $v(t,{configuration:e,context:r,target:s}){for(let[a,...n]of t){let c=n[n.length-1]==="|";if(c&&n.pop(),c)await qr.pipevp(a,n,{cwd:s,stdin:r.stdin,stdout:r.stdout,stderr:r.stderr,strict:!0});else{r.stdout.write(`${he.pretty(e,` $ ${[a,...n].join(" ")}`,"grey")} +`);try{await qr.execvp(a,n,{cwd:s,strict:!0})}catch(f){throw r.stdout.write(f.stdout||f.stack),f}}}}async function $5(t,{configuration:e,report:r,target:s}){let a=!1;if(!t.force&&ce.existsSync(J.join(s,".git"))){r.reportInfo(0,"Fetching the latest commits"),r.reportSeparator();try{await $v(ict(t),{configuration:e,context:t.context,target:s}),a=!0}catch{r.reportSeparator(),r.reportWarning(0,"Repository update failed; we'll try to regenerate it")}}a||(r.reportInfo(0,"Cloning the remote repository"),r.reportSeparator(),await ce.removePromise(s),await ce.mkdirPromise(s,{recursive:!0}),await $v(nct(t,s),{configuration:e,context:t.context,target:s}))}async function oct(t,e,{project:r,report:s,target:a}){let n=await Sm(r.configuration,e),c=new Set(Object.keys(n));for(let f of r.configuration.plugins.keys())c.has(f)&&await eq(f,t,{project:r,report:s,target:a})}Ge();Ge();Dt();Yt();var wye=ut(Ai()),Bye=Ie("vm");var PC=class extends ft{constructor(){super(...arguments);this.name=ge.String();this.checksum=ge.Boolean("--checksum",!0,{description:"Whether to care if this plugin is modified"})}static{this.paths=[["plugin","import"]]}static{this.usage=ot.Usage({category:"Plugin-related commands",description:"download a plugin",details:` + This command downloads the specified plugin from its remote location and updates the configuration to reference it in further CLI invocations. + + Three types of plugin references are accepted: + + - If the plugin is stored within the Yarn repository, it can be referenced by name. + - Third-party plugins can be referenced directly through their public urls. + - Local plugins can be referenced by their path on the disk. + + If the \`--no-checksum\` option is set, Yarn will no longer care if the plugin is modified. + + Plugins cannot be downloaded from the npm registry, and aren't allowed to have dependencies (they need to be bundled into a single file, possibly thanks to the \`@yarnpkg/builder\` package). + `,examples:[['Download and activate the "@yarnpkg/plugin-exec" plugin',"$0 plugin import @yarnpkg/plugin-exec"],['Download and activate the "@yarnpkg/plugin-exec" plugin (shorthand)',"$0 plugin import exec"],["Download and activate a community plugin","$0 plugin import https://example.org/path/to/plugin.js"],["Activate a local plugin","$0 plugin import ./path/to/plugin.js"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins);return(await Ot.start({configuration:r,stdout:this.context.stdout},async a=>{let{project:n}=await Tt.find(r,this.context.cwd),c,f;if(this.name.match(/^\.{0,2}[\\/]/)||fe.isAbsolute(this.name)){let p=J.resolve(this.context.cwd,fe.toPortablePath(this.name));a.reportInfo(0,`Reading ${he.pretty(r,p,he.Type.PATH)}`),c=J.relative(n.cwd,p),f=await ce.readFilePromise(p)}else{let p;if(this.name.match(/^https?:/)){try{new URL(this.name)}catch{throw new jt(52,`Plugin specifier "${this.name}" is neither a plugin name nor a valid url`)}c=this.name,p=this.name}else{let h=G.parseLocator(this.name.replace(/^((@yarnpkg\/)?plugin-)?/,"@yarnpkg/plugin-"));if(h.reference!=="unknown"&&!wye.default.valid(h.reference))throw new jt(0,"Official plugins only accept strict version references. Use an explicit URL if you wish to download them from another location.");let E=G.stringifyIdent(h),C=await Sm(r,fn);if(!Object.hasOwn(C,E)){let S=`Couldn't find a plugin named ${G.prettyIdent(r,h)} on the remote registry. +`;throw r.plugins.has(E)?S+=`A plugin named ${G.prettyIdent(r,h)} is already installed; possibly attempting to import a built-in plugin.`:S+=`Note that only the plugins referenced on our website (${he.pretty(r,"https://github.com/yarnpkg/berry/blob/master/plugins.yml",he.Type.URL)}) can be referenced by their name; any other plugin will have to be referenced through its public url (for example ${he.pretty(r,"https://github.com/yarnpkg/berry/raw/master/packages/plugin-typescript/bin/%40yarnpkg/plugin-typescript.js",he.Type.URL)}).`,new jt(51,S)}c=E,p=C[E].url,h.reference!=="unknown"?p=p.replace(/\/master\//,`/${E}/${h.reference}/`):fn!==null&&(p=p.replace(/\/master\//,`/@yarnpkg/cli/${fn}/`))}a.reportInfo(0,`Downloading ${he.pretty(r,p,"green")}`),f=await nn.get(p,{configuration:r})}await tq(c,f,{checksum:this.checksum,project:n,report:a})})).exitCode()}};async function tq(t,e,{checksum:r=!0,project:s,report:a}){let{configuration:n}=s,c={},f={exports:c};(0,Bye.runInNewContext)(e.toString(),{module:f,exports:c});let h=`.yarn/plugins/${f.exports.name}.cjs`,E=J.resolve(s.cwd,h);a.reportInfo(0,`Saving the new plugin in ${he.pretty(n,h,"magenta")}`),await ce.mkdirPromise(J.dirname(E),{recursive:!0}),await ce.writeFilePromise(E,e);let C={path:h,spec:t};r&&(C.checksum=Nn.makeHash(e)),await ze.addPlugin(s.cwd,[C])}var act=({pluginName:t,noMinify:e},r)=>[["yarn",`build:${t}`,...e?["--no-minify"]:[],"|"]],xC=class extends ft{constructor(){super(...arguments);this.installPath=ge.String("--path",{description:"The path where the repository should be cloned to"});this.repository=ge.String("--repository","https://github.com/yarnpkg/berry.git",{description:"The repository that should be cloned"});this.branch=ge.String("--branch","master",{description:"The branch of the repository that should be cloned"});this.noMinify=ge.Boolean("--no-minify",!1,{description:"Build a plugin for development (debugging) - non-minified and non-mangled"});this.force=ge.Boolean("-f,--force",!1,{description:"Always clone the repository instead of trying to fetch the latest commits"});this.name=ge.String()}static{this.paths=[["plugin","import","from","sources"]]}static{this.usage=ot.Usage({category:"Plugin-related commands",description:"build a plugin from sources",details:` + This command clones the Yarn repository into a temporary folder, builds the specified contrib plugin and updates the configuration to reference it in further CLI invocations. + + The plugins can be referenced by their short name if sourced from the official Yarn repository. + `,examples:[['Build and activate the "@yarnpkg/plugin-exec" plugin',"$0 plugin import from sources @yarnpkg/plugin-exec"],['Build and activate the "@yarnpkg/plugin-exec" plugin (shorthand)',"$0 plugin import from sources exec"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),s=typeof this.installPath<"u"?J.resolve(this.context.cwd,fe.toPortablePath(this.installPath)):J.resolve(fe.toPortablePath((0,vye.tmpdir)()),"yarnpkg-sources",Nn.makeHash(this.repository).slice(0,6));return(await Ot.start({configuration:r,stdout:this.context.stdout},async n=>{let{project:c}=await Tt.find(r,this.context.cwd),f=G.parseIdent(this.name.replace(/^((@yarnpkg\/)?plugin-)?/,"@yarnpkg/plugin-")),p=G.stringifyIdent(f),h=await Sm(r,fn);if(!Object.hasOwn(h,p))throw new jt(51,`Couldn't find a plugin named "${p}" on the remote registry. Note that only the plugins referenced on our website (https://github.com/yarnpkg/berry/blob/master/plugins.yml) can be built and imported from sources.`);let E=p;await $5(this,{configuration:r,report:n,target:s}),await eq(E,this,{project:c,report:n,target:s})})).exitCode()}};async function eq(t,{context:e,noMinify:r},{project:s,report:a,target:n}){let c=t.replace(/@yarnpkg\//,""),{configuration:f}=s;a.reportSeparator(),a.reportInfo(0,`Building a fresh ${c}`),a.reportSeparator(),await $v(act({pluginName:c,noMinify:r},n),{configuration:f,context:e,target:n}),a.reportSeparator();let p=J.resolve(n,`packages/${c}/bundles/${t}.js`),h=await ce.readFilePromise(p);await tq(t,h,{project:s,report:a})}Ge();Dt();Yt();var kC=class extends ft{constructor(){super(...arguments);this.name=ge.String()}static{this.paths=[["plugin","remove"]]}static{this.usage=ot.Usage({category:"Plugin-related commands",description:"remove a plugin",details:` + This command deletes the specified plugin from the .yarn/plugins folder and removes it from the configuration. + + **Note:** The plugins have to be referenced by their name property, which can be obtained using the \`yarn plugin runtime\` command. Shorthands are not allowed. + `,examples:[["Remove a plugin imported from the Yarn repository","$0 plugin remove @yarnpkg/plugin-typescript"],["Remove a plugin imported from a local file","$0 plugin remove my-local-plugin"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s}=await Tt.find(r,this.context.cwd);return(await Ot.start({configuration:r,stdout:this.context.stdout},async n=>{let c=this.name,f=G.parseIdent(c);if(!r.plugins.has(c))throw new nt(`${G.prettyIdent(r,f)} isn't referenced by the current configuration`);let p=`.yarn/plugins/${c}.cjs`,h=J.resolve(s.cwd,p);ce.existsSync(h)&&(n.reportInfo(0,`Removing ${he.pretty(r,p,he.Type.PATH)}...`),await ce.removePromise(h)),n.reportInfo(0,"Updating the configuration..."),await ze.updateConfiguration(s.cwd,{plugins:E=>{if(!Array.isArray(E))return E;let C=E.filter(S=>S.path!==p);return C.length===0?ze.deleteProperty:C.length===E.length?E:C}})})).exitCode()}};Ge();Yt();var QC=class extends ft{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"})}static{this.paths=[["plugin","runtime"]]}static{this.usage=ot.Usage({category:"Plugin-related commands",description:"list the active plugins",details:` + This command prints the currently active plugins. Will be displayed both builtin plugins and external plugins. + `,examples:[["List the currently active plugins","$0 plugin runtime"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins);return(await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout},async a=>{for(let n of r.plugins.keys()){let c=this.context.plugins.plugins.has(n),f=n;c&&(f+=" [builtin]"),a.reportJson({name:n,builtin:c}),a.reportInfo(null,`${f}`)}})).exitCode()}};Ge();Ge();Yt();var TC=class extends ft{constructor(){super(...arguments);this.idents=ge.Rest()}static{this.paths=[["rebuild"]]}static{this.usage=ot.Usage({description:"rebuild the project's native packages",details:` + This command will automatically cause Yarn to forget about previous compilations of the given packages and to run them again. + + Note that while Yarn forgets the compilation, the previous artifacts aren't erased from the filesystem and may affect the next builds (in good or bad). To avoid this, you may remove the .yarn/unplugged folder, or any other relevant location where packages might have been stored (Yarn may offer a way to do that automatically in the future). + + By default all packages will be rebuilt, but you can filter the list by specifying the names of the packages you want to clear from memory. + `,examples:[["Rebuild all packages","$0 rebuild"],["Rebuild fsevents only","$0 rebuild fsevents"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Tt.find(r,this.context.cwd),n=await Kr.find(r);if(!a)throw new ar(s.cwd,this.context.cwd);let c=new Set;for(let f of this.idents)c.add(G.parseIdent(f).identHash);if(await s.restoreInstallState({restoreResolutions:!1}),await s.resolveEverything({cache:n,report:new ki}),c.size>0)for(let f of s.storedPackages.values())c.has(f.identHash)&&(s.storedBuildState.delete(f.locatorHash),s.skippedBuilds.delete(f.locatorHash));else s.storedBuildState.clear(),s.skippedBuilds.clear();return await s.installWithNewReport({stdout:this.context.stdout,quiet:this.context.quiet},{cache:n})}};Ge();Ge();Ge();Yt();var rq=ut(Go());Ul();var RC=class extends ft{constructor(){super(...arguments);this.all=ge.Boolean("-A,--all",!1,{description:"Apply the operation to all workspaces from the current project"});this.mode=ge.String("--mode",{description:"Change what artifacts installs generate",validator:fo($l)});this.patterns=ge.Rest()}static{this.paths=[["remove"]]}static{this.usage=ot.Usage({description:"remove dependencies from the project",details:` + This command will remove the packages matching the specified patterns from the current workspace. + + If the \`--mode=\` option is set, Yarn will change which artifacts are generated. The modes currently supported are: + + - \`skip-build\` will not run the build scripts at all. Note that this is different from setting \`enableScripts\` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run. + + - \`update-lockfile\` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost. + + This command accepts glob patterns as arguments (if valid Idents and supported by [micromatch](https://github.com/micromatch/micromatch)). Make sure to escape the patterns, to prevent your own shell from trying to expand them. + `,examples:[["Remove a dependency from the current project","$0 remove lodash"],["Remove a dependency from all workspaces at once","$0 remove lodash --all"],["Remove all dependencies starting with `eslint-`","$0 remove 'eslint-*'"],["Remove all dependencies with the `@babel` scope","$0 remove '@babel/*'"],["Remove all dependencies matching `react-dom` or `react-helmet`","$0 remove 'react-{dom,helmet}'"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Tt.find(r,this.context.cwd),n=await Kr.find(r);if(!a)throw new ar(s.cwd,this.context.cwd);await s.restoreInstallState({restoreResolutions:!1});let c=this.all?s.workspaces:[a],f=["dependencies","devDependencies","peerDependencies"],p=[],h=!1,E=[];for(let I of this.patterns){let R=!1,N=G.parseIdent(I);for(let U of c){let W=[...U.manifest.peerDependenciesMeta.keys()];for(let ee of(0,rq.default)(W,I))U.manifest.peerDependenciesMeta.delete(ee),h=!0,R=!0;for(let ee of f){let ie=U.manifest.getForScope(ee),ue=[...ie.values()].map(le=>G.stringifyIdent(le));for(let le of(0,rq.default)(ue,G.stringifyIdent(N))){let{identHash:me}=G.parseIdent(le),pe=ie.get(me);if(typeof pe>"u")throw new Error("Assertion failed: Expected the descriptor to be registered");U.manifest[ee].delete(me),E.push([U,ee,pe]),h=!0,R=!0}}}R||p.push(I)}let C=p.length>1?"Patterns":"Pattern",S=p.length>1?"don't":"doesn't",P=this.all?"any":"this";if(p.length>0)throw new nt(`${C} ${he.prettyList(r,p,he.Type.CODE)} ${S} match any packages referenced by ${P} workspace`);return h?(await r.triggerMultipleHooks(I=>I.afterWorkspaceDependencyRemoval,E),await s.installWithNewReport({stdout:this.context.stdout},{cache:n,mode:this.mode})):0}};Ge();Ge();Yt();var Sye=Ie("util"),FC=class extends ft{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"})}static{this.paths=[["run"]]}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Tt.find(r,this.context.cwd);if(!a)throw new ar(s.cwd,this.context.cwd);return(await Ot.start({configuration:r,stdout:this.context.stdout,json:this.json},async c=>{let f=a.manifest.scripts,p=je.sortMap(f.keys(),C=>C),h={breakLength:1/0,colors:r.get("enableColors"),maxArrayLength:2},E=p.reduce((C,S)=>Math.max(C,S.length),0);for(let[C,S]of f.entries())c.reportInfo(null,`${C.padEnd(E," ")} ${(0,Sye.inspect)(S,h)}`),c.reportJson({name:C,script:S})})).exitCode()}};Ge();Ge();Yt();var NC=class extends ft{constructor(){super(...arguments);this.inspect=ge.String("--inspect",!1,{tolerateBoolean:!0,description:"Forwarded to the underlying Node process when executing a binary"});this.inspectBrk=ge.String("--inspect-brk",!1,{tolerateBoolean:!0,description:"Forwarded to the underlying Node process when executing a binary"});this.topLevel=ge.Boolean("-T,--top-level",!1,{description:"Check the root workspace for scripts and/or binaries instead of the current one"});this.binariesOnly=ge.Boolean("-B,--binaries-only",!1,{description:"Ignore any user defined scripts and only check for binaries"});this.require=ge.String("--require",{description:"Forwarded to the underlying Node process when executing a binary"});this.silent=ge.Boolean("--silent",{hidden:!0});this.scriptName=ge.String();this.args=ge.Proxy()}static{this.paths=[["run"]]}static{this.usage=ot.Usage({description:"run a script defined in the package.json",details:` + This command will run a tool. The exact tool that will be executed will depend on the current state of your workspace: + + - If the \`scripts\` field from your local package.json contains a matching script name, its definition will get executed. + + - Otherwise, if one of the local workspace's dependencies exposes a binary with a matching name, this binary will get executed. + + - Otherwise, if the specified name contains a colon character and if one of the workspaces in the project contains exactly one script with a matching name, then this script will get executed. + + Whatever happens, the cwd of the spawned process will be the workspace that declares the script (which makes it possible to call commands cross-workspaces using the third syntax). + `,examples:[["Run the tests from the local workspace","$0 run test"],['Same thing, but without the "run" keyword',"$0 test"],["Inspect Webpack while running","$0 run --inspect-brk webpack"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a,locator:n}=await Tt.find(r,this.context.cwd);await s.restoreInstallState();let c=this.topLevel?s.topLevelWorkspace.anchoredLocator:n;if(!this.binariesOnly&&await In.hasPackageScript(c,this.scriptName,{project:s}))return await In.executePackageScript(c,this.scriptName,this.args,{project:s,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr});let f=await In.getPackageAccessibleBinaries(c,{project:s});if(f.get(this.scriptName)){let h=[];return this.inspect&&(typeof this.inspect=="string"?h.push(`--inspect=${this.inspect}`):h.push("--inspect")),this.inspectBrk&&(typeof this.inspectBrk=="string"?h.push(`--inspect-brk=${this.inspectBrk}`):h.push("--inspect-brk")),this.require&&h.push(`--require=${this.require}`),await In.executePackageAccessibleBinary(c,this.scriptName,this.args,{cwd:this.context.cwd,project:s,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr,nodeArgs:h,packageAccessibleBinaries:f})}if(!this.topLevel&&!this.binariesOnly&&a&&this.scriptName.includes(":")){let E=(await Promise.all(s.workspaces.map(async C=>C.manifest.scripts.has(this.scriptName)?C:null))).filter(C=>C!==null);if(E.length===1)return await In.executeWorkspaceScript(E[0],this.scriptName,this.args,{stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr})}if(this.topLevel)throw this.scriptName==="node-gyp"?new nt(`Couldn't find a script name "${this.scriptName}" in the top-level (used by ${G.prettyLocator(r,n)}). This typically happens because some package depends on "node-gyp" to build itself, but didn't list it in their dependencies. To fix that, please run "yarn add node-gyp" into your top-level workspace. You also can open an issue on the repository of the specified package to suggest them to use an optional peer dependency.`):new nt(`Couldn't find a script name "${this.scriptName}" in the top-level (used by ${G.prettyLocator(r,n)}).`);{if(this.scriptName==="global")throw new nt("The 'yarn global' commands have been removed in 2.x - consider using 'yarn dlx' or a third-party plugin instead");let h=[this.scriptName].concat(this.args);for(let[E,C]of $I)for(let S of C)if(h.length>=S.length&&JSON.stringify(h.slice(0,S.length))===JSON.stringify(S))throw new nt(`Couldn't find a script named "${this.scriptName}", but a matching command can be found in the ${E} plugin. You can install it with "yarn plugin import ${E}".`);throw new nt(`Couldn't find a script named "${this.scriptName}".`)}}};Ge();Ge();Yt();var OC=class extends ft{constructor(){super(...arguments);this.descriptor=ge.String();this.resolution=ge.String()}static{this.paths=[["set","resolution"]]}static{this.usage=ot.Usage({description:"enforce a package resolution",details:'\n This command updates the resolution table so that `descriptor` is resolved by `resolution`.\n\n Note that by default this command only affect the current resolution table - meaning that this "manual override" will disappear if you remove the lockfile, or if the package disappear from the table. If you wish to make the enforced resolution persist whatever happens, edit the `resolutions` field in your top-level manifest.\n\n Note that no attempt is made at validating that `resolution` is a valid resolution entry for `descriptor`.\n ',examples:[["Force all instances of lodash@npm:^1.2.3 to resolve to 1.5.0","$0 set resolution lodash@npm:^1.2.3 npm:1.5.0"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Tt.find(r,this.context.cwd),n=await Kr.find(r);if(await s.restoreInstallState({restoreResolutions:!1}),!a)throw new ar(s.cwd,this.context.cwd);let c=G.parseDescriptor(this.descriptor,!0),f=G.makeDescriptor(c,this.resolution);return s.storedDescriptors.set(c.descriptorHash,c),s.storedDescriptors.set(f.descriptorHash,f),s.resolutionAliases.set(c.descriptorHash,f.descriptorHash),await s.installWithNewReport({stdout:this.context.stdout},{cache:n})}};Ge();Dt();Yt();var Dye=ut(Go()),LC=class extends ft{constructor(){super(...arguments);this.all=ge.Boolean("-A,--all",!1,{description:"Unlink all workspaces belonging to the target project from the current one"});this.leadingArguments=ge.Rest()}static{this.paths=[["unlink"]]}static{this.usage=ot.Usage({description:"disconnect the local project from another one",details:` + This command will remove any resolutions in the project-level manifest that would have been added via a yarn link with similar arguments. + `,examples:[["Unregister a remote workspace in the current project","$0 unlink ~/ts-loader"],["Unregister all workspaces from a remote project in the current project","$0 unlink ~/jest --all"],["Unregister all previously linked workspaces","$0 unlink --all"],["Unregister all workspaces matching a glob","$0 unlink '@babel/*' 'pkg-{a,b}'"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Tt.find(r,this.context.cwd),n=await Kr.find(r);if(!a)throw new ar(s.cwd,this.context.cwd);let c=s.topLevelWorkspace,f=new Set;if(this.leadingArguments.length===0&&this.all)for(let{pattern:p,reference:h}of c.manifest.resolutions)h.startsWith("portal:")&&f.add(p.descriptor.fullName);if(this.leadingArguments.length>0)for(let p of this.leadingArguments){let h=J.resolve(this.context.cwd,fe.toPortablePath(p));if(je.isPathLike(p)){let E=await ze.find(h,this.context.plugins,{useRc:!1,strict:!1}),{project:C,workspace:S}=await Tt.find(E,h);if(!S)throw new ar(C.cwd,h);if(this.all){for(let P of C.workspaces)P.manifest.name&&f.add(G.stringifyIdent(P.anchoredLocator));if(f.size===0)throw new nt("No workspace found to be unlinked in the target project")}else{if(!S.manifest.name)throw new nt("The target workspace doesn't have a name and thus cannot be unlinked");f.add(G.stringifyIdent(S.anchoredLocator))}}else{let E=[...c.manifest.resolutions.map(({pattern:C})=>C.descriptor.fullName)];for(let C of(0,Dye.default)(E,p))f.add(C)}}return c.manifest.resolutions=c.manifest.resolutions.filter(({pattern:p})=>!f.has(p.descriptor.fullName)),await s.installWithNewReport({stdout:this.context.stdout,quiet:this.context.quiet},{cache:n})}};Ge();Ge();Ge();Yt();var bye=ut(Vv()),nq=ut(Go());Ul();var MC=class extends ft{constructor(){super(...arguments);this.interactive=ge.Boolean("-i,--interactive",{description:"Offer various choices, depending on the detected upgrade paths"});this.fixed=ge.Boolean("-F,--fixed",!1,{description:"Store dependency tags as-is instead of resolving them"});this.exact=ge.Boolean("-E,--exact",!1,{description:"Don't use any semver modifier on the resolved range"});this.tilde=ge.Boolean("-T,--tilde",!1,{description:"Use the `~` semver modifier on the resolved range"});this.caret=ge.Boolean("-C,--caret",!1,{description:"Use the `^` semver modifier on the resolved range"});this.recursive=ge.Boolean("-R,--recursive",!1,{description:"Resolve again ALL resolutions for those packages"});this.mode=ge.String("--mode",{description:"Change what artifacts installs generate",validator:fo($l)});this.patterns=ge.Rest()}static{this.paths=[["up"]]}static{this.usage=ot.Usage({description:"upgrade dependencies across the project",details:"\n This command upgrades the packages matching the list of specified patterns to their latest available version across the whole project (regardless of whether they're part of `dependencies` or `devDependencies` - `peerDependencies` won't be affected). This is a project-wide command: all workspaces will be upgraded in the process.\n\n If `-R,--recursive` is set the command will change behavior and no other switch will be allowed. When operating under this mode `yarn up` will force all ranges matching the selected packages to be resolved again (often to the highest available versions) before being stored in the lockfile. It however won't touch your manifests anymore, so depending on your needs you might want to run both `yarn up` and `yarn up -R` to cover all bases.\n\n If `-i,--interactive` is set (or if the `preferInteractive` settings is toggled on) the command will offer various choices, depending on the detected upgrade paths. Some upgrades require this flag in order to resolve ambiguities.\n\n The, `-C,--caret`, `-E,--exact` and `-T,--tilde` options have the same meaning as in the `add` command (they change the modifier used when the range is missing or a tag, and are ignored when the range is explicitly set).\n\n If the `--mode=` option is set, Yarn will change which artifacts are generated. The modes currently supported are:\n\n - `skip-build` will not run the build scripts at all. Note that this is different from setting `enableScripts` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run.\n\n - `update-lockfile` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost.\n\n Generally you can see `yarn up` as a counterpart to what was `yarn upgrade --latest` in Yarn 1 (ie it ignores the ranges previously listed in your manifests), but unlike `yarn upgrade` which only upgraded dependencies in the current workspace, `yarn up` will upgrade all workspaces at the same time.\n\n This command accepts glob patterns as arguments (if valid Descriptors and supported by [micromatch](https://github.com/micromatch/micromatch)). Make sure to escape the patterns, to prevent your own shell from trying to expand them.\n\n **Note:** The ranges have to be static, only the package scopes and names can contain glob patterns.\n ",examples:[["Upgrade all instances of lodash to the latest release","$0 up lodash"],["Upgrade all instances of lodash to the latest release, but ask confirmation for each","$0 up lodash -i"],["Upgrade all instances of lodash to 1.2.3","$0 up lodash@1.2.3"],["Upgrade all instances of packages with the `@babel` scope to the latest release","$0 up '@babel/*'"],["Upgrade all instances of packages containing the word `jest` to the latest release","$0 up '*jest*'"],["Upgrade all instances of packages with the `@babel` scope to 7.0.0","$0 up '@babel/*@7.0.0'"]]})}static{this.schema=[tB("recursive",qf.Forbids,["interactive","exact","tilde","caret"],{ignore:[void 0,!1]})]}async execute(){return this.recursive?await this.executeUpRecursive():await this.executeUpClassic()}async executeUpRecursive(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Tt.find(r,this.context.cwd),n=await Kr.find(r);if(!a)throw new ar(s.cwd,this.context.cwd);await s.restoreInstallState({restoreResolutions:!1});let c=[...s.storedDescriptors.values()],f=c.map(E=>G.stringifyIdent(E)),p=new Set;for(let E of this.patterns){if(G.parseDescriptor(E).range!=="unknown")throw new nt("Ranges aren't allowed when using --recursive");for(let C of(0,nq.default)(f,E)){let S=G.parseIdent(C);p.add(S.identHash)}}let h=c.filter(E=>p.has(E.identHash));for(let E of h)s.storedDescriptors.delete(E.descriptorHash),s.storedResolutions.delete(E.descriptorHash);return await s.installWithNewReport({stdout:this.context.stdout},{cache:n,mode:this.mode})}async executeUpClassic(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Tt.find(r,this.context.cwd),n=await Kr.find(r);if(!a)throw new ar(s.cwd,this.context.cwd);await s.restoreInstallState({restoreResolutions:!1});let c=this.fixed,f=r.isInteractive({interactive:this.interactive,stdout:this.context.stdout}),p=Kv(this,s),h=f?["keep","reuse","project","latest"]:["project","latest"],E=[],C=[];for(let N of this.patterns){let U=!1,W=G.parseDescriptor(N),ee=G.stringifyIdent(W);for(let ie of s.workspaces)for(let ue of["dependencies","devDependencies"]){let me=[...ie.manifest.getForScope(ue).values()].map(Be=>G.stringifyIdent(Be)),pe=ee==="*"?me:(0,nq.default)(me,ee);for(let Be of pe){let Ce=G.parseIdent(Be),g=ie.manifest[ue].get(Ce.identHash);if(typeof g>"u")throw new Error("Assertion failed: Expected the descriptor to be registered");let we=G.makeDescriptor(Ce,W.range);E.push(Promise.resolve().then(async()=>[ie,ue,g,await zv(we,{project:s,workspace:ie,cache:n,target:ue,fixed:c,modifier:p,strategies:h})])),U=!0}}U||C.push(N)}if(C.length>1)throw new nt(`Patterns ${he.prettyList(r,C,he.Type.CODE)} don't match any packages referenced by any workspace`);if(C.length>0)throw new nt(`Pattern ${he.prettyList(r,C,he.Type.CODE)} doesn't match any packages referenced by any workspace`);let S=await Promise.all(E),P=await lA.start({configuration:r,stdout:this.context.stdout,suggestInstall:!1},async N=>{for(let[,,U,{suggestions:W,rejections:ee}]of S){let ie=W.filter(ue=>ue.descriptor!==null);if(ie.length===0){let[ue]=ee;if(typeof ue>"u")throw new Error("Assertion failed: Expected an error to have been set");let le=this.cli.error(ue);s.configuration.get("enableNetwork")?N.reportError(27,`${G.prettyDescriptor(r,U)} can't be resolved to a satisfying range + +${le}`):N.reportError(27,`${G.prettyDescriptor(r,U)} can't be resolved to a satisfying range (note: network resolution has been disabled) + +${le}`)}else ie.length>1&&!f&&N.reportError(27,`${G.prettyDescriptor(r,U)} has multiple possible upgrade strategies; use -i to disambiguate manually`)}});if(P.hasErrors())return P.exitCode();let I=!1,R=[];for(let[N,U,,{suggestions:W}]of S){let ee,ie=W.filter(pe=>pe.descriptor!==null),ue=ie[0].descriptor,le=ie.every(pe=>G.areDescriptorsEqual(pe.descriptor,ue));ie.length===1||le?ee=ue:(I=!0,{answer:ee}=await(0,bye.prompt)({type:"select",name:"answer",message:`Which range do you want to use in ${G.prettyWorkspace(r,N)} \u276F ${U}?`,choices:W.map(({descriptor:pe,name:Be,reason:Ce})=>pe?{name:Be,hint:Ce,descriptor:pe}:{name:Be,hint:Ce,disabled:!0}),onCancel:()=>process.exit(130),result(pe){return this.find(pe,"descriptor")},stdin:this.context.stdin,stdout:this.context.stdout}));let me=N.manifest[U].get(ee.identHash);if(typeof me>"u")throw new Error("Assertion failed: This descriptor should have a matching entry");if(me.descriptorHash!==ee.descriptorHash)N.manifest[U].set(ee.identHash,ee),R.push([N,U,me,ee]);else{let pe=r.makeResolver(),Be={project:s,resolver:pe},Ce=r.normalizeDependency(me),g=pe.bindDescriptor(Ce,N.anchoredLocator,Be);s.forgetResolution(g)}}return await r.triggerMultipleHooks(N=>N.afterWorkspaceDependencyReplacement,R),I&&this.context.stdout.write(` +`),await s.installWithNewReport({stdout:this.context.stdout},{cache:n,mode:this.mode})}};Ge();Ge();Ge();Yt();var UC=class extends ft{constructor(){super(...arguments);this.recursive=ge.Boolean("-R,--recursive",!1,{description:"List, for each workspace, what are all the paths that lead to the dependency"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.peers=ge.Boolean("--peers",!1,{description:"Also print the peer dependencies that match the specified name"});this.package=ge.String()}static{this.paths=[["why"]]}static{this.usage=ot.Usage({description:"display the reason why a package is needed",details:` + This command prints the exact reasons why a package appears in the dependency tree. + + If \`-R,--recursive\` is set, the listing will go in depth and will list, for each workspaces, what are all the paths that lead to the dependency. Note that the display is somewhat optimized in that it will not print the package listing twice for a single package, so if you see a leaf named "Foo" when looking for "Bar", it means that "Foo" already got printed higher in the tree. + `,examples:[["Explain why lodash is used in your project","$0 why lodash"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Tt.find(r,this.context.cwd);if(!a)throw new ar(s.cwd,this.context.cwd);await s.restoreInstallState();let n=G.parseIdent(this.package).identHash,c=this.recursive?cct(s,n,{configuration:r,peers:this.peers}):lct(s,n,{configuration:r,peers:this.peers});xs.emitTree(c,{configuration:r,stdout:this.context.stdout,json:this.json,separators:1})}};function lct(t,e,{configuration:r,peers:s}){let a=je.sortMap(t.storedPackages.values(),f=>G.stringifyLocator(f)),n={},c={children:n};for(let f of a){let p={};for(let E of f.dependencies.values()){if(!s&&f.peerDependencies.has(E.identHash))continue;let C=t.storedResolutions.get(E.descriptorHash);if(!C)throw new Error("Assertion failed: The resolution should have been registered");let S=t.storedPackages.get(C);if(!S)throw new Error("Assertion failed: The package should have been registered");if(S.identHash!==e)continue;{let I=G.stringifyLocator(f);n[I]={value:[f,he.Type.LOCATOR],children:p}}let P=G.stringifyLocator(S);p[P]={value:[{descriptor:E,locator:S},he.Type.DEPENDENT]}}}return c}function cct(t,e,{configuration:r,peers:s}){let a=je.sortMap(t.workspaces,S=>G.stringifyLocator(S.anchoredLocator)),n=new Set,c=new Set,f=S=>{if(n.has(S.locatorHash))return c.has(S.locatorHash);if(n.add(S.locatorHash),S.identHash===e)return c.add(S.locatorHash),!0;let P=!1;S.identHash===e&&(P=!0);for(let I of S.dependencies.values()){if(!s&&S.peerDependencies.has(I.identHash))continue;let R=t.storedResolutions.get(I.descriptorHash);if(!R)throw new Error("Assertion failed: The resolution should have been registered");let N=t.storedPackages.get(R);if(!N)throw new Error("Assertion failed: The package should have been registered");f(N)&&(P=!0)}return P&&c.add(S.locatorHash),P};for(let S of a)f(S.anchoredPackage);let p=new Set,h={},E={children:h},C=(S,P,I)=>{if(!c.has(S.locatorHash))return;let R=I!==null?he.tuple(he.Type.DEPENDENT,{locator:S,descriptor:I}):he.tuple(he.Type.LOCATOR,S),N={},U={value:R,children:N},W=G.stringifyLocator(S);if(P[W]=U,!(I!==null&&t.tryWorkspaceByLocator(S))&&!p.has(S.locatorHash)){p.add(S.locatorHash);for(let ee of S.dependencies.values()){if(!s&&S.peerDependencies.has(ee.identHash))continue;let ie=t.storedResolutions.get(ee.descriptorHash);if(!ie)throw new Error("Assertion failed: The resolution should have been registered");let ue=t.storedPackages.get(ie);if(!ue)throw new Error("Assertion failed: The package should have been registered");C(ue,N,ee)}}};for(let S of a)C(S.anchoredPackage,h,null);return E}Ge();var pq={};Vt(pq,{GitFetcher:()=>tS,GitResolver:()=>rS,default:()=>kct,gitUtils:()=>ka});Ge();Dt();var ka={};Vt(ka,{TreeishProtocols:()=>eS,clone:()=>Aq,fetchBase:()=>Jye,fetchChangedFiles:()=>Kye,fetchChangedWorkspaces:()=>Pct,fetchRoot:()=>Vye,isGitUrl:()=>jC,lsRemote:()=>Yye,normalizeLocator:()=>bct,normalizeRepoUrl:()=>_C,resolveUrl:()=>fq,splitRepoUrl:()=>W0,validateRepoUrl:()=>uq});Ge();Dt();Yt();ql();var qye=ut(Hye()),HC=ut(Ie("querystring")),lq=ut(Ai());function aq(t,e,r){let s=t.indexOf(r);return t.lastIndexOf(e,s>-1?s:1/0)}function jye(t){try{return new URL(t)}catch{return}}function Sct(t){let e=aq(t,"@","#"),r=aq(t,":","#");return r>e&&(t=`${t.slice(0,r)}/${t.slice(r+1)}`),aq(t,":","#")===-1&&t.indexOf("//")===-1&&(t=`ssh://${t}`),t}function Gye(t){return jye(t)||jye(Sct(t))}function _C(t,{git:e=!1}={}){if(t=t.replace(/^git\+https:/,"https:"),t=t.replace(/^(?:github:|https:\/\/github\.com\/|git:\/\/github\.com\/)?(?!\.{1,2}\/)([a-zA-Z0-9._-]+)\/(?!\.{1,2}(?:#|$))([a-zA-Z0-9._-]+?)(?:\.git)?(#.*)?$/,"https://github.com/$1/$2.git$3"),t=t.replace(/^https:\/\/github\.com\/(?!\.{1,2}\/)([a-zA-Z0-9._-]+)\/(?!\.{1,2}(?:#|$))([a-zA-Z0-9._-]+?)\/tarball\/(.+)?$/,"https://github.com/$1/$2.git#$3"),e){let r=Gye(t);r&&(t=r.href),t=t.replace(/^git\+([^:]+):/,"$1:")}return t}function Wye(){return{...process.env,GIT_SSH_COMMAND:process.env.GIT_SSH_COMMAND||`${process.env.GIT_SSH||"ssh"} -o BatchMode=yes`}}var Dct=[/^ssh:/,/^git(?:\+[^:]+)?:/,/^(?:git\+)?https?:[^#]+\/[^#]+(?:\.git)(?:#.*)?$/,/^git@[^#]+\/[^#]+\.git(?:#.*)?$/,/^(?:github:|https:\/\/github\.com\/)?(?!\.{1,2}\/)([a-zA-Z._0-9-]+)\/(?!\.{1,2}(?:#|$))([a-zA-Z._0-9-]+?)(?:\.git)?(?:#.*)?$/,/^https:\/\/github\.com\/(?!\.{1,2}\/)([a-zA-Z0-9._-]+)\/(?!\.{1,2}(?:#|$))([a-zA-Z0-9._-]+?)\/tarball\/(.+)?$/],eS=(a=>(a.Commit="commit",a.Head="head",a.Tag="tag",a.Semver="semver",a))(eS||{});function jC(t){return t?Dct.some(e=>!!t.match(e)):!1}function W0(t){t=_C(t);let e=t.indexOf("#");if(e===-1)return{repo:t,treeish:{protocol:"head",request:"HEAD"},extra:{}};let r=t.slice(0,e),s=t.slice(e+1);if(s.match(/^[a-z]+=/)){let a=HC.default.parse(s);for(let[p,h]of Object.entries(a))if(typeof h!="string")throw new Error(`Assertion failed: The ${p} parameter must be a literal string`);let n=Object.values(eS).find(p=>Object.hasOwn(a,p)),[c,f]=typeof n<"u"?[n,a[n]]:["head","HEAD"];for(let p of Object.values(eS))delete a[p];return{repo:r,treeish:{protocol:c,request:f},extra:a}}else{let a=s.indexOf(":"),[n,c]=a===-1?[null,s]:[s.slice(0,a),s.slice(a+1)];return{repo:r,treeish:{protocol:n,request:c},extra:{}}}}function bct(t){return G.makeLocator(t,_C(t.reference))}function uq(t,{configuration:e}){let r=_C(t,{git:!0});if(!nn.getNetworkSettings(`https://${(0,qye.default)(r).resource}`,{configuration:e}).enableNetwork)throw new jt(80,`Request to '${r}' has been blocked because of your configuration settings`);return r}async function Yye(t,e){let r=uq(t,{configuration:e}),s=await cq("listing refs",["ls-remote",r],{cwd:e.startingCwd,env:Wye()},{configuration:e,normalizedRepoUrl:r}),a=new Map,n=/^([a-f0-9]{40})\t([^\n]+)/gm,c;for(;(c=n.exec(s.stdout))!==null;)a.set(c[2],c[1]);return a}async function fq(t,e){let{repo:r,treeish:{protocol:s,request:a},extra:n}=W0(t),c=await Yye(r,e),f=(h,E)=>{switch(h){case"commit":{if(!E.match(/^[a-f0-9]{40}$/))throw new Error("Invalid commit hash");return HC.default.stringify({...n,commit:E})}case"head":{let C=c.get(E==="HEAD"?E:`refs/heads/${E}`);if(typeof C>"u")throw new Error(`Unknown head ("${E}")`);return HC.default.stringify({...n,commit:C})}case"tag":{let C=c.get(`refs/tags/${E}`);if(typeof C>"u")throw new Error(`Unknown tag ("${E}")`);return HC.default.stringify({...n,commit:C})}case"semver":{let C=Fr.validRange(E);if(!C)throw new Error(`Invalid range ("${E}")`);let S=new Map([...c.entries()].filter(([I])=>I.startsWith("refs/tags/")).map(([I,R])=>[lq.default.parse(I.slice(10)),R]).filter(I=>I[0]!==null)),P=lq.default.maxSatisfying([...S.keys()],C);if(P===null)throw new Error(`No matching range ("${E}")`);return HC.default.stringify({...n,commit:S.get(P)})}case null:{let C;if((C=p("commit",E))!==null||(C=p("tag",E))!==null||(C=p("head",E))!==null)return C;throw E.match(/^[a-f0-9]+$/)?new Error(`Couldn't resolve "${E}" as either a commit, a tag, or a head - if a commit, use the 40-characters commit hash`):new Error(`Couldn't resolve "${E}" as either a commit, a tag, or a head`)}default:throw new Error(`Invalid Git resolution protocol ("${h}")`)}},p=(h,E)=>{try{return f(h,E)}catch{return null}};return _C(`${r}#${f(s,a)}`)}async function Aq(t,e){return await e.getLimit("cloneConcurrency")(async()=>{let{repo:r,treeish:{protocol:s,request:a}}=W0(t);if(s!=="commit")throw new Error("Invalid treeish protocol when cloning");let n=uq(r,{configuration:e}),c=await ce.mktempPromise(),f={cwd:c,env:Wye()};return await cq("cloning the repository",["clone","-c","core.autocrlf=false",n,fe.fromPortablePath(c)],f,{configuration:e,normalizedRepoUrl:n}),await cq("switching branch",["checkout",`${a}`],f,{configuration:e,normalizedRepoUrl:n}),c})}async function Vye(t){let e,r=t;do{if(e=r,await ce.existsPromise(J.join(e,".git")))return e;r=J.dirname(e)}while(r!==e);return null}async function Jye(t,{baseRefs:e}){if(e.length===0)throw new nt("Can't run this command with zero base refs specified.");let r=[];for(let f of e){let{code:p}=await qr.execvp("git",["merge-base",f,"HEAD"],{cwd:t});p===0&&r.push(f)}if(r.length===0)throw new nt(`No ancestor could be found between any of HEAD and ${e.join(", ")}`);let{stdout:s}=await qr.execvp("git",["merge-base","HEAD",...r],{cwd:t,strict:!0}),a=s.trim(),{stdout:n}=await qr.execvp("git",["show","--quiet","--pretty=format:%s",a],{cwd:t,strict:!0}),c=n.trim();return{hash:a,title:c}}async function Kye(t,{base:e,project:r}){let s=je.buildIgnorePattern(r.configuration.get("changesetIgnorePatterns")),{stdout:a}=await qr.execvp("git",["diff","--name-only",`${e}`],{cwd:t,strict:!0}),n=a.split(/\r\n|\r|\n/).filter(h=>h.length>0).map(h=>J.resolve(t,fe.toPortablePath(h))),{stdout:c}=await qr.execvp("git",["ls-files","--others","--exclude-standard"],{cwd:t,strict:!0}),f=c.split(/\r\n|\r|\n/).filter(h=>h.length>0).map(h=>J.resolve(t,fe.toPortablePath(h))),p=[...new Set([...n,...f].sort())];return s?p.filter(h=>!J.relative(r.cwd,h).match(s)):p}async function Pct({ref:t,project:e}){if(e.configuration.projectCwd===null)throw new nt("This command can only be run from within a Yarn project");let r=[J.resolve(e.cwd,Er.lockfile),J.resolve(e.cwd,e.configuration.get("cacheFolder")),J.resolve(e.cwd,e.configuration.get("installStatePath")),J.resolve(e.cwd,e.configuration.get("virtualFolder"))];await e.configuration.triggerHook(c=>c.populateYarnPaths,e,c=>{c!=null&&r.push(c)});let s=await Vye(e.configuration.projectCwd);if(s==null)throw new nt("This command can only be run on Git repositories");let a=await Jye(s,{baseRefs:typeof t=="string"?[t]:e.configuration.get("changesetBaseRefs")}),n=await Kye(s,{base:a.hash,project:e});return new Set(je.mapAndFilter(n,c=>{let f=e.tryWorkspaceByFilePath(c);return f===null?je.mapAndFilter.skip:r.some(p=>c.startsWith(p))?je.mapAndFilter.skip:f}))}async function cq(t,e,r,{configuration:s,normalizedRepoUrl:a}){try{return await qr.execvp("git",e,{...r,strict:!0})}catch(n){if(!(n instanceof qr.ExecError))throw n;let c=n.reportExtra,f=n.stderr.toString();throw new jt(1,`Failed ${t}`,p=>{p.reportError(1,` ${he.prettyField(s,{label:"Repository URL",value:he.tuple(he.Type.URL,a)})}`);for(let h of f.matchAll(/^(.+?): (.*)$/gm)){let[,E,C]=h;E=E.toLowerCase();let S=E==="error"?"Error":`${bB(E)} Error`;p.reportError(1,` ${he.prettyField(s,{label:S,value:he.tuple(he.Type.NO_HINT,C)})}`)}c?.(p)})}}var tS=class{supports(e,r){return jC(e.reference)}getLocalPath(e,r){return null}async fetch(e,r){let s=r.checksums.get(e.locatorHash)||null,a=new Map(r.checksums);a.set(e.locatorHash,s);let n={...r,checksums:a},c=await this.downloadHosted(e,n);if(c!==null)return c;let[f,p,h]=await r.cache.fetchPackageFromCache(e,s,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${G.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the remote repository`),loader:()=>this.cloneFromRemote(e,n),...r.cacheOptions});return{packageFs:f,releaseFs:p,prefixPath:G.getIdentVendorPath(e),checksum:h}}async downloadHosted(e,r){return r.project.configuration.reduceHook(s=>s.fetchHostedRepository,null,e,r)}async cloneFromRemote(e,r){let s=W0(e.reference),a=await Aq(e.reference,r.project.configuration),n=J.resolve(a,s.extra.cwd??vt.dot),c=J.join(n,"package.tgz");await In.prepareExternalProject(n,c,{configuration:r.project.configuration,report:r.report,workspace:s.extra.workspace,locator:e});let f=await ce.readFilePromise(c);return await je.releaseAfterUseAsync(async()=>await ps.convertToZip(f,{configuration:r.project.configuration,prefixPath:G.getIdentVendorPath(e),stripComponents:1}))}};Ge();Ge();var rS=class{supportsDescriptor(e,r){return jC(e.range)}supportsLocator(e,r){return jC(e.reference)}shouldPersistResolution(e,r){return!0}bindDescriptor(e,r,s){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,s){let a=await fq(e.range,s.project.configuration);return[G.makeLocator(e,a)]}async getSatisfying(e,r,s,a){let n=W0(e.range);return{locators:s.filter(f=>{if(f.identHash!==e.identHash)return!1;let p=W0(f.reference);return!(n.repo!==p.repo||n.treeish.protocol==="commit"&&n.treeish.request!==p.treeish.request)}),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let s=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await je.releaseAfterUseAsync(async()=>await Ut.find(s.prefixPath,{baseFs:s.packageFs}),s.releaseFs);return{...e,version:a.version||"0.0.0",languageName:a.languageName||r.project.configuration.get("defaultLanguageName"),linkType:"HARD",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};var xct={configuration:{changesetBaseRefs:{description:"The base git refs that the current HEAD is compared against when detecting changes. Supports git branches, tags, and commits.",type:"STRING",isArray:!0,isNullable:!1,default:["master","origin/master","upstream/master","main","origin/main","upstream/main"]},changesetIgnorePatterns:{description:"Array of glob patterns; files matching them will be ignored when fetching the changed files",type:"STRING",default:[],isArray:!0},cloneConcurrency:{description:"Maximal number of concurrent clones",type:"NUMBER",default:2}},fetchers:[tS],resolvers:[rS]};var kct=xct;Yt();var GC=class extends ft{constructor(){super(...arguments);this.since=ge.String("--since",{description:"Only include workspaces that have been changed since the specified ref.",tolerateBoolean:!0});this.recursive=ge.Boolean("-R,--recursive",!1,{description:"Find packages via dependencies/devDependencies instead of using the workspaces field"});this.noPrivate=ge.Boolean("--no-private",{description:"Exclude workspaces that have the private field set to true"});this.verbose=ge.Boolean("-v,--verbose",!1,{description:"Also return the cross-dependencies between workspaces"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"})}static{this.paths=[["workspaces","list"]]}static{this.usage=ot.Usage({category:"Workspace-related commands",description:"list all available workspaces",details:"\n This command will print the list of all workspaces in the project.\n\n - If `--since` is set, Yarn will only list workspaces that have been modified since the specified ref. By default Yarn will use the refs specified by the `changesetBaseRefs` configuration option.\n\n - If `-R,--recursive` is set, Yarn will find workspaces to run the command on by recursively evaluating `dependencies` and `devDependencies` fields, instead of looking at the `workspaces` fields.\n\n - If `--no-private` is set, Yarn will not list any workspaces that have the `private` field set to `true`.\n\n - If both the `-v,--verbose` and `--json` options are set, Yarn will also return the cross-dependencies between each workspaces (useful when you wish to automatically generate Buck / Bazel rules).\n "})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s}=await Tt.find(r,this.context.cwd);return(await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout},async n=>{let c=this.since?await ka.fetchChangedWorkspaces({ref:this.since,project:s}):s.workspaces,f=new Set(c);if(this.recursive)for(let p of[...c].map(h=>h.getRecursiveWorkspaceDependents()))for(let h of p)f.add(h);for(let p of f){let{manifest:h}=p;if(h.private&&this.noPrivate)continue;let E;if(this.verbose){let C=new Set,S=new Set;for(let P of Ut.hardDependencies)for(let[I,R]of h.getForScope(P)){let N=s.tryWorkspaceByDescriptor(R);N===null?s.workspacesByIdent.has(I)&&S.add(R):C.add(N)}E={workspaceDependencies:Array.from(C).map(P=>P.relativeCwd),mismatchedWorkspaceDependencies:Array.from(S).map(P=>G.stringifyDescriptor(P))}}n.reportInfo(null,`${p.relativeCwd}`),n.reportJson({location:p.relativeCwd,name:h.name?G.stringifyIdent(h.name):null,...E})}})).exitCode()}};Ge();Ge();Yt();var qC=class extends ft{constructor(){super(...arguments);this.workspaceName=ge.String();this.commandName=ge.String();this.args=ge.Proxy()}static{this.paths=[["workspace"]]}static{this.usage=ot.Usage({category:"Workspace-related commands",description:"run a command within the specified workspace",details:` + This command will run a given sub-command on a single workspace. + `,examples:[["Add a package to a single workspace","yarn workspace components add -D react"],["Run build script on a single workspace","yarn workspace components run build"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Tt.find(r,this.context.cwd);if(!a)throw new ar(s.cwd,this.context.cwd);let n=s.workspaces,c=new Map(n.map(p=>[G.stringifyIdent(p.anchoredLocator),p])),f=c.get(this.workspaceName);if(f===void 0){let p=Array.from(c.keys()).sort();throw new nt(`Workspace '${this.workspaceName}' not found. Did you mean any of the following: + - ${p.join(` + - `)}?`)}return this.cli.run([this.commandName,...this.args],{cwd:f.cwd})}};var Qct={configuration:{enableImmutableInstalls:{description:"If true (the default on CI), prevents the install command from modifying the lockfile",type:"BOOLEAN",default:zye.isCI},defaultSemverRangePrefix:{description:"The default save prefix: '^', '~' or ''",type:"STRING",values:["^","~",""],default:"^"},preferReuse:{description:"If true, `yarn add` will attempt to reuse the most common dependency range in other workspaces.",type:"BOOLEAN",default:!1}},commands:[aC,lC,cC,uC,OC,bC,EC,GC,pC,hC,gC,dC,sC,oC,fC,AC,mC,yC,IC,CC,wC,BC,LC,vC,SC,xC,PC,kC,DC,QC,TC,RC,FC,NC,MC,UC,qC]},Tct=Qct;var yq={};Vt(yq,{default:()=>Oct});Ge();Ge();var gq="catalog:";var dq=t=>t.startsWith(gq),Rct=t=>t.range.slice(gq.length)||null,Xye=t=>t===null?"default catalog":`catalog "${t}"`,Fct=t=>t.scope?`@${t.scope}/${t.name}`:t.name,mq=(t,e,r,s)=>{let a=Rct(e),n;if(a===null)n=t.configuration.get("catalog");else try{let E=t.configuration.get("catalogs");E&&(n=E.get(a))}catch{n=void 0}if(!n||n.size===0)throw new jt(82,`${G.prettyDescriptor(t.configuration,e)}: ${Xye(a)} not found or empty`);let c=Fct(e),f=n.get(c);if(!f)throw new jt(82,`${G.prettyDescriptor(t.configuration,e)}: entry not found in ${Xye(a)}`);let p=t.configuration.normalizeDependency(G.makeDescriptor(e,f));return r.supportsDescriptor(p,s)?r.bindDescriptor(p,t.topLevelWorkspace.anchoredLocator,s):p};var Nct={configuration:{catalog:{description:"The default catalog of packages",type:"MAP",valueDefinition:{description:"The catalog of packages",type:"STRING"}},catalogs:{description:"Named catalogs of packages",type:"MAP",valueDefinition:{description:"A named catalog",type:"MAP",valueDefinition:{description:"Package version in the catalog",type:"STRING"}}}},hooks:{beforeWorkspacePacking:(t,e)=>{let r=t.project,s=r.configuration.makeResolver(),a={project:r,resolver:s,report:new ki};for(let n of Ut.allDependencies){let c=e[n];if(c)for(let[f,p]of Object.entries(c)){if(typeof p!="string"||!dq(p))continue;let h=G.parseIdent(f),E=G.makeDescriptor(h,p),C=mq(r,E,s,a),{protocol:S,source:P,params:I,selector:R}=G.parseRange(G.convertToManifestRange(C.range));S===t.project.configuration.get("defaultProtocol")&&(S=null),c[f]=G.makeRange({protocol:S,source:P,params:I,selector:R})}}},reduceDependency:async(t,e,r,s,{resolver:a,resolveOptions:n})=>dq(t.range)?mq(e,t,a,n):t}},Oct=Nct;var Bq={};Vt(Bq,{default:()=>Mct});Ge();var Qt={optional:!0},Eq=[["@tailwindcss/aspect-ratio@<0.2.1",{peerDependencies:{tailwindcss:"^2.0.2"}}],["@tailwindcss/line-clamp@<0.2.1",{peerDependencies:{tailwindcss:"^2.0.2"}}],["@fullhuman/postcss-purgecss@3.1.3 || 3.1.3-alpha.0",{peerDependencies:{postcss:"^8.0.0"}}],["@samverschueren/stream-to-observable@<0.3.1",{peerDependenciesMeta:{rxjs:Qt,zenObservable:Qt}}],["any-observable@<0.5.1",{peerDependenciesMeta:{rxjs:Qt,zenObservable:Qt}}],["@pm2/agent@<1.0.4",{dependencies:{debug:"*"}}],["debug@<4.2.0",{peerDependenciesMeta:{"supports-color":Qt}}],["got@<11",{dependencies:{"@types/responselike":"^1.0.0","@types/keyv":"^3.1.1"}}],["cacheable-lookup@<4.1.2",{dependencies:{"@types/keyv":"^3.1.1"}}],["http-link-dataloader@*",{peerDependencies:{graphql:"^0.13.1 || ^14.0.0"}}],["typescript-language-server@*",{dependencies:{"vscode-jsonrpc":"^5.0.1","vscode-languageserver-protocol":"^3.15.0"}}],["postcss-syntax@*",{peerDependenciesMeta:{"postcss-html":Qt,"postcss-jsx":Qt,"postcss-less":Qt,"postcss-markdown":Qt,"postcss-scss":Qt}}],["jss-plugin-rule-value-function@<=10.1.1",{dependencies:{"tiny-warning":"^1.0.2"}}],["ink-select-input@<4.1.0",{peerDependencies:{react:"^16.8.2"}}],["license-webpack-plugin@<2.3.18",{peerDependenciesMeta:{webpack:Qt}}],["snowpack@>=3.3.0",{dependencies:{"node-gyp":"^7.1.0"}}],["promise-inflight@*",{peerDependenciesMeta:{bluebird:Qt}}],["reactcss@*",{peerDependencies:{react:"*"}}],["react-color@<=2.19.0",{peerDependencies:{react:"*"}}],["gatsby-plugin-i18n@*",{dependencies:{ramda:"^0.24.1"}}],["useragent@^2.0.0",{dependencies:{request:"^2.88.0",yamlparser:"0.0.x",semver:"5.5.x"}}],["@apollographql/apollo-tools@<=0.5.2",{peerDependencies:{graphql:"^14.2.1 || ^15.0.0"}}],["material-table@^2.0.0",{dependencies:{"@babel/runtime":"^7.11.2"}}],["@babel/parser@*",{dependencies:{"@babel/types":"^7.8.3"}}],["fork-ts-checker-webpack-plugin@<=6.3.4",{peerDependencies:{eslint:">= 6",typescript:">= 2.7",webpack:">= 4","vue-template-compiler":"*"},peerDependenciesMeta:{eslint:Qt,"vue-template-compiler":Qt}}],["rc-animate@<=3.1.1",{peerDependencies:{react:">=16.9.0","react-dom":">=16.9.0"}}],["react-bootstrap-table2-paginator@*",{dependencies:{classnames:"^2.2.6"}}],["react-draggable@<=4.4.3",{peerDependencies:{react:">= 16.3.0","react-dom":">= 16.3.0"}}],["apollo-upload-client@<14",{peerDependencies:{graphql:"14 - 15"}}],["react-instantsearch-core@<=6.7.0",{peerDependencies:{algoliasearch:">= 3.1 < 5"}}],["react-instantsearch-dom@<=6.7.0",{dependencies:{"react-fast-compare":"^3.0.0"}}],["ws@<7.2.1",{peerDependencies:{bufferutil:"^4.0.1","utf-8-validate":"^5.0.2"},peerDependenciesMeta:{bufferutil:Qt,"utf-8-validate":Qt}}],["react-portal@<4.2.2",{peerDependencies:{"react-dom":"^15.0.0-0 || ^16.0.0-0 || ^17.0.0-0"}}],["react-scripts@<=4.0.1",{peerDependencies:{react:"*"}}],["testcafe@<=1.10.1",{dependencies:{"@babel/plugin-transform-for-of":"^7.12.1","@babel/runtime":"^7.12.5"}}],["testcafe-legacy-api@<=4.2.0",{dependencies:{"testcafe-hammerhead":"^17.0.1","read-file-relative":"^1.2.0"}}],["@google-cloud/firestore@<=4.9.3",{dependencies:{protobufjs:"^6.8.6"}}],["gatsby-source-apiserver@*",{dependencies:{"babel-polyfill":"^6.26.0"}}],["@webpack-cli/package-utils@<=1.0.1-alpha.4",{dependencies:{"cross-spawn":"^7.0.3"}}],["gatsby-remark-prismjs@<3.3.28",{dependencies:{lodash:"^4"}}],["gatsby-plugin-favicon@*",{peerDependencies:{webpack:"*"}}],["gatsby-plugin-sharp@<=4.6.0-next.3",{dependencies:{debug:"^4.3.1"}}],["gatsby-react-router-scroll@<=5.6.0-next.0",{dependencies:{"prop-types":"^15.7.2"}}],["@rebass/forms@*",{dependencies:{"@styled-system/should-forward-prop":"^5.0.0"},peerDependencies:{react:"^16.8.6"}}],["rebass@*",{peerDependencies:{react:"^16.8.6"}}],["@ant-design/react-slick@<=0.28.3",{peerDependencies:{react:">=16.0.0"}}],["mqtt@<4.2.7",{dependencies:{duplexify:"^4.1.1"}}],["vue-cli-plugin-vuetify@<=2.0.3",{dependencies:{semver:"^6.3.0"},peerDependenciesMeta:{"sass-loader":Qt,"vuetify-loader":Qt}}],["vue-cli-plugin-vuetify@<=2.0.4",{dependencies:{"null-loader":"^3.0.0"}}],["vue-cli-plugin-vuetify@>=2.4.3",{peerDependencies:{vue:"*"}}],["@vuetify/cli-plugin-utils@<=0.0.4",{dependencies:{semver:"^6.3.0"},peerDependenciesMeta:{"sass-loader":Qt}}],["@vue/cli-plugin-typescript@<=5.0.0-alpha.0",{dependencies:{"babel-loader":"^8.1.0"}}],["@vue/cli-plugin-typescript@<=5.0.0-beta.0",{dependencies:{"@babel/core":"^7.12.16"},peerDependencies:{"vue-template-compiler":"^2.0.0"},peerDependenciesMeta:{"vue-template-compiler":Qt}}],["cordova-ios@<=6.3.0",{dependencies:{underscore:"^1.9.2"}}],["cordova-lib@<=10.0.1",{dependencies:{underscore:"^1.9.2"}}],["git-node-fs@*",{peerDependencies:{"js-git":"^0.7.8"},peerDependenciesMeta:{"js-git":Qt}}],["consolidate@<0.16.0",{peerDependencies:{mustache:"^3.0.0"},peerDependenciesMeta:{mustache:Qt}}],["consolidate@<=0.16.0",{peerDependencies:{velocityjs:"^2.0.1",tinyliquid:"^0.2.34","liquid-node":"^3.0.1",jade:"^1.11.0","then-jade":"*",dust:"^0.3.0","dustjs-helpers":"^1.7.4","dustjs-linkedin":"^2.7.5",swig:"^1.4.2","swig-templates":"^2.0.3","razor-tmpl":"^1.3.1",atpl:">=0.7.6",liquor:"^0.0.5",twig:"^1.15.2",ejs:"^3.1.5",eco:"^1.1.0-rc-3",jazz:"^0.0.18",jqtpl:"~1.1.0",hamljs:"^0.6.2",hamlet:"^0.3.3",whiskers:"^0.4.0","haml-coffee":"^1.14.1","hogan.js":"^3.0.2",templayed:">=0.2.3",handlebars:"^4.7.6",underscore:"^1.11.0",lodash:"^4.17.20",pug:"^3.0.0","then-pug":"*",qejs:"^3.0.5",walrus:"^0.10.1",mustache:"^4.0.1",just:"^0.1.8",ect:"^0.5.9",mote:"^0.2.0",toffee:"^0.3.6",dot:"^1.1.3","bracket-template":"^1.1.5",ractive:"^1.3.12",nunjucks:"^3.2.2",htmling:"^0.0.8","babel-core":"^6.26.3",plates:"~0.4.11","react-dom":"^16.13.1",react:"^16.13.1","arc-templates":"^0.5.3",vash:"^0.13.0",slm:"^2.0.0",marko:"^3.14.4",teacup:"^2.0.0","coffee-script":"^1.12.7",squirrelly:"^5.1.0",twing:"^5.0.2"},peerDependenciesMeta:{velocityjs:Qt,tinyliquid:Qt,"liquid-node":Qt,jade:Qt,"then-jade":Qt,dust:Qt,"dustjs-helpers":Qt,"dustjs-linkedin":Qt,swig:Qt,"swig-templates":Qt,"razor-tmpl":Qt,atpl:Qt,liquor:Qt,twig:Qt,ejs:Qt,eco:Qt,jazz:Qt,jqtpl:Qt,hamljs:Qt,hamlet:Qt,whiskers:Qt,"haml-coffee":Qt,"hogan.js":Qt,templayed:Qt,handlebars:Qt,underscore:Qt,lodash:Qt,pug:Qt,"then-pug":Qt,qejs:Qt,walrus:Qt,mustache:Qt,just:Qt,ect:Qt,mote:Qt,toffee:Qt,dot:Qt,"bracket-template":Qt,ractive:Qt,nunjucks:Qt,htmling:Qt,"babel-core":Qt,plates:Qt,"react-dom":Qt,react:Qt,"arc-templates":Qt,vash:Qt,slm:Qt,marko:Qt,teacup:Qt,"coffee-script":Qt,squirrelly:Qt,twing:Qt}}],["vue-loader@<=16.3.3",{peerDependencies:{"@vue/compiler-sfc":"^3.0.8",webpack:"^4.1.0 || ^5.0.0-0"},peerDependenciesMeta:{"@vue/compiler-sfc":Qt}}],["vue-loader@^16.7.0",{peerDependencies:{"@vue/compiler-sfc":"^3.0.8",vue:"^3.2.13"},peerDependenciesMeta:{"@vue/compiler-sfc":Qt,vue:Qt}}],["scss-parser@<=1.0.5",{dependencies:{lodash:"^4.17.21"}}],["query-ast@<1.0.5",{dependencies:{lodash:"^4.17.21"}}],["redux-thunk@<=2.3.0",{peerDependencies:{redux:"^4.0.0"}}],["skypack@<=0.3.2",{dependencies:{tar:"^6.1.0"}}],["@npmcli/metavuln-calculator@<2.0.0",{dependencies:{"json-parse-even-better-errors":"^2.3.1"}}],["bin-links@<2.3.0",{dependencies:{"mkdirp-infer-owner":"^1.0.2"}}],["rollup-plugin-polyfill-node@<=0.8.0",{peerDependencies:{rollup:"^1.20.0 || ^2.0.0"}}],["snowpack@<3.8.6",{dependencies:{"magic-string":"^0.25.7"}}],["elm-webpack-loader@*",{dependencies:{temp:"^0.9.4"}}],["winston-transport@<=4.4.0",{dependencies:{logform:"^2.2.0"}}],["jest-vue-preprocessor@*",{dependencies:{"@babel/core":"7.8.7","@babel/template":"7.8.6"},peerDependencies:{pug:"^2.0.4"},peerDependenciesMeta:{pug:Qt}}],["redux-persist@*",{peerDependencies:{react:">=16"},peerDependenciesMeta:{react:Qt}}],["sodium@>=3",{dependencies:{"node-gyp":"^3.8.0"}}],["babel-plugin-graphql-tag@<=3.1.0",{peerDependencies:{graphql:"^14.0.0 || ^15.0.0"}}],["@playwright/test@<=1.14.1",{dependencies:{"jest-matcher-utils":"^26.4.2"}}],...["babel-plugin-remove-graphql-queries@<3.14.0-next.1","babel-preset-gatsby-package@<1.14.0-next.1","create-gatsby@<1.14.0-next.1","gatsby-admin@<0.24.0-next.1","gatsby-cli@<3.14.0-next.1","gatsby-core-utils@<2.14.0-next.1","gatsby-design-tokens@<3.14.0-next.1","gatsby-legacy-polyfills@<1.14.0-next.1","gatsby-plugin-benchmark-reporting@<1.14.0-next.1","gatsby-plugin-graphql-config@<0.23.0-next.1","gatsby-plugin-image@<1.14.0-next.1","gatsby-plugin-mdx@<2.14.0-next.1","gatsby-plugin-netlify-cms@<5.14.0-next.1","gatsby-plugin-no-sourcemaps@<3.14.0-next.1","gatsby-plugin-page-creator@<3.14.0-next.1","gatsby-plugin-preact@<5.14.0-next.1","gatsby-plugin-preload-fonts@<2.14.0-next.1","gatsby-plugin-schema-snapshot@<2.14.0-next.1","gatsby-plugin-styletron@<6.14.0-next.1","gatsby-plugin-subfont@<3.14.0-next.1","gatsby-plugin-utils@<1.14.0-next.1","gatsby-recipes@<0.25.0-next.1","gatsby-source-shopify@<5.6.0-next.1","gatsby-source-wikipedia@<3.14.0-next.1","gatsby-transformer-screenshot@<3.14.0-next.1","gatsby-worker@<0.5.0-next.1"].map(t=>[t,{dependencies:{"@babel/runtime":"^7.14.8"}}]),["gatsby-core-utils@<2.14.0-next.1",{dependencies:{got:"8.3.2"}}],["gatsby-plugin-gatsby-cloud@<=3.1.0-next.0",{dependencies:{"gatsby-core-utils":"^2.13.0-next.0"}}],["gatsby-plugin-gatsby-cloud@<=3.2.0-next.1",{peerDependencies:{webpack:"*"}}],["babel-plugin-remove-graphql-queries@<=3.14.0-next.1",{dependencies:{"gatsby-core-utils":"^2.8.0-next.1"}}],["gatsby-plugin-netlify@3.13.0-next.1",{dependencies:{"gatsby-core-utils":"^2.13.0-next.0"}}],["clipanion-v3-codemod@<=0.2.0",{peerDependencies:{jscodeshift:"^0.11.0"}}],["react-live@*",{peerDependencies:{"react-dom":"*",react:"*"}}],["webpack@<4.44.1",{peerDependenciesMeta:{"webpack-cli":Qt,"webpack-command":Qt}}],["webpack@<5.0.0-beta.23",{peerDependenciesMeta:{"webpack-cli":Qt}}],["webpack-dev-server@<3.10.2",{peerDependenciesMeta:{"webpack-cli":Qt}}],["@docusaurus/responsive-loader@<1.5.0",{peerDependenciesMeta:{sharp:Qt,jimp:Qt}}],["eslint-module-utils@*",{peerDependenciesMeta:{"eslint-import-resolver-node":Qt,"eslint-import-resolver-typescript":Qt,"eslint-import-resolver-webpack":Qt,"@typescript-eslint/parser":Qt}}],["eslint-plugin-import@*",{peerDependenciesMeta:{"@typescript-eslint/parser":Qt}}],["critters-webpack-plugin@<3.0.2",{peerDependenciesMeta:{"html-webpack-plugin":Qt}}],["terser@<=5.10.0",{dependencies:{acorn:"^8.5.0"}}],["babel-preset-react-app@10.0.x <10.0.2",{dependencies:{"@babel/plugin-proposal-private-property-in-object":"^7.16.7"}}],["eslint-config-react-app@*",{peerDependenciesMeta:{typescript:Qt}}],["@vue/eslint-config-typescript@<11.0.0",{peerDependenciesMeta:{typescript:Qt}}],["unplugin-vue2-script-setup@<0.9.1",{peerDependencies:{"@vue/composition-api":"^1.4.3","@vue/runtime-dom":"^3.2.26"}}],["@cypress/snapshot@*",{dependencies:{debug:"^3.2.7"}}],["auto-relay@<=0.14.0",{peerDependencies:{"reflect-metadata":"^0.1.13"}}],["vue-template-babel-compiler@<1.2.0",{peerDependencies:{"vue-template-compiler":"^2.6.0"}}],["@parcel/transformer-image@<2.5.0",{peerDependencies:{"@parcel/core":"*"}}],["@parcel/transformer-js@<2.5.0",{peerDependencies:{"@parcel/core":"*"}}],["parcel@*",{peerDependenciesMeta:{"@parcel/core":Qt}}],["react-scripts@*",{peerDependencies:{eslint:"*"}}],["focus-trap-react@^8.0.0",{dependencies:{tabbable:"^5.3.2"}}],["react-rnd@<10.3.7",{peerDependencies:{react:">=16.3.0","react-dom":">=16.3.0"}}],["connect-mongo@<5.0.0",{peerDependencies:{"express-session":"^1.17.1"}}],["vue-i18n@<9",{peerDependencies:{vue:"^2"}}],["vue-router@<4",{peerDependencies:{vue:"^2"}}],["unified@<10",{dependencies:{"@types/unist":"^2.0.0"}}],["react-github-btn@<=1.3.0",{peerDependencies:{react:">=16.3.0"}}],["react-dev-utils@*",{peerDependencies:{typescript:">=2.7",webpack:">=4"},peerDependenciesMeta:{typescript:Qt}}],["@asyncapi/react-component@<=1.0.0-next.39",{peerDependencies:{react:">=16.8.0","react-dom":">=16.8.0"}}],["xo@*",{peerDependencies:{webpack:">=1.11.0"},peerDependenciesMeta:{webpack:Qt}}],["babel-plugin-remove-graphql-queries@<=4.20.0-next.0",{dependencies:{"@babel/types":"^7.15.4"}}],["gatsby-plugin-page-creator@<=4.20.0-next.1",{dependencies:{"fs-extra":"^10.1.0"}}],["gatsby-plugin-utils@<=3.14.0-next.1",{dependencies:{fastq:"^1.13.0"},peerDependencies:{graphql:"^15.0.0"}}],["gatsby-plugin-mdx@<3.1.0-next.1",{dependencies:{mkdirp:"^1.0.4"}}],["gatsby-plugin-mdx@^2",{peerDependencies:{gatsby:"^3.0.0-next"}}],["fdir@<=5.2.0",{peerDependencies:{picomatch:"2.x"},peerDependenciesMeta:{picomatch:Qt}}],["babel-plugin-transform-typescript-metadata@<=0.3.2",{peerDependencies:{"@babel/core":"^7","@babel/traverse":"^7"},peerDependenciesMeta:{"@babel/traverse":Qt}}],["graphql-compose@>=9.0.10",{peerDependencies:{graphql:"^14.2.0 || ^15.0.0 || ^16.0.0"}}],["vite-plugin-vuetify@<=1.0.2",{peerDependencies:{vue:"^3.0.0"}}],["webpack-plugin-vuetify@<=2.0.1",{peerDependencies:{vue:"^3.2.6"}}],["eslint-import-resolver-vite@<2.0.1",{dependencies:{debug:"^4.3.4",resolve:"^1.22.8"}}],["notistack@^3.0.0",{dependencies:{csstype:"^3.0.10"}}],["@fastify/type-provider-typebox@^5.0.0",{peerDependencies:{fastify:"^5.0.0"}}],["@fastify/type-provider-typebox@^4.0.0",{peerDependencies:{fastify:"^4.0.0"}}]];var Iq;function Zye(){return typeof Iq>"u"&&(Iq=Ie("zlib").brotliDecompressSync(Buffer.from("G7weAByFTVk3Vs7UfHhq4yykgEM7pbW7TI43SG2S5tvGrwHBAzdz+s/npQ6tgEvobvxisrPIadkXeUAJotBn5bDZ5kAhcRqsIHe3F75Walet5hNalwgFDtxb0BiDUjiUQkjG0yW2hto9HPgiCkm316d6bC0kST72YN7D7rfkhCE9x4J0XwB0yavalxpUu2t9xszHrmtwalOxT7VslsxWcB1qpqZwERUra4psWhTV8BgwWeizurec82Caf1ABL11YMfbf8FJ9JBceZOkgmvrQPbC9DUldX/yMbmX06UQluCEjSwUoyO+EZPIjofr+/oAZUck2enraRD+oWLlnlYnj8xB+gwSo9lmmks4fXv574qSqcWA6z21uYkzMu3EWj+K23RxeQlLqiE35/rC8GcS4CGkKHKKq+zAIQwD9iRDNfiAqueLLpicFFrNsAI4zeTD/eO9MHcnRa5m8UT+M2+V+AkFST4BlKneiAQRSdST8KEAIyFlULt6wa9EBd0Ds28VmpaxquJdVt+nwdEs5xUskI13OVtFyY0UrQIRAlCuvvWivvlSKQfTO+2Q8OyUR1W5RvetaPz4jD27hdtwHFFA1Ptx6Ee/t2cY2rg2G46M1pNDRf2pWhvpy8pqMnuI3++4OF3+7OFIWXGjh+o7Nr2jNvbiYcQdQS1h903/jVFgOpA0yJ78z+x759bFA0rq+6aY5qPB4FzS3oYoLupDUhD9nDz6F6H7hpnlMf18KNKDu4IKjTWwrAnY6MFQw1W6ymOALHlFyCZmQhldg1MQHaMVVQTVgDC60TfaBqG++Y8PEoFhN/PBTZT175KNP/BlHDYGOOBmnBdzqJKplZ/ljiVG0ZBzfqeBRrrUkn6rA54462SgiliKoYVnbeptMdXNfAuaupIEi0bApF10TlgHfmEJAPUVidRVFyDupSem5po5vErPqWKhKbUIp0LozpYsIKK57dM/HKr+nguF+7924IIWMICkQ8JUigs9D+W+c4LnNoRtPPKNRUiCYmP+Jfo2lfKCKw8qpraEeWU3uiNRO6zcyKQoXPR5htmzzLznke7b4YbXW3I1lIRzmgG02Udb58U+7TpwyN7XymCgH+wuPDthZVQvRZuEP+SnLtMicz9m5zASWOBiAcLmkuFlTKuHspSIhCBD0yUPKcxu81A+4YD78rA2vtwsUEday9WNyrShyrl60rWmA+SmbYZkQOwFJWArxRYYc5jGhA5ikxYw1rx3ei4NmeX/lKiwpZ9Ln1tV2Ae7sArvxuVLbJjqJRjW1vFXAyHpvLG+8MJ6T2Ubx5M2KDa2SN6vuIGxJ9WQM9Mk3Q7aCNiZONXllhqq24DmoLbQfW2rYWsOgHWjtOmIQMyMKdiHZDjoyIq5+U700nZ6odJAoYXPQBvFNiQ78d5jaXliBqLTJEqUCwi+LiH2mx92EmNKDsJL74Z613+3lf20pxkV1+erOrjj8pW00vsPaahKUM+05ssd5uwM7K482KWEf3TCwlg/o3e5ngto7qSMz7YteIgCsF1UOcsLk7F7MxWbvrPMY473ew0G+noVL8EPbkmEMftMSeL6HFub/zy+2JQ==","base64")).toString()),Iq}var Cq;function $ye(){return typeof Cq>"u"&&(Cq=Ie("zlib").brotliDecompressSync(Buffer.from("G8MSIIzURnVBnObTcvb3XE6v2S9Qgc2K801Oa5otNKEtK8BINZNcaQHy+9/vf/WXBimwutXC33P2DPc64pps5rz7NGGWaOKNSPL4Y2KRE8twut2lFOIN+OXPtRmPMRhMTILib2bEQx43az2I5d3YS8Roa5UZpF/ujHb3Djd3GDvYUfvFYSUQ39vb2cmifp/rgB4J/65JK3wRBTvMBoNBmn3mbXC63/gbBkW/2IRPri0O8bcsRBsmarF328pAln04nyJFkwUAvNu934supAqLtyerZZpJ8I8suJHhf/ocMV+scKwa8NOiDKIPXw6Ex/EEZD6TEGaW8N5zvNHYF10l6Lfooj7D5W2k3dgvQSbp2Wv8TGOayS978gxlOLVjTGXs66ozewbrjwElLtyrYNnWTfzzdEutgROUFPVMhnMoy8EjJLLlWwIEoySxliim9kYW30JUHiPVyjt0iAw/ZpPmCbUCltYPnq6ZNblIKhTNhqS/oqC9iya5sGKZTOVsTEg34n92uZTf2iPpcZih8rPW8CzA+adIGmyCPcKdLMsBLShd+zuEbTrqpwuh+DLmracZcjPC5Sdf5odDAhKpFuOsQS67RT+1VgWWygSv3YwxDnylc04/PYuaMeIzhBkLrvs7e/OUzRTF56MmfY6rI63QtEjEQzq637zQqJ39nNhu3NmoRRhW/086bHGBUtx0PE0j3aEGvkdh9WJC8y8j8mqqke9/dQ5la+Q3ba4RlhvTbnfQhPDDab3tUifkjKuOsp13mXEmO00Mu88F/M67R7LXfoFDFLNtgCSWjWX+3Jn1371pJTK9xPBiMJafvDjtFyAzu8rxeQ0TKMQXNPs5xxiBOd+BRJP8KP88XPtJIbZKh/cdW8KvBUkpqKpGoiIaA32c3/JnQr4efXt85mXvidOvn/eU3Pase1typLYBalJ14mCso9h79nuMOuCa/kZAOkJHmTjP5RM2WNoPasZUAnT1TAE/NH25hUxcQv6hQWR/m1PKk4ooXMcM4SR1iYU3fUohvqk4RY2hbmTVVIXv6TvqO+0doOjgeVFAcom+RlwJQmOVH7pr1Q9LoJT6n1DeQEB+NHygsATbIwTcOKZlJsY8G4+suX1uQLjUWwLjjs0mvSvZcLTpIGAekeR7GCgl8eo3ndAqEe2XCav4huliHjdbIPBsGJuPX7lrO9HX1UbXRH5opOe1x6JsOSgHZR+EaxuXVhpLLxm6jk1LJtZfHSc6BKPun3CpYYVMJGwEUyk8MTGG0XL5MfEwaXpnc9TKnBmlGn6nHiGREc3ysn47XIBDzA+YvFdjZzVIEDcKGpS6PbUJehFRjEne8D0lVU1XuRtlgszq6pTNlQ/3MzNOEgCWPyTct22V2mEi2krizn5VDo9B19/X2DB3hCGRMM7ONbtnAcIx/OWB1u5uPbW1gsH8irXxT/IzG0PoXWYjhbMsH3KTuoOl5o17PulcgvsfTSnKFM354GWI8luqZnrswWjiXy3G+Vbyo1KMopFmmvBwNELgaS8z8dNZchx/Cl/xjddxhMcyqtzFyONb2Zdu90NkI8pAeufe7YlXrp53v8Dj/l8vWeVspRKBGXScBBPI/HinSTGmLDOGGOCIyH0JFdOZx0gWsacNlQLJMIrBhqRxXxHF/5pseWwejlAAvZ3klZSDSYY8mkToaWejXhgNomeGtx1DTLEUFMRkgF5yFB22WYdJnaWN14r1YJj81hGi45+jrADS5nYRhCiSlCJJ1nL8pYX+HDSMhdTEWyRcgHVp/IsUIZYMfT+YYncUQPgcxNGCHfZ88vDdrcUuaGIl6zhAsiaq7R5dfqrqXH/JcBhfjT8D0azayIyEz75Nxp6YkcyDxlJq3EXnJUpqDohJJOysL1t1uNiHESlvsxPb5cpbW0+ICZqJmUZus1BMW0F5IVBODLIo2zHHjA0=","base64")).toString()),Cq}var wq;function eEe(){return typeof wq>"u"&&(wq=Ie("zlib").brotliDecompressSync(Buffer.from("m9XmPqMRsZ7bFo1U5CxexdgYepcdMsrcAbbqv7/rCXGM7SZhmJ2jPScITf1tA+qxuDFE8KC9mQaCs84ftss/pB0UrlDfSS52Q7rXyYIcHbrGG2egYMqC8FFfnNfZVLU+4ZieJEVLu1qxY0MYkbD8opX7TYstjKzqxwBObq8HUIQwogljOgs72xyCrxj0q79cf/hN2Ys/0fU6gkRgxFedikACuQLS4lvO/N5NpZ85m+BdO3c5VplDLMcfEDt6umRCbfM16uxnqUKPvPFg/qtuzzId3SjAxZFoZRqK3pdtWt/C+VU6+zuX09NsoBs3MwobpU1yyoXZnzA1EmiMRS5GfJeLxV51/jSXrfgTWr1af9hwKvqCfSVHiQuk+uO/N16Cror2c1QlthM7WkS/86azhK3b47PG6f5TAJVtrK7g+zlR2boyKBV+QkdOXcfBDrI8yCciS3LktLb+d3gopE3R1QYFN1QWdQtrso2qK3+OTVYpTdPAfICTe9//3y/1+6mixIob4kfOI1WT3DxyD2ZuR06a6RPOPlftc/bZeqWqUtoqSetJlgP0AOBsOOeWqkpKJDtgP25CmIz+ZAo8+zwb3wI5ZD/0a7Qb7Q8Ag8HkWzhVQqzLFksA/nKSsR6hEu4tymzAQcZUDV4D2f17NbNSreHMVG0D1Knfa5n//prG6IzFVH7GSdEZn+1eEohVH5hmz6wxnj0biDxnMlq0fHQ2v7ogu8tEBnHaJICmVgLINf+jr4b/AVtDfPSZWelMen+u+pT60nu+9LrK0z0L/oyvC+kDtsi13AdC/i6pd29uB/1alOsA0Kc6N0wICwzbHkBQGJ94pBZ5TyKj7lzzUQ5CYn3Xp/cLhrJ2GpBakWmkymfeKcX2Vy2QEDcIxnju2369rf+l+H7E96GzyVs0gyDzUD0ipfKdmd7LN80sxjSiau/0PX2e7EMt4hNqThHEad9B1L44EDU1ZyFL+QJ0n1v7McxqupfO9zYGEBGJ0XxHdZmWuNKcV+0WJmzGd4y1qu3RfbunEBAQgZyBUWwjoXAwxk2XVRjBAy1jWcGsnb/Tu2oRKUbqGxHjFxUihoreyXW2M2ZnxkQYPfCorcVYq7rnrfuUV1ZYBNakboTPj+b+PLaIyFVsA5nmcP8ZS23WpTvTnSog5wfhixjwbRCqUZs5CmhOL9EgGmgj/26ysZ0jCMvtwDK2F7UktN2QnwoB1S1oLmpPmOrFf/CT8ITb/UkMLLqMjdVY/y/EH/MtrH9VkMaxM7mf8v/TkuD1ov5CqEgw9xvc/+8UXQ/+Idb2isH35w98+skf/i3b72L4ElozP8Dyc9wbdJcY70N/9F9PVz4uSI/nhcrSt21q/fpyf6UbWyso4Ds08/rSPGAcAJs8sBMCYualxyZxlLqfQnp9jYxdy/TQVs6vYmnTgEERAfmtB2No5xf8eqN4yCWgmnR91NQZQ4CmYCqijiU983mMTgUPedf8L8/XiCu9jbsDMIARuL0a0MZlq7lU2nxB8T+N/F7EFutvEuWhxf3XFlS0KcKMiAbpPy3gv/6r+NIQcVkdlqicBgiYOnzr6FjwJVz+QQxpM+uMAIW4F13oWQzNh95KZlI9LOFocgrLUo8g+i+ZNTor6ypk+7O/PlsJ9WsFhRgnLuNv5P2Isk25gqT6i2tMopOL1+RQcnRBuKZ06E8Ri4/BOrY/bQ4GAZPE+LXKsS5jTYjEl5jHNgnm+kjV9trqJ4C9pcDVxTWux8uovsXQUEYh9BP+NR07OqmcjOsakIEI/xofJioScCLW09tzJAVwZwgbQtVnkX3x8H1sI2y8Hs4AiQYfXRNklTmb9mn9RgbJl2yf19aSzCGZqFq79dXW791Na6an1ydMUb/LNp5HdEZkkmTAdP7EPMC563MSh6zxa+Bz5hMDuNq43JYIRJRIWCuNWvM1xTjf8XaHnVPKElBLyFDMJyWiSAElJ0FJVA++8CIBc8ItAWrxhecW+tOoGq4yReF6Dcz615ifhRWLpIOaf8WTs3zUcjEBS1JEXbIByQhm6+oAoTb3QPkok35qz9L2c/mp5WEuCJgerL5QCxMXUWHBJ80t+LevvZ65pBkFa72ITFw4oGQ05TynQJyDjU1AqBylBAdTE9uIflWo0b+xSUCJ9Ty3GlCggfasdT0PX/ue3w16GUfU+QVQddTm9XiY2Bckz2tKt2il7oUIGBRa7Ft5qJfrRIK3mVs9QsDo9higyTz0N9jmILeRhROdecjV44DDZzYnJNryISvfdIq2x4c2/8e2UXrlRm303TE6kxkQ/0kylxgtsQimZ/nb6jUaggIXXN+F2vyIqMGIuJXQR8yzdFIHknqeWFDgsdvcftmkZyWojcZc+ZFY4rua8nU3XuMNchfTDpBbrjMXsJGonJ+vKX0sZbNcoakrr9c9i+bj6uf6f4yNDdaiXLRhJrlh5zmfbkOGQkosfTqWYgpEKdYx2Kxfb+ZDz4Ufteybj63LzVc7oklSvXHh5Nab4+b8DeoXZihVLRZRCBJuj0J6zk3PtbkjaEH3sD3j6hHhwmufk+pBoGYd9qCJEFL21AmLzzHHktN9jW7GSpe1p91X10Bm5/Dhxo3BNex+EtiAFD3dTK0NcvT58F0IFIQIhgLP6s1MX8wofvtnPX1PQ/bLAwNP+ulKiokjXruRYKzTErNjFrvX5n6QD7oiRbOs3OQUswDgOxzcd+WwGZH1ONZJLEKk2T4VGPrrdkN9ncxP/oQ8UFvRbI7zGVrpNjlniCHT6nYmp7SlDcZ1XmS7tm9CXTMumh89LnaNuF3/wPVa/NLSE195Ntstwz1V2ZLc/sULMGaL4gdF3src9sR1Fh33/xiS3qOrJQlLpy2luR0/y+0q0RnVBBBe4yi4ueiNOdNAq/pR8JehYiEiu7YVJJcGBNBHlCOREQviO39dwxTxdulwW+UOO+OrXOskQ/csaLPIKxUOUHktlUtch/SkuaV5QD2G4vweAaCoSxMZ8k9jagIRR/irArsMUBBkvwQBZj1NYclQ1WtdeoYsd38CObL/DJksETohDEy6ZCixViSEPvNKiV1SSCwIiVk0dPGwTZxeNwPoA0BDhYNc4tIkej3DcTHVTS8W1vYFlURRUS4k2naQ5xI0fseTRBHJQ3WJ6Tn45afc9k9VffnLeTH+Kdd9X9Rnont4E39i8pr21YM+umrbIBTB8Ex2jNapeDYMPaeXACP6jpZnFy8NEyG2AF+Ega5vkvKIWjidXnkItArCkmeU63Fx+eg8KiP95JfLbUQus2hJTKPeGTz9b9A0TJtnTVcdJW15L/+3ZIOQ3jeoFsEuB9IGzxFY52ntO1vJvNdPQMJhXkvTNcRYz7Qz6l09rNUNGbfVNOW7tQgzdp42/0sZtnFW0+64nFJ127Niq3QLT8vwHYw3kOplK43u3yllVjU+RYv76vu3JMghXWGsSB0u3ESlir8CjF5ZIflzQoMn0xbP3qWknhPYHTAfu11TcndM/gV+npAK5/yKkwjnzWs5UXGXJHwAFo1FU99jtfiDBlqk9Xmq1YKsy7YkB5nOmw6dy9mjCqYT72Nz9S4+BsTCObdH/e/YZR3MzUt/j/sjQMujqJNOqABq9wAJCDwn/vwSbELgikVGYviA89VqCQjLBkWsMBf7qNjRT3hPXMbT+DM+fsTUEgPlFV5oq2qzdgZ6uAb0yK/szd/zKqTdSC0GlgQ//otU9TAFEtm4moY7QTBAIb2YdPBQAqhW1LevpeqAvf9tku0fT+IfpA8fDsqAOAQxGbPa0YLgAOIZRFlh3WHrFyBDcFLdrSJP+9Ikfv1V16ukcQt9i8sBbU/+m0SAUsjdTq6mtQfoeI7xPWpsP+1vTo73Rz8VnYLmgxaDWgOuNmD8+vxzpyCIC1upRk0+Wd7Z0smljU7G9IdJYlY5vyGTyzRkkN88RMEm9OKFJ4IHwBxzcQtMNeMUwwUATphdaafYwiPK8NptzFLY0dUIAFj2UVoHzUBmmTP1mWCmKvvesqnrG3hj+FHkfjO3nN+MaWXgorgAAA6K9IXTUD1+uwaqHXsEALRgD82K6GVuzjQznaC89QI2B34wNf1dPIwydDO38xCsAKCdf19/ePn1xejxPZgLmzLlTLvloYWMde1luC66/CFwUdwGF5iJ4QIAM5jvbl94r6EYr52H2W12SlcjAHBSzoVjusrp7UZh18Z/J+vwjQccSS/JBNE2b1adygAAyNgJ5P+bqz5+CPu24bqx6Gjcz84IAtVx2VEyBJTqrocOCI9I7r4vD7cz9L3AGZ6DBzEu36w6fQsAkN2IsmzCZWMxqbMTE75ymnyFiK09l327D2K9sywTANigkEkmLwTn4RqDiPxpy5HKA4aeYqbSoi0AUAKsGA5go3ZXjR0qpUsAoMWolyNxzyiIPZ+qsEM7QDgbHW9WJWwBADq5800tDEPPiPa6ialFj0uNAEDJEC4am4A/oPGPxmDmXdikl4cLKa8CgG7265rxY/wjtmbutfwJ6M9Mer8dKHyeZkalbAEA49jkE8MATNz+qKwsMOlGAEC+lkvGJh0ds/j5uNtg3tilTY+NTe/JnqF4N6uSDACAHKQP1Lht8vSzU7iEyzPjut2EPs/Y38IspIepXm+8s+bS2w8QPd+8ONuavlmV3gIAJLA8T+O2x6fBKOJyYweNq/YsVtd2SjETADgxiwkX4POo7fsmuHnc8rCP05hqlnABgBq023MivCisNnZRtK+sru0oXAIAK+fRHim5pkf85kL/YfPLQ/xReQkXAChjtR0XhfDJaiOHaB9ZXctR2AQARsyesDkUv0deoTWmffvT4f6SYAUA6+xXzrX3Smi6X8zthH22b/w19LM0XlWqr0rjAgAWs1Wq4T6AhPsAVGoEAAa5PpwVKjiHWlfJ2TZJf63FjF8SUG6KBOOL9A4PW3qOHE295pQyfVPIvxcJeU+CKduBk6Q+a2BAVtKhf4QnHrHLFpj6sNDUDvhCfNPmtn4pdDSUkHE1wPPrF1UvkQS/L1S52Zv0Sb/r9YK+jx51oWU+i39Owb1p4MDw3LcwvjpMvtDXPEWBlLcw4DNpOOC8f11nKez61/hc4txssbudIo5lL+aszAI1EiiSfkCetqOyBs4trCbou3jqJZ4diL4zvDnDBRgP+086X66Tvj3JOY1rJwmj/sJrubDrVb32PWhOs6BN+sJXQ+6nOZJTgPRg4PWz8sp/wWI3wsGBQoSU6tr0dWOkrwhDNCN5mfGAM5vfnawcoCdm2CdzIN0r72XbbDWqjom1cMjYh229sPnvzWLZAaSiQR3bSL1XjCwFH1wa4ZmmLeiaD4xutxAZfzu0FwMUkXTsvb7SX7TLM4zwjGg+HbjiaRWI92lgwaxTyKgiXbnThL9j7uBDihzuMULvXXes0e9x7PwRK+6mBLGD9z7PAt7b7va1J2EHu/zZfZ6JPoQVd849MZCk3RJOxd5Nsxi+O0lUD4Pochlk5+4naG1j6yiVRKBPobLOad//hDECeD1ORiB9M37JsSxMC6yAkKEdy7S1aRmXRGrLECneqByM8iQ8x6d71F1uhkYUi3WEjh/A9Yw//HCidh7pl7XD8vEkuN/f7XQ3+fhmSfR/9fHkNcRp4qCD13IGIBIAsQXtoDUnASJc+5H5f7YWufNDdZ3SiHJqVvKw8K1RNB/4mJi3YzQP47nmN2cw2BH4yKk+zk7wcLx2bVzeS773YW/7nMg8DMlWZGeYPJ8lYLzOnN4o/0fk9Fb9upq1yXbRyN7iDSRnOnj+kn3vLjHbn3NmA2tRwcfVd/KHGxPybUwcg9e742hY/XBtEgCQYe9Qh8t8fte6aEo1Lt7a9rryutsDxLxo0o9/lhdL/GMs9n3cCxZiuv3as0lchJm9dQGckDBOT/R+y2ft/W/eswB4NFnsqcrBTerQmx0BTPclttiZPF+ctHerFc2RW9MJzpuGOShqyTLCNsCjhPV3EtMF8nVQf2TL6GzI6EphQEjQgG6JrtMu/0zWg2e97o/uoTIf4ipUvVVM0KYey+VkMCWrFynVZh/hpTTXcm3+EV7yX7W6Ehrz8KON4P9MrENJx2msYomlnUT80OrH6Y1+KEfOWn8KyenbZuHQkjBZcDAx5+J64Aj6TSooLJw3anwLeZGOQeSSPXLe6dVY7MF7HhAl2HU9fwES3l2dLETAm5btht91AwjpdUoQghLn7RhAIRWFRVWJa2Jtc0Tm+dHRGiAvx6wG/OCGa7BsWuJ6U3LwfOzSY5qNsj3Qpt6+JyEhflEfl2YZ7jhjJ3y+3ehNh4IBG4eEmVuhYdlx/EQQvnVDqC5Lodj7NWEXjMFyT14tjF768alhticUJrdl3w6P7cKsF4rhxIKWxOSELDHpzaBPR0EgNZlKdZrSiJfPGaWK++nvRxwoo0gt4maZU1CAx33oq3e+NirCq8K514FHpLc0jbti5KzNlr3ttdqoSeYKrOsq+jS0w4q5Z2AMeYnbAgCra8oCHFF0wJ/PTdXUMVyIdTRhS8cJZVr5dTMliVhKm9/TZduaYLTA346l+ILCTo1es+CVq/f+2MU+XuX47AuupenBsoFCNMV/2ywHjCr2flEAWipfnI46tqmjq81ytF7IWoydKyHCSI4ew+k4+ATvUzq2buldaR6SAI4VKAMyMT7zkBkAMB00NLbwmtJqj2k7NAGAqHKufA41DAksWEk7A33esJTuBprShiAOZCMOdd72+E7b1umdzQCSOsdaB3BxZgCAIhUUSdbxYbW7MfnSRjQBAOeidlz5FgodFOhlNAn2jcFu6KmERUygbnHGMpnfdLZ+KTEVgF9WExaIcJy8hr/tp7Y+ofIvp0nKjrUMZqLMAMAsmaCWuxWW9dpVpoxoAgBXKtOVhyhPGCAhWFJty3Ija39F5udrAvbBC+QD+d2Qpx5Dhfh+FqLgzUW10AwAWChUQzuhruPOnJ3rUZXMdgmhZDvzdRCfX1UCN4/l/wPrk1X0qHN3KbpjTKBihdxy04nZgZFKr7EcDqvvSSpivzg7QGxmssgfLo5KZRV1TZtdbR+k3S/kYjTNfDUZyWrcFtxkiVhetaWfvcxumYBgVeSozNkvIgSbt+L/2Cl6TuiPToNFUi3gzvnWRxo0ES1a/Wjq0Zc47dikmBBXXE4/cj/BEnTUGU8vsXsssBsmrEbCzB27QqDQGPdcgFpmIb3VQSk9zfTyXFlADILp0V5qUnuHn2SAu8QszfXheW/UnD34sJXHTECWUYQhLc5QozwqlP1qnYO/j2pQmGU03C06s3d2EjlIdLNuy+Z0X9GIUUWCXDpwtAPYI/zXrF26ADyEpyyj5o5bn4GKoyNdkhskDGYenTTQ+fRqo0EL0yIqcAfyVOvo2jq3CjCRKOLgRzv8NZ30rd0sMLzpKrIwt866C8KrAes6AeYvDWFOdG2WjV8dNiG2wUyaYIU3T/cDo3COPFw8EPEFcIZAcCNE6BpH0CBPxefguDvpbTKPZF5TYE+uaLtxvaIUB3bIQI6/yK34JNzrQt1az5ucZEtXCMlBED4lW3rAfndm6l/kCGLzwMc1jaGqJo9VNR0VIO4dMQMAo+m4cpFwrKQXPzW3czk7Vehrc4bS6j+UCQBQhrljlDaOxR/+L+5R2jt6Tz+GWNGIJbKP1cd9mk9gzEk9hjdUxnNNvHTW4dOvtRS4MRoQDFpUwYuR+pe67JmTNfNtDqx7LG4zNLjh8a/7i6F+adgW4ci+DW1Ilf9ok+1zg/3+lfN6pK5X6QelSexeWGj2JnH1ym6sQa173zvfno297vUcHC6hAoTC/3enX+ej+9JNHu5RQubQD4++jHOK2fiK8Df3A4QC1LZSDmK46S0VdPvZ8VSJnWHbWlJDsshRGb3dyRkMr3d8VnqqBEcrMSKUyBqMsk6yUayfov2tM+rgwqxlrsiFu4pvawUNfFtcuWrc8FmGXzmz8Vn5LxfzeQoLfUX/JWNR9xC9tZZamjtBesX5eUAqtw7rpFfDcdbgXsMcsICLg6iqrNnoDTf4umgefPn5ZdXLAEaKmKr9K2jWq3EjfHsxMwBg48Ul4dwopQnV1GzvwQsXaQIAGfxz3b1L+LfNKAGAuxiMqmZyB+AYNU1XTRJXly88AYU39jt8cP2yet2jRRzcU6scgDEiEryUmuE0/9XcsZcfId18ZowZMT1Pn3IAxpBI9rrhhqfOkyl7L398ZNuIPH7ElH1o1LGcrV7PCOR1IzMAwAuoc0mYU0VR8SZmewtvuEATAGjx8Jyr7ndZRRabBAAakrqa1eFyutex5al/HR9+Pg/51BPSD406ljMQA8pRvJ9nBgCMQyre6J1RTDLuzPw1pAsbjcEeOqQ1rdTmu87PE3XTX6L5Gyznwp9PhH9fPkpGQ8UNREgtj619rgZb/3wPFNQVbHc/a4jvwl/8oBKYjqAA6N6ujHBoGb4ATrvhNBnDILjc0CJKnveWTCZsDPoCAtX87ot1zaqQIOzniFoY5+YhQw5B2c/phhnSAZA9ApFkx0IJ7sCLThlPpxnHyv9oR13WpgPR4gUqXIl2N4nXnTkJrp58Eu4njBlKzTOEZg8IxnUq8+sqOnQo9N2SE6jdRZ1z/fsQ3CJqNvCck7DRQdc3RveF/dc5mlOPI8T4uL+oz+Z8sJ9wZo/NELlDNct9N677yFvr2oYCQ3/83EfWnj06lnR27o268AYQhVTPo3RYYPpkhgyVUD50TQGcbIPBCGxagjGtFBjceJbYSX958r3v5q3JbgoA8LXamYl9ce+UOusgjorz1/LGw/LsWuxIqVZLUflBNNzqe8wfBnngUekITgge65Xj6xD8Ero1H/HAEgzxiww6j8ZB7I9hA4PQLxy2xTCSF3tJ/60ye1nRAiEhHZjEwgdaaD7HdmaDiTG4HD0ArtUhToud4pjcKlanIcEUD7j13JTtBA9u040VgeqfcMoXejWyk7YDcHR0TNJsYM2cyGylQEg654jKROckKeaXtByXo7DqAQhhd+e41CpRPIm6zoUBBU30L6veKGoHUvVujt12wrswKY0GCX7BAJ1ePs85euedVbtDdCFD6u6HVpjhIAJuyalS4D2EoUBc+OfKne64AHj8o92ql+v1XqI15bZv54pNU+xgh2zxoFup3vOQ40Jgk6wnrxfKqgVYJ8SCL5iRzYqxfYJEKQ6I4V7umobUg1tBdDZCI6wYso5GIsPj5aztuwBIib7SFoG3neHuUIkB0omw3HgYMqAVKWPKX3j0zEOeXOXa53uihs/cCwK2zTUdWfmdaBXGvP2ca3oubeEUEhTjUTjLD469sBTbSoNat4Q6NAHDoLn1d7TVHjJAmwfrggxygS3ojqv4siKiccTvzqizQ/sT37uxiPOJBH54kEryjipahqC4WYQ3Ztrduw39FZkaL80/Kl1M7mFa0VRxRoxS2hASYUpIdRLxT54CSsaACskZURcD6T7DueOjXevevtHYqtG2ZT+lHHVdNiMYIjJ4fu/nmbJp1zaOCONKPSKaP8J95Ije8V4Dnzyb3018HkdmaFbKBJDZMrXEB/VBy2mXVnq8WJSTK8CQuWPax3x8N3IdHtP+nKkRuXSj644Hnl38rAj9tk+2VVRuWRjNa1nsrvymeydN2VmUP4vo65rVvUozV8g+vFK0Pl3TTFjraGzjnpqnYj8fEn7y8xRGCb8o0PpJFDvkn5OOcISVLmQL98k0v89Y4snCvN8eEeM3lT34MjVzW2tBDx823AnRhLHF+wMcfn1USCfNH/y2+Nkmud//9f0xIbj11Zu5Zj4+4VjnVY/3brOKzwL+ejBmAOA47WPUljHF/2vcrorTjC9qauGcdjWqnl4Xqn61TABAfHiRvtpVT/BXt6udWv7G98iwegCujaC1eL1yhl59ATcUPRL3AaIOA+I5uupJcT1P8HWp2/hzT0Sgulz3jhhpRAGwRce+/k0LmNKMTfgx0HDnnYCoD4hwwcoVOwxDBCUhRKsQoCSRhCue2/9c9F4/djN/iU8vqQQAu2W7NleXuELigy7hrrH0ugYBzkBDFOm6hLH5gmTFDrY922J2jrjyFiDRWEKvovHJtvocMB+GdcfEc26nXAIxds31Zvyjgg9jDEkcu356cP45FQyWQ/2Xr9D3uuWTcP5rnCe2ZJ0E+rAzmSuB7q8l5kKexhJKIEgrqufzwt4z0Ma+6Z2Tc87Mxal5/108FsEkt5OMAUkkyPVYQvnEFI//BZi8mLGfYTCJKmKnPSOjj6PKKtrk9r4yTzXtIoLNfgCFXbO64O3y2dHOc0mB/cn4z5fkuA4VivPPReLcHVz8e0Cn05dLt14MyJdAU5yPV1oQSPcU194ylCH1I3Xt+oTMx7XGZgDuxpWddWvXNDuvgrl5OdL1SFnrVEM9U/0qfyz+6vo/VODmhzpDG/dFXZtJ7jTriHeSCKPhhLO5/uYBuSfw1POp6E8u60XdpKOROkyUcoWjqimnNyHhPDDdV1/7ND2Bh/7aiuxpFbYlYhwZNrk3v2ylTvyNsFmfuRontBwiqKx329Zob7jLYDIb9PrG+AWk4nN4QAF3naK32CroJjFK0dzBGBdbhqGvOwlO4Bqc2B+K8vMn9SgTYKOTXQpGthMF0aJQHsdrTiN+fG+eK6bKky6CiukeqBgoB0KYhl0ngc3MWhYQhR6ULDmmmrqvURCguRGH+xUW59GyJPI78e38CbKxEQpOnYlmZUheRl8+5Orw0KnDEZXpMdVzYEcr8V95gf54U3cS7adnQVQm9yAR5pkyblumE52RaVLbIouY4WxcNzoLJraAqsbN7CUaEyQRtqm83YVxgTXFBNPk2z9SfS/2mTSulgEfWUOYmQEfiAaWnX+P0ezKFz1BzO/T9SX4B8Sm7NUmDnbHI74izpe3Dq/k2jqvsxNBX7keI1eux798aA+Ee3pag6xpPDa7uIun6dXBDb9xrdpAFa1TYvlj/3iacVrXUYInG3OQv5lASKQr6Ok3CWTOFrkE3Ab4lFR8hbY0DZsgpiXw3Ic8YccFXomJeuZ+zNjq4CmlxYhcXQnrgtpWb2S+JXEp5JHh9APA4IjKN4hdm0qnHRzhSFfJCcOkg/RinGMzwtgNDahb4H/uNWjrIexsVRC9uYlMT3CCWCLeq12rSi3BlAQrnIAdFhL2INatBUy7ruc1TE+6eZ2XkZ/C6d6+CJrwouvF0ghjWDogxPbgxotmr56iGJoKnuwNF/VWHb037trPU+K8a9PCmGGWrqdiVkSOISAAc7D91xXG8Svq43DBvltxo/jeFylAbMWcCDXDm0rM6DbyRvFtLzAazwd/SPi1x5/NHyxHgX5VESDDn1tRHXzSlbjz2ulMvtv9Dp+Ic6KQZ3edNwa+9iZsx7kIwYF4aRfPuiAwhoYbkgvhVzlgwfF3Z5tX5KgmwkDs6AQdqyuZv1U3sFzdM7UxaJQ6JM5ELO+d+/k6PEylnYrwSOBlurpS2rECSHSp8S5Sbrm9jweZ44BxmkOBY4P5BmhH1PRRkCRcXYG91K0JRzOD/B1vQCcHf//8atBI/HuWuilLAbut+HwOMwBwqaIhe73RUkx4vCmUs4j6ALwz2cUa21NgLwszAYDj7hk5AvfEbG4HnKsavV0z2HZTPwBwNCiFQ3kIus/yxQ2assWZAi2zvyzAEU2C3XdnMwLHq7+vztaFd9UtqeZAqkKXkjoBs2vNdgByZS2cA1XNs70DCmO/0wQp1xWZZFWF8W3oy6uDaQnLF/YRxHk4rtJAAui5f4zymPhhpt+bgyGzSZdePfx3cSoXJIAuErW2pSJav7eSO0FL2bOd0eNgTenDatV0qcMQm4q085gBgJZgp6OlHCwNuT4pJjv46ZFji8t1ho8XaAIABIPsmTYL/HWV3harXQv7AQAWvtqIyuK3dJ+Cj9PGMb7K/JvB5xoGYzzTeucCQeXKMYa5Jh9EzhnyD3aGdQvU/FS1qMnjkPpyqtBQbX+HZgCANU1TteXcz9EMPZ0a78Xu1gxoX41fMf9Gx5SxOfgyF43WlePpTPS7KysCZeKjhxfH8OR2QZTGU8btjQNsDjEviJ5zZ659N/5Cs3tCTKjmg9XhwU2AieBC2CpJAc9MszqjvkvHbiHW4L7rMM9qMRXNBirYkwJvjoctYaKk80gNWxIUK2xDd1rykGGMhRq2glXBCIanrVbE4ctMSCncz7rDmN8J8+7xEr+37HpwPbbLV7DuIoUNODXiuNOYAYAdqqXg3NFSErZEqkops7NsF4dEt0pzJgBg3t6nyOT+ujWUO3o/HWboODheW/ZPjzH7Y2vJl5Vf1yz6cJxee134g1HHKtqNR06Yb1afnVoMAHh1fMz7KJmMuovLqpY/VRzDP+iqbrVar9VPSZxLCflzMZyzGDZ8juE3iuEfdIFWywg4UAxhvkt7H3Vz2Nmijfg10C3pDCGbW5HkGR033VTgXud+mVEqiPa0FRwBokdONicFMVWtN2cDyUBXkaaL5B06Dqt35stna5O88Hr68+Z+0vHQeOL7mZXCPby/RztHkz1eoTOcHLwcfGzDjP9lqtKlou5FzABAt+Kmy07cqDp8+QpF+lRyz702fCBvwQM5RRMAiMkiog3HhpH3/YCarpVzwsDVzQUBQNA83tWEAQVHZpGCKOs9UgWB0sS0CoJt+jEqKJxR4KigJF3udZC6mslAYLpqlIKwZZRLawYKHLe1OAacLM8+C5yT/b4tcDp1RVdidcVxOsa8Vfh2fiRZ4tPLrNuhQJAAyu8f42gdo2Z48/uSo/P29+J71n4oGiSAghLF0zoExPPe086JT6uNadoIQf+UfWOXtuWPNasWv/o8ZgCguhluxCuXg+UWd3uW2hGf5Yq3s0gTAMDia0wbFX5SKZfmYVwWGgQAHXyMEWXhV+k+Ar+tjd34iPkX4kOGQRqfp70XJHXkjm/sJ/ruOb4mSeuYnTfjCWFvoEcG4BwfnEtpFvRelrlGIum4+DYYBA7AtEQyHmxHxTHP/CVxmr/Sp7QXobUx4qP+rGJRXehvjg/uZD3fs2M5+cf7E5+fOPC8KOzGyYE0ZYwhuF0MBVh+MePAVk05a3djJn7kqrUyvLsOroqbM46Z+nM6JvdaGsEjVfwqoN2SfHc135EyJUq88XZEIX8I5nbsDEklYj4fVQqmNM/LjlmbbOv7O+qij/N1bqYrmUIugDHNlrEKYJjRKVYXlHSPdfyGYRC+RPqs64u/jo2ougiKUNbbpI+Db/x2xXsz0rs6VPAcqFgWBi/RYfXDhM5Ens0FyhIjELEM6DiViir7E6DJ9dNP4HqWVSnodz119e7ebZ8KbVAEGh++0g/ApiYn5VRNSkMFBkNiOgyUXPxXrPkCEEh32BdBNi3O8TCdjh1Kx36Mgtx2wdrve3T5Tblwg3Dy+gFH1Y8bEJ4Y8CpF3f2ifCSfFN4eSp3qgkZwRVzRWFGKT6KmfJbumRyGcIXhjcutiG3UCPipFIo5tES/QJQ4o5fA1zjdnptOZ6UTfGNOqVAk55iL3/7V9vAJgEzoLJTAOcpesyuSLJ9+IW+7q3ToWSR3w5Y1jIGVKSSunuyIIgcV81NlP/hsnTQRh8qFuSJCUR//D4NH89aIdvtqj5KNjOeCsW9jtsu+p9no9a8geJI1GJXPffb0anRpeUfz4mHRTMBWKl2PDpgKGxjEFyPzEZovmYVbBJqzI/RTaIuAbGwW7lIsDnvF2tLp7Hu1b3qfcsk+/G3PLnDBtaF3JHFxcZZjXgxceGu9ILgKdVl711k70N7xjW3vWAcAGE3Dl1+jmMZYWowjir3aY4c8NRZirPY0Ev1+E7PCsPpUUrFDWx5UL3Rodd/wKDQrtaeR5aVhbA3ILyE3ZJhjvRLYnEuAOyGwKzeB1SZsOJCWaGuT/p5rkM+b8QSzB+lVCEqxH0kxZyEM08yz5OVyjGpfkg0zhcnqroQ1mRg3mTReLxNIU9elAcNGtsPJ5lXSDFeEIunTdwmY2MhZ8LoROcH35TLh3OplkQ6JJnwA1CB9d6SN0ThG3scVgT6N+LHBf3cmMBRjqZn7XbXIGemgb/Xk8bt/mx5VZe42eAID680ptynUQBNR9Rf8HbSWhuPaSJA7qG83SvHE4ZU8OEZqIpGXZ2GlaMKbIbq4uiDYovInRvGODQYcpAO4zgeB4dnzqV7jSqHt230tB5CUBEsE9/4cJkpF0SBAh3k35zXTHvCenvz1Ud2TezFEu6rBNFZnsbQrAZqU7ErkypRSf6XKqPZigpk+a+0vsVaED2D3JhRNwxIY2pE+dvJNX6SJNv8AiFzDxFryAUsX4o48r+31f43Yzj4WI6eSDCeJu+GPFvJDu133wd1RnUutlzOH90ntQT/X7R/amKrLW7A0s7jEKi1VMJ5La3AvXzgwxMrp+bww7wFh1HKN3Xhvv+lKLFWQ4sUEOD0zd8CG7eucPfHjJI21YN1vyB1iSH3wVqtyGD321FZKYMEewOQgYKGh26SN3RxAK4uhux5ehCjaQ3GjyCMS4cIeECSG9Ami/Bv5lzzDc4SKixDRO7muxtyUi7xbSGtZIACJ1BYtKuVj8nKICZEkv6tAB0p5TtJpK/9/XVrKVqIC5Gn5Gl+0A2Rp6qk+LbeXn8lN20x2VCwnMxjORdqIQiITNmlKN5I4thKV3Ze3OPhGP46gumAIlPrjldf1dBKZVqhtblr7/oNQt+T9uE7exCNrEZu9oghu1pbzbmo/SpgGJQZbzXpocaLCH1LDy+GH68PkYGdP4CubBJyQ1g6E90ERC3NTSp0QBu/GHRqDgqyK3V2j9dxCEcVLFpXzSIB7on3SnT1kN8WtZr7ekIrjZi5f0VjZ7TRFA2LXcUfw+v714j3uPV07vb6V+Guqzup7wTfa5UOr6bDQ1T3NbY5CGPvUfib/szeX2BjA7h6u+ioHp1/cw2IrfMVok9S9Z7yhpsnxkOmq8Xo0MV1RmRf8bpBvDNH6cgLW961Vv5SeD4Jpn5HEoPWpbBq9Bpna680qtL7lTEt5D8J1k+uhkho8aCcB6XQ2X8v3eZNlMhvyPqR7PLF2hJCMfG8uj+rFeMWAK3akFPtO/o/VbnP2iGtkR7/rWe7ck92lDvk8q6oXiA3cZktHYFYSaLq/Wd2Evot7Yw3RHQToOu7B9UKkrATgIggmR6iaaXml2a1gHX2n548XA7GA0NQHEl1jZVE8ujv65YK5p+tg0LLvdzacpN/toxn+ebxUhZ9WrxYP/6fr9Dd/3jKT9qPcwb0ZHjwa/vmHOeZ72aED+8NvjT7aj4YMnL9DKEMLCLsQsf5EarQaDzcmTWgys8xKOyFBrbcOon9JCV+wNpa53kzxvzJ5O7bVGIgO402v5IAgHbO+6RUbSNbEWEGK5hXuh+Ctu9QahUtfNk/FnItXny1lltmcqOehqOIVT1blWCfzlpMrYeA2qZwB3KGKD+QmDdOALt20yVYVTB5tTj2+GmMDy7xkk08/ezZRHkiu8F0SYN6kOz01gIVGhx4PnxMBNNZ19oSmZ0G7FbhqlOWIIN2tq4hR3nQRsLN+eWFM6eCpGpYrQ5lDB1p4wKcLgCNRIbYX1syQAvEl1a7llGiQmb6ECq/7/nV3Xt89iAoMLWoQN9mTtC42bTObuALCdRI0FV310Ea36gJCuyQ4X4E50iOCXlEIKYZ45eU7UrnNCS17WqO8MCAmY/Yand6v9O4d4kmT7ZC6qk2ekv8GIkgTdUVpWwTWFjLkaZ6q9fkiCDJsYM825A3DCEUh5hZUZGJFNwjUOTlKo3HuGa4aRV7sQlx3cjhkPGRIchPPtePHjmm8Ip2DZR/q5o86FVBaF5Sk9XumrXpwRZPTIQ8bJxNId0kTDy1nEIPjmvYo3kUVH3D7CVqAmawsvm8JH2Z8KLO8/ycLE/DBQ4WvxhWo0Pph5K98UQLfVWZ/UytitHvuWl11gNnpSwBMZijoDMvuarjMIyi2buz2w3nFt2lpdsU17X3m7DfPdSAU9ozBqxNBx8mWf4WzrW5IfaqvHR+vH+6YsTi6rz0tLf4aYgt3gu05+/SiYYq5pqhILfws18fN2XL7xjVL8jw9EWjAFXcAuix8blRIvBCOgrr//dB0izhF6Q4oWfD+aK30NB7cqT/Opn3kXl2QFB4JyrpPrPt0JPzeIdIfbzbr/hE9plcxZZnOkVdFV/zSp8FxdslyWpjEPNJJXZ1ePgtW8Q+fbzcSjnd79KdsHHypr2ZwICYguSrAJJFHlydIA6Ttjc067yPgP6S3LV3rdJuwzy3VURPPHcEuBE9RKTDdFVjDOea4iMrycYG+WNjo2W4TIQg4t+3bQ0kjB2yZ4EE1MQaEyWQTd7kBeL8RFGoyLWXUR5C3g+NeYxfCxVsIvZVoBp9HFHTUJCbXacDeU4pAR7s52EfaGGusTdyg4bF2zu/jkG6jO2B4phg6J6GFn4PPaNgei5xBroUV92Oj5wuQfwYpJO3/plgv5Y0r80XSsnGEXuAWiWmZmY1lsQ8US4K1dYzPRcTy5Jlxw4fYlmKuVWTRbRMYKmuw1I33DmDEq1P8VP92Od4QKQnw9hFYWJPYbHR0xKSftb2WMjZ8tBAxQRPsko2tgFd8fyI6MCWnUbiNYeCpRs+YHAIoP5A+IMw7ilfD67stGzBQbPe0rkPkdzvafekGuhsTZkCc1If+8DSkV43eb9zvJrl1ePyIq5kn1iSK48mmVI5s6WKnHAb87PJYKWmHAK/LiVmO1GT1IDxFSZpp6kLIrQ7z8uqWdiM1+HzjCOwrqHqwKVQCrrOeaQZV3Cn2NWhvzqwXdibTusuLztkgAGUlBxHXhPHbYl7s4t/uGwwBytV2qw66lXlF+tFiQG8sAr/l2+r8X+oPmPxVda9IVEtMFPehuoD+szcvsVuBjanjPfYXvZ1sY08gp19W6SxEGa5MH9kyBEfRetwvbGSqFojHD2jSJn5jmQ3OFTtWNPaj6WgL4LGDmfRvLGMwm5o3lTJkx2kAkCf27T4iS0PfW7p0PeQeHjoPZ90eKsPWr9dxgOSg7PKMbAB5+v0/X3SUGA8BZjFKz+g1kLfK4vgHtHa9G7ODeBAEKJ7NZ+pZtitnlTsDdSbUu3PeQvYjt8EhRO0QBPg22kUkFv+JRStiXAXYTTqYAjjf+cCyqr7UJcxbMM371xP4jigI4Kub0l4rz7G2iqZkzSvv47XPVqmV/l/qyRaVUsyrWGaB8Foer1e7OepmcSpQxfAbod3dnOIX4z27UQXtQgJobSIkWYTYZkjCAP37uo9WcCNqL9w4NRW40ADhRMYBmRub96mtPmEO9KOezoayE3UFzDVvk8YxLZha/Bzt9LXEfY5sF/FVyV4e+iHBKpbaCoIB/I7Ntfnf+qFO6ZQlYjH5ecDmKYSk61/ngM7IN9BaZKepxqwDSNsMK7eQ/gnoyGTVPFcPQgoPz7GMBocsvBftsYYjogrg5iLJtK+2TCKSnAt8VEF6h8ypqi4A7HaAjqhK8eQZOfi9fjaw35vff2n6/3Hy5fs4iRuaT43Vwu+NN/BLTk6tyTyTsd6o3OFwet5g6ojRzhtMnS3peiBHGEcGtg2GVTrJWp2gIFIs5KPyrAophV8Onw+qo/HH+YrmB6vkPieGt7VPry2xQCKnJ+lVCQrgZd0AQMCqvBgQp+mYcCLJzoVtart15zDIVzi0momismLW61a7tTrqbvnlGgR2GxHMECE3111MlUkwFXYtx1vcYe3fbYFXXPoPAKAoMCf2s2xwctbtusDZ1cPHEXsrhg3/zviTN7gbp4AtQqyGI8COwAUt782BS/OxOwDrfsN2AABVtfQvvN+Hai79m45zarWdRnmo7b48HqADqqPphAJOcVWmE6TrpjEPAGAPOIiNuy1QkZ2ZPlALnj0c0LW8YUJQOzVQI7Hs7nij+oX37OGikkz/Wu24Xl39/yx0G2C/WP7edwTWwENB1ZgUIXWF4/F+Hr/JnytTZk0+iu+3VNsAqsF0OLj5/sh79nCxF2bkfPhkWvtMijpO7Xf5R9kf4nyPCXtlFsb3H7YCf10Rc171fYX4MvixfNsA9tosnsxd4BIi9GaGT9iv+W53tfpIK2XugXoVRKRQcdx53QCAj68BNFTUdcqnmZ0LqS3ukg5q5isckmNHUVkxdEhOiVRJXISuGBHtETFhrrvIs0ngCmrX4y0mW/s3YzC3S/8BgF4cqD32EwR0ZN2mDHppiwcL+sT+RgXMwSnAcSFsTduP80FQBb4rDv49Ge9DKs6aW2psI90rV4gcAt7Eced1AQDnKIrYj0f8uwKmfu8wMr+ex/at+DweCrbC59l7ZD2HUL4oysJnurkIaug40ygE01hSAAAwASJFtvhpiPUHId5mMwgZ6lpROiDZvVwHAFBCCGOLuZhnvWQqIkz3JdKaxm5xUzevRXZkZY2929k7imOvtveTwVj3lH3OvBEvfIB4tw9/pcogEIS51MV2nLx6pta2ufndi5N/XyuzHOp4tX07VU0OQJPa84WmSZDrrfWbtTcfv/T39LPko+c1rF7YEz9rM6U1rF96M59g9cktVllRpsCqYhx3PjcAsAqrGUXBMKXcZPANOTGTJeUMraxbO2swl+LlKxzaRURxdsUEzquwS5GzJE5olHIeIgAQaVnLCVY9BRMda0k5d/1pC0gNvOwfANA6kA2xHyfxZ0FOob30iIXKxTmcqD8XxRNkr+jI0nuOA5Q5l/Jq2URemRf4ru8IkTdlT1JNaolgiwm6GXecj6Cx55gVt7BVgStP9CpJzZzxZDKMpraMBPF149VfuDk5W+JGpq7KhshgFoHBMTY8t4SruiUqOBuCgtuPmODsnl5BFd3SdTQ73pZ8fnYEBJfWAo1wYJhoYDrBwFRigU2n1YOJBAYIBC6Vl740850tyXxjgoDL/nFsp8JEAHMIANYhIQCe+XZ6Ki4wtj9z4s37J596qh8oJuSRpUTYdqvLqsl1IUNgMbGRMMVQqerjwIoOBIvhvCkAwLkOnN3usRMeBy7stGOP+bpL3ptAVFwl49CpoGt7WR4AcBwjboIWbqo65luDaW/ux0yvmj+YTumfhIntczgdVuwSmAxrg0FquqAGm9CpGElDj+MzoaBJj1s1e8vq2PD8Ub2HA5/0xTXL6K5pu/r9MM/tLnWJod96/hO400WAK2z3904HZ8b1HBMZXTWZkKNVzTR4IrD65o26AQALhQp4AbG8mTGwc8Xd5VXAeQsBSI0FsgDUVRK44G+FVjUhAgAtQ+sCJ9jUbPh1vDfcvcq/u15rNNB14z8A4DLk6XV+vLY4F6t5HHCxBfFN67IRXJ6mvw0U11QrpXisIL3DrfdWpyz1CcoU42Cq6+fWA06z7mHXSHJldz1Bkhc25j3eTjWa2gGAlJE0ZPmG5u00UW83EtQFOSsNCaSuMQ8AcA48R8Oh45ZVgdmyMih2uCIF5pZlo6wCC7EG1KjAVndAsbwg4+KWFd314aQ4TlpwPkNrbKkHhuodKaKYFRv6GbIfc/DTIS/9MrZTgbEBVOVonNhbndOIfBT6ofxW+ho/Rk89QuxZWDnKVkL8bABfj2PvaSj90uinomMD2POweJQ+Be/a1Cs42xFUIjL6yvFiE2NViUHkDnHced0AwLTOPzTImzsFZKTtprPxkryFUOjqikroqCpQTJVErdB9TYgAQEPQ4oYTrGru8jzeG2ZV+zfX4LSW/gMAWhl0k/3EBfraag4BBtTFkzBTRYeW3rOkWslLmQW+pPdhq706C5QyfZhgboceEvIzWO9lEqQ/ZO9xT/HNeinsY643vp+BGEBexdfzbQAABp/qaNw2vRWCquO3vPmnlM4CUVXQ3ZaB1pHCzA0IZ/H5u0IIma4MsYIQth1nEYuQ0CoWEwAA0w7bVYgUzJcJKp0cm5hka1dmMgCz4uQadgCA2UKsWExpLWFdNnMDYE1LvDGwFmySEogbcIxKHHj06/lwe8wpUMf+TymTqZT6cQlfVbGD4QS7nmACn+6OoP3enWfJG24ruwwvWxvb68HL+c16gt2TNasMXmaRIQBw0wgS+ynUJluos5PourUM3SwnJ0+i6Jh8vnMBH/+0qCq7K1ACAtXukEDFAHoaEAEAAARd7lPLiAJJU3vVf9PRNLE6vfgfABhAc5D5sxXKqv6W3tzG39LG2/hb36bb5EtKrTsBavpEC4MXLK+L+eAi1n/VrN8H+SC7f/79K/05bxVuEMRc/u+Ca6A8krSyN+q8ZhSj3vrcZL3BMXZZjEh+4pkDr12cFHsL/559wPd/sIUbHivH/4Z5/tj48SgOcLjTe8v3zOSy2/2M/gD9GkMWsVtTdyTVvg+3W6uwXhxk1FmId6QMP/uZeku8OJb5sRrrttOGRRDG+lpD88P7L10woNhld50dJssC2L3OGDzF47ApDuFpTp8CAII2lRzF8nnl43Csejuv2TTXrZuiCoipt3LVOC0PABikV4MhsqosnJsXcqNaGTOB3Fwn21xB7shpsLqgtLcrKqoQbBdOMXxwF9rGKrzKaemo3h+DlyEn+EL3F9zk7rf19d/HjKBNRb3EHooiBcy33plc/Tq+s+a6zu92p3tcZQgAjDX4ErKRamcBDryZOGA15vzu1LqhQJ9MYfDu3aUOAXV1EvABnDIihDlXeK67OE1OtL0glpV/vEGwZDDsxn8AYCRou9f8WQRwqr+tN5f4C228xF9cW+ZKN5RiEvjuRGUEldYn6Vt6kYQpp0tCIGG2M1CioNRuuxtMQ+kqZyxYIdOdZe0AQFgFBdiWL2IhA6bbLuIhJbK0klBFVWCVpjwAgOXhVVVBBTZuakC27IxTIAme7VmQXt6QEkijCio1Ltwj4zaUKHzkPcM5RXxjvU0t/cBQqSFFqKKiiIIb/jhTMe8lrqmdy2oNoAJD4wToKYbsWyW9Ofg7we/ImDz9CLE/XaFI8Oi10pejA7vfHCY/l9oawP52tWFpigZrOPMgp/nE2huTszl7klaVCKxzoloEDgCk2x8faoc3NwRE0HbZXL8sZyH17dVYFBuoUp1EWUDHRgR6xv+f6y66tlSUkduLpmZr/6Z3ZEMdTFfjPwAwIDTXNH+2QtTUn9Ob2/hb2ngbf+vadq70glDzAu6AcGy/akkqsE1/TKEItTbUb1F8oT/nBx9PzPQmWmTCtfG1dm8LcVdwF5g4UxQft+VK5Nvoj208DiQ8dQu3/atIawDmRPJ43jNDVrWAFTJ0OAJEYJGQzpeDGKkybTYd5mukPmldavVcjb4/dyfi/gLd/Ozoq0tIKBWjJy2eLim1ITyuoX2Edm7GMqOichceVrfRhypP98e5uOAaIt1SMlMZ2IhIq6e3SphC+I/h0nbG27Ai2dMU2mYYBoNsoANzwdjT0gvkUj0hNRpsDGuJBYmO1C7D5OPki6qP4mLe/obk8oiOTLSuUWjYBtLtYyCHeyA5Tw3tYSJItv1hitwsHaSGHT2dNhvkLxqYUw9Hu7C9CIQD18omTNkPwc1IQXEGbuS07nkzR6JsqXjCoNSB/tnqWkLsaDcUAmA8z86JiEM/Ni+SODFvBxi1gEAWZHLIlnoB1VkBkOBrf239cXXlpVD8c2NFej6ddl8uARiyiGrmQ9Hka+APe1xY9NRUTfwzLfv6FcD5A6WEtXxtbID+ymrVY9/J4iwNREZjukGdhjkX8hGsswGUWk7vnC9l7ibCX6ASP04eueRlIMD4qCzdpyeVoe+2oS3Uyi7xW4CtNYNLneV35GHLjDUvqWAwFviZPsYXKd3Uqh3A9GlyAfPGM0WbZ5+eTm8XiG9bTN+ULlK8BXWhTt9eX0xw6fmhzbNPz7XywsmFvyOUfKx3j5Wv9QMd33Kp0ouJJv36ePfA/bGqXGotwjghbiLn9s4bFtrzcNYh5vdx9wS8PmsHjblJ8rX0ORBx4SCS1KvrdExAQ9xPWeNmlEJnwqBsif2jfm+PyTxBNaN3rYpFkTQK+0rrGNAOxWV/wBCJ0kwgxiXHwLVoG8NTIrrxMiIcUDX6olm6hzE3XbRZFf1Psjqff6ujR29sTcPei1pgfGRzvgAqIHDToyngNbDbYTzaHmDsZMwrhVALcC6VHdMmJNirZ+h4+Aqx1qof3sHNn848n6ekkUKtk4gQdIA2AD2rUSVwMTGA95YBHeotFyOYhipzN3srWpDN6Iflf14z5Ob9ObbbRt2rWegh7JrzO+k0WiiO3AYhqgJrXDZ2t8iMcJNlDZRCMV8DndlBfACGGHAiLJcZtnQk7PVJE6jP8ceelv9dOzC53kfXG+wBAH1T9CXY8UBfmYmhWLzTo5rAMblPkTRKEaBgtZkotQhQ7LLEKNFqfgwbPtog3XsLUMN2ClDrVbGAADVaNwDlEhNsrXS6Fh2BW9tuLbBiz44n5lsQyCo5cbubMgQ5d85YKiOkr0f5k9PV5zqcONcoRMnJkGJoUL1q4RSvmp3aVQeS0lXTQxLDB3tHSL1gYmoFOfhhlYFVoBnIPzXLs4M6sfAJNaRCERBjfr4x17J5b7xCQllj2FP/auE0VrHLhG4qKin4El9AiQ9IcW4M8pntZMUtXK5iTkRlzvjn7m0nwtCCXVkoqCIlK6MULVW0ja07CkDffd/ZVrm6DRDZeDQv+PL2Pp6XH5qd5BLchhHXRrowk70ZsWolmlycHZeoRNFvkmOKUHKbe+0bYAslGi3kgZycD86ZfTZmRG4vKBRMphUh1Fh9Fyxz3n5RsXa4Fg9wYMTpDx4t5qxHiwKc9GSKY51QEz8zu/ENXOaQh+f8YjWU34kzjdUuErVYbcqaQkD6BQqcfSpwev9ejYSyePgOtL5aFtgex6x8BCSSdarUMGq9tUM+h7pXYPAnPvxK/trfumJ1bVjGnipf9E19v5hwCkD6GkwAgIDA0KbHTMcJyqIElfmfNAhW0nXG7kKw5twCNhvBunaR2DIAlxHBWm6unYoAAIgDcKLFgUb0ddjaX3MDHDhqAAgAcgPyiv0YByqrMdO9MjKCLhXFyfWXFHSblSYEBzYKdrKXAAVHZQbsqWAE3rVVYFw1hFuLXOXsbizkapuNJcPbVzcNEAFAlmDqdN/2OGovNz01d7tgMgPJVU6FTCfNhAAAF8As2rgpAgylZ3bHfVXaGDx7r5hsZmUQhwMzqBE7mFVjglV1DsU4rHmlNPXnfG4FjY7fKtQNoFpGYwS66swnSb8lOekLqzlu++bV36rWDWBfvdqocZ33hBvhXyZ3r8G/Gvvp1d8mlzydVnUtBMW2bB4ObwAT5g2gVoMJAKBewCzTwzOGq2ZRAqr4HwQm2HQoY1SflfFGpgGCtzGSVHhyqa2mhdv52no9+aJxO0zx0cU1B1GL+QH6viaAAEAH/LX5A+GHWrPCAHcFsZJY9ojfZZZ68VGlgozuYRGP1v5ZE1vnlIRkfUa71ybJ9dO1uT3X5/5+4usJ2R6uGEEGCTDhlSIelpNdDXBgDfkhCBXLMqgScP45B8E35l8YsGcK4Fw7QxJghRXQANhjyxkDshs+AACXENSWw0JPISL192ZMEJPWDZvfcaNoUgUWr8my5pPkuicgZwfXzWjenE2FgLkUZ0UjcwqkCxvDOpLUmfI84zmoYq4lrtJtYlvE0Rg2OJGLBAwb6zDa3AKN0xtp9MFLGD3+0V35Odcp3O5aBh7+rXbNUcL9weBlnWkPdwtovF19Mk3c9umJgmBvNLbXy/I4RKcX1VEid0n29ti6Wru6riQeoFgn7W2ZsDdAig0mAEBqgOnh6eMB1GUAyrXvEuyg9owogT3MgADAXpZECI9aJAoAqCAKw4hoGqCovAslO1ssU2z+xIvrKK6WagMAKHdsYcxmqYUBGtQ1dLmFHLASXdRstJktG2pqLXHrVu9Km2j6dKTaNSRecmGA9qR1RQ8ybuAEjYHGvy5OlEYDp5devkvTF9419AjUSoOS5RqG+RsheEFXiOU99MAgRldcPnYA8spa/hAAHFTSddLyHYfI69FHjjvfTtr1GStXaUzA5sw2rd/bwkxqm3uXVrj2bTNHsIXt+zFbJgi2cKeKY9tlsEVYYQ+eGGyzT6kR88DR5/KUvrhw0VS4vVLkuHwZmhvWJcb9+vDTWxjn+VWHK/kX/SoUq3XqR0HBGTPh2QLmpsEEANhq4LoN9XPvOoKU+F8UBOnUn1Glx5gGAh7XSBLxrEWiAIAPYtCMiINxvTWehk9Wqi4xuspxDTzbEA8ATDcorOHi3J3Pg4quWM3oQAuaOJv+nCho05SaGjfypyDOlHa9bu2tZMVZa/9jA26ti1vDuy4Gt11HeEMwHM276IdGeBEfuyWDSxogAoBbgzdj++6Wwc3W3N0ddJriKpdNi1hptqqGbxb5nHT+/YIBNdzO2JKvoMZaZqCCOhrZIxV0H4OYKdDNGrFJoAbFpivYPtPh8zIXnWTb4NoMHX9Ry20AdRga5LxjHugH46M3mZujv7QGO7LVx3JrfbcB7NhWfIaTEPDHbemR6f1aLg16p7axgc96WnvDbFfX3mDZOmlPyYQ9BnxoMAEAfAGmwtNHAXhn/kkD4OGGbFt7xj6AHWZANMAelkQQj1wkCgDwIKrDiGiM3q4BivTrJaIktTL/gMNFewCAKzU3zCRFgIYLM84tHjj8KvxqvSnhc7TxCk/L23TBjwvXHiotEtbfKvw5+lkkFSKsNf9Thf0xxbdyL0dmfhsdeZV96q/qm31cL/cESbWfcYgVSXcZmWQwLWX/OcrSNJ3jpCS+0D1+A3c9q/MHX0J4ghoN41Frez4G87xwUEUa3SS4QtPiGQjKX3b3V3oW8PrArxQTyNmt9IIQV8IZNPPN+xiDR7jOYBlumI9m+ndavwQK8ml2TBDE7KrwJRJLIrn933ZRANS++RXGPp5aMdhSrynKLZVl246VVuF28T/3Hn5NBXZYO3PdwK5YwbGAq7bkp0NM8ZZ8AABTuwjFcFc0An8wqrLx71lPM8Nb7ER+vOdplI0sAMBin1K76Ch1eqH2yGZ2Lu3EDKrTZYurZ3nk8Y3q4OOG8SVdqLdVwHYO1puo1IsrUjqt6k1Phhu+CwaMh00+Km9c85JuEr71c6VVc6coTDYFApkwkL5KBMBGkf7cdn4lfi756Ou6Iy5S8+ndlkiwa9w/tg7BPXed8XgIXq2t5KXgpeNnDGFXYCAtFKodFqHWisX+NAQAQNKCjEjHjDI6QG/rdRLRB9bgS/YaTXsAQN9mECdZpIQpcB+s8gqBTWC2tJk4uAlsR0uMy9xNswksRi6FG5OXWJJ+ZU+6uIlKLJ8pQMyjuLRZO127IrQ5dg/uumPEImCZvK/Lml4CluX7+axh4z38jDODyjDNmCHlRwt7m+xaULzsS+/TFP+b2XbHspvwWjdkEDxXhn/+BvDZ6YmXQQ6sjdKFuQiUIcsugueudKltySz0EOPMn0RzN0l5hU0iIj7H5H1Gz+NIo14fqzygBDhyqr6EhzVel9pnCR4A5ye8oyUn4drLXgFM3DSeijXfhN5+ndLoizM2fjpdAmKqvn+Snqv+DW0Rk5GiKkcF03T2GfKlFk7koDmkTRmuCo6N/+zDxA9a0gLghsGHa3f7GzHXnwufk7RCTgAGCjS113fL3VyubGSz8C9VH+J/TK/wlYbHe0XiOoCssAqQhVkOS85pjRk2/zek1zm94jq4saDT5fWk/ic7uyhNxQaIu7LyxeJbA2YtXN1P8V+fA+oqF+5lf1IrZOQoEtY1WkB4fxbUSPoEY/6uc8T/1/ZhckpcKWjvprk6wVs6sg3IUODu0ZONHFcd5ZLmswfUJMfvlsiykJf3jDY0f+sAYIYjjho0sQ2dX8JZIXw89IAQsCMyZnx3zb0lYgpPOEjADm2GTHmEMGSyRfXChbWO2QPb1UZmJNavM3IH52+cZz5oByzl+TwmeeBoGVT4zh2AHcEd2CTOq5zP2JnU9ZIhEU3pEacXOubXNmPYT9Iyrz2PkZDbaY4WD/ht8sKMY9q9r4QvYas9aWviMNFJ7+q9aTPy/dt0kK9cnAfMlygmIvIQnsU/inaR6Tqd2tTz6bImJEJrFGYCwef/j8G584jsg7cSkZ1JF7UcWR22TCVpWf993SKBcqVNaP6vE2h0aYGTARq0Jjksjoe12bjEw032fDSJyPo4Bj9xi9L9O1yaT3PfAikuJrNzdXzglixr6TVyW9QzWhZk588b3VhVCbcC4xJTFxmnmDpX3GLqAY5jTDVTGFTkj1k0gaF7sdGOfOKJtC34HbEThv/ggIetpwlCFx6rmTp37GbqgujyqYuM7QyKgtJjP1OXKRb0zm/d6pY/XjR1aeJHUxcST5o6pzcy2PGmqQ5+/GnqIRKPmmph8ampSxavyhWCsQWKjmflDxIyLTn48a5yuvCMFxofIbGbU486JeA8t6yE1FZkNQufzUtrjxxFUZqkrRb2bTiFNhiUFOkCkzvjRVs3+aQn9s+dK3UXPLHo6UEST47bcLYJGx5JyYXpCWpTCk4rYnqgJwpNKUPiECRAmoNrbKSqfJtl4GbRdC1ZtfiNNVsnc5QVV2ZQiC+Z7KDjcoTZG7RxejediCl9yz/pDuqIWIO7v8c6o26FgDWcOKdW2qUNpk5wVqZ7ptFicadaSggAbPUME2/Blh11ariFwULd92UWmY1TY4TgZCMXELL7gAFASrd5nTm20qrowm2O0CZ0+fa8hEMp+VDfYeNfM73HtRrCU936vdKrvZ2nniDHEYbSlRIGzTajAABaAClphug+jeeCBFabf1QPM439WLly2aO58otQF1wCtUUMYVdgIk0EbBsR5Jmiu9MQAADJ1WMSuftRfQBU7eskAt2jRClNewAAeuaMqUxS2Iv5w5rVDXyc3mTjs7QxG59lTLGZgghu8cozqD3JijALFJ0U7Ukv0uFieJ16c5d/rCI8scluSbvbRFbhssluR6vflGlG6h44PE0v1L1aehIANKeQjcJSuwGgBUFNleVrp+PcBWxq45x6tt0YTNtUh6kya7DVlNJMCAAwAcZVyHWi8K1gynpm50IIyLOxByE6BoFriBHrxHhNcgY6eZNjNMYb9XN/jvYv8QwfriF/EQKegg4B6o66JycYhQ3/gt8TNnbp1ww6pQJB/iMzP1UdAlQoyG9/mDg3Ka+NJbtD+ZDoVVWZIP+3VeaOqpnlsf2PBdz2cZHwYETZAuOijAIAzNGsbHlXe4jpul6Isq3L6V9z+S53FV57s2dYur2pDXToHok04xKlpSclUQCAWtQQRD3ZgTpUnE1s0KhLewDAZF57QdJ1rqUPcxgOh3Kc2TpUDsTnTYZ6SZ26LYJIdt3145JnScv+tSRc8pb7FhtjgQf6vRj++ubchl+5sg5v9gEyLz1kYmWXk62IXeBlOdlNA7fTXAIA3BXC3dAN7g4qlnMQpmH+jUrIe5qxR/047jpiuT7FOGsrJx0bGcfNGL68lS4nhNEu+gAA5vImDjGNuCyDjgTaXTWQggSvl7IAAHABIkrMhex5e3g6EjGxmeQN2beiyFIsMcXT9hZ3iuyPG+xLwkZ0je1mWAbOHxQNfKQpTmx6utzIWX3CX3kE3jpVnVXcTXJZCUe/tcVqnzf82BTL1RHGinX5gk01owAAG7FypjoLb2AATgBlas80DSjLDDQENMWSNAH2VG67rHZ9nrYUejhRlKgUI1qpTGTGF3BJr5fDAwCcXlAK+1EKkkWrqewEvULy2BZrcEF5WZuGkObGuuqUfsEkKmkb9kSXnAomtUSlWMAa3PdzsXaHIWs4UdUo7dmdYd2c+PANkUj5mKNI0finPMZ+7Q5msZJbXywQAmte7Cnnh4AIx+4TS5oJIjFCTBcDy+MV4BASLz0JALBuJLJcajcA4MoQFrF8LJ1nmNgilrLejmU3h9yVoTCYvedGEsw0EgIAmCQ5IpvLtrRwFBa7UcG6ui3NGr1awncZ2ga+y4QwofRV11jkIzgc831wRyDcOfZ9wuF8ujaslSif6D1qlWhvh0erDpx815boU9Cr1KLjboNFyIRZ7GvDwHIUp6MAAAr20U0nSOBQBuBlksIR2mzXma6B0G67BToSoavmSDqPxezCtWtGuM/7f56GAACIsTlRYnxOZSIXyZlr1AYAeD1DEM6oqJj9aA7ScNpM7RakydliXc/yg6hZLqUDyUu6a/3qPrPClqjkqmgU9+kSttRiwKbAu9ie6H6RzVoltjmJKhJMBLfdpUCIcDlsFAMRicNDGRAxu/QkAKAiJHFZajcA0L1Iiqf7kq4xPKBUc8cMpKp2VgRSHNZiQgDg4oTUauPSAlHOYKZRT5Qgo9K2IKOGsPluuPIquJia7Nufg4G3vbzgle+an/rvjhIrkkdV8vSiyY9lgfZxkXAaK9ey5KKIAgDcpWVv9UHkSpghSn0tAS+jlbvU2vmzK/RObXBA79VIJ85ccydtbi5QRKe03cTCKVGigz/+PQ67vqfziSqw0toAQFIrt7eSTrjssPD1jSVsyFzDbt8UKhDfeknToq27Ma/VLILrCknIq1vdzfGkfZYf9ZBRkydeukarr4LTHYTj3U7fmBxSsz48bCRP1SNCuQWUAMCm2Vm6GwDqgOI+9x4Jq+Fm7uL3eAcFCoZBm/3YTPOXj3u/dodfCq9c7Sr9478LSSSCQ4BKAPnt8RFmePFS/GQXvScfH5UKAPnP/GhWjT2uNvJPhw2292QYi3DRA5VSAAABI9UbVTFgYAs7yjNoOSDSoKFslJSKOlgwcduCqmxaW6QsEoh8IsEsxgMAOUAVkBcEcwY0HxcY4dbg8Ddo5thf+Or2EaYtZpAaF1cr2j59eY/k8Naz34seqeGRQSO5bhwydxXC3YniHBMA4ASoiwakl6g5B2F5DHDHQOZqZ6YHyJWuHE6sOcdQmIotHwvYqf/lXd/fFAn/IrGkC+jKzMsKG72neWn9SgIMsZb0gFdVW3Mn8JjlLAAAywXOwHDZ61tZUxJXozMvs129AjtniVWVBoJQcfffVak6ZognkNVP0rE+MijVuHUtoVZ7UQkaA41/VZxg8FE/kVvCOfkeIhEmfDpSQocNvw/f8R4uGSfp859wPXeh6nPW+BNxc6zfmDBuANxFcVoKAOAKDfUecH0lwJr9vJReqfpsVeMvb9s02OAtTaQ9wIUHXWM8bJOTKS9s3l1+DE6Zs0mUO5/eFUA99zqJEK7rFSaF3oZ4AEB0V1IlN8J+jBxRODTKapqeY73IUFli805CgE9geLP0VnmSFnsYwPK13nD62MBJa2QKhKCqeZcDUHUPeuq1xJBt7MI8D3lu+yBlRJuYz75QuY4eDVN/v/mwJRiiwrOMep/u1Qw7Boqcn6jpOpjfhm/FvzwPNuLtrWabFcXgVWG9nBXG/FP3N5slV1GFVP2BcohbSVCoXrdT3gNr7w3KIMOut9BvxuXNTe3gami2d2hgW7A8QabjNRuaaAkZkGmRFSH76GMMtFKFF6VJ4Uk/YIv/iZQooCIDM7pFPSQzdF2/py+WDSQo9rU0Q+FWmX3+t1DKAxY3EyLKkl0CC6AJmtF4eRiEqgChrTDnsh09afuxJ9csBnUPYVk35msPV7WwyOp94BCpCvT7TvyTaqY33Lgq5XAIY5butFhBbjePXBgoRYpxNObIQbCz3csteRS/Y0EWHXc/4gp8MA6BCw/mcqvz8y4kSiAYbIJFhjzwzQ5mXg7Fgl1oFHSKB1FRQ8hxY/qFJ8RHJz0PfDInOMJNxcuVPWiQ7nfORkOaaKIRaKEL8U5h3cf9ad3HCa378I+OqNf707oPi3wrHIAew+4tfQMpqChw+0EvGZ7pow/ub0BNi5yLvx78hDIKKaXMOUxKEKYekUoU7gfrPoYWiBUR9j45q3jGPQsjh1z+aRO6Bjnjwzj8El9kRqyraAuDfhWNNQ5YuDmIVjteui6G2rVJChUNWOnidyteR21FVirTNPBOzlnqOQjmclsbhdH3SMKeoktqZ2QQN9OLakubJS8mIGcB6ZArqOPhJXwgFqOiuycvMyMcatrFJ2bLsKAkuMb6VQkBgNzKzcTMqga1eAGOsqz4cJdkgqKo+DSXZQdoUfENL38INKIyXfvk4erResTmPg3OhDBdBdj6neA1KyFTSxVNuut6XZv8wHE1H3xq5dEiRPGueZJ5Rcc973b8I5quLGvS5D43j6or2+R3nrqKnGvVGOqyeEDPD+BhmkwoL3CfTRF7Xy7xm3cRKhw82Kq1Pj/QfJWv0EPRiRbc7pTb4/FqWa1QYWdkMWH25IuiwN7lKAAA+xirKBDL0plFqEz+p7pvwFjp323tmUvrTwFczQxcAVxkSa7FQzfvAgAYCrfHiaZu5oNNxKFVidrrH3hHarggHgCwJBNl/lh7wezEKrysprWgqMLYkiX7du5JjKm9txJqr4mT1QxYuElUS9aFnrwhZ5MowM5E9BI4tkOgBoAT9bA6MclJo376/N/FYJSFy3Vtq9Pg7S4nEwDUZ0hNt6dijFSLjECcqns/By5c2VhxF0+UCkZbvbdr/l1EouPM7GRskga1MrxBptUsW21kOsMgpAZZyLlWnmwdqBH3a7xpiG2Or1z4XkcTYqL/hS6wEvOvVTF07bUi4dtd3LLXvdMoAIAd2XU6zZlKsiLAHY7bzur25s9ce/WXdtUGLrSrSnJxZtT9L14AwIgCS8SKibYoXIui2cQJTTG5BwBUkFlhUuoWP76pxp15Fmfyxt44BDPx6BBTS+2gpaP33O0xtsjH/u0dqSy6UrDhOtScTxxBQE3QhCgWxrJtPUglqWpkgJrdNmjmlsoEgA2EHFMdGkoQpICMiMBd70UycRc2MGvGYVenseu8jVaekEL8m87+AEIM8TtT5989vD9lOjZNbhqj8EIG707iqQ6t03YLLYYNTCkFABigpbpRrAF3odnps31ZQGus2EALOkrSgirxAgAGpi7aBZ1NHG7oS+4BAJ2y1DAplvwRTS9zEkQoPjdccYBcT79lBR7BfaDZv/E1qef/onV5e7KR/4/t5Pf0CzxQ+7+qPP1X9c3e17palAmNWjQBAEBUmGFzFJrYQS3VgFvoNTviIgDHfqowrVLB+DuZ89x+zu953TiSprj7L+uPO6uJPq+ykAMAwGhd3JJaGW1w8H+vYfXZpBdaAIAx+qZyuU4FDIaSBpx5o+tY6ysxMbXW16qJ1Ky7ir2RUMZ/T91WKEiT+YGjqL2fzz/hHILfaDlBfarPwwjhnUJLzm0XUgCAKtpWcUMPQxQHvSiOAIvWO0s3smfOL+MtDQuD0SJZ9hxfazCqOwGEaWJ5FwDYwWhcnFF0nEtLProykWAVXhQPAHDxO2UX1g2yB9WH9CYXH6ONBXysKSXi6/R3hO8yBBKo1cO62lMDdm6yBduZ2N4ApBwCGgaoOGw0l0/T/10MRq3AQdc2HYG8Xk4mANC3EM1tTzlZJK0wAs60sUxy4AJruYqsxlS0gppaSAgATGX59QrWroVjGumTixk0g3y31hdazoZb69vzNuQgxIbqyVTFeM7P+6EhF+CDRh6WG1wf8aE4lFQvVYwDFc3u36vTOeHtZ1Txj6ejAAAqHpVTX52cnsoEVDNxVTzzzJl/fWTlSgZjZOWMpmPYogCkcRcAwDY0BXKiaaaBlhOpxqpE9wPu/46kuCAeAPBKpmW6WJ08zIO+UIzW9O52o2RlLbHTzeQlNag5JhUWmJ3idbsKocmKUyj+t1EQOpJQLMML/fhSJRT3GnpuonCa23qVCFY4nxVWO+eES6PG/5PwV5JjFG7dsa2eQapKy8kEAKEbUrvbU3EbqfZ1DYpXwKHZijtb5BQxUUMhAMCrZcrpY3WczSBNPaNmkLaZLTJIrwkhk/HEninzMcz0nzcDTo/z2RgbWqo9Z7SJof1NQSycOWQ6SokUAEDreTj+aCM/Bim1SwLejgZ1eTeyo9Kb1chc3cWVuZ8pf51qVt20ijFR9yzwAgADdCsuygvaOvGcqcSH6r7VcArxAMBokSx+dgOFsgjDmpOoZFrk4+IqZD0cqFoKDc2yK2ooeL9eyzEOKIvgHULLrn0MflgNbjpRfbQkAbSgwnAK0XaYCiUZ/UPfWNntSHdWoUwAKC0SGHV0sLKDq762BIrdk9PYYeP5CxDvGAte8KL06EJC/1ygT2p9ANGGeH50zxuWpP5ojzHlEiqVIw0J+tOCHkYMZ4pvPTVWKQUAWBXij8Z7YJBSqQbcheYyaARKHBiAcBqgS7wAQICKizJDn4fqM59YXMdiPAAQQBUQFgRzBjQfFxgx1eCE77oT8aG1hn+95Xg+xvMXOaKLqezwhuK7lqc/qjx4YZa9HELc2NV1mT1F6MFFEwDAQMRt0IMacEC98/td9tQ8eRs4/GBSFZlDFMve1d00hqHsblKeWYuQ8FFBMdFaXny6/Jou6idliJ+l3XXWcr3WLGpPXXl5UI4NLWx4V8qNCa14+0nhSQkOEAKyd3GFiuo18uLGPC+8MGFqQrFj3kmpv67078hXk0stMi2+frECpzezP5xLzKqmaqr+BIwIAHlx0mWje/pBvMGCHABgKMRMgbHMHJOxRSGZoLLmvMLsI3mdZhYAQEVB8pTposztl6cjSUFspm4WH/1BKVsPVEEcQaWYe6LeHZzl1vpL29NBmCA2NVDrsLRGsA60Uofd2c0BR4OG3DvDvOoIWsBXqc8/KWXy6td56555jDWs9IKBNcgXZK0vttHbZw6L7aiJj0RqozCEw6v8WHSlmhJqSqRATNPjaCEl9KYqiKQ73l9EeRL00EAN3JG8B59DKynocr5jPTlSDj6WNkLiMEHZhGxGciDWQnd3go42qClbafoELdPTDKM+/PrHeW+Iw/tdlTu5vqxiVkqanOxXrlg9QVTfbdZysCRR6mYUAEAaARNohgUb1yYPJIVYNgHFLe4B1Ecxhi+XUo0zYqzdTqFdJCR8VF0j2qqN9Ezkg8Mkz2lYRF/L5PHRJp2uINr+hcNcT/RitpEddkKCh4aWVF3zLjXuXw4XTpe/KzfMNa6xwnwF58PaMBxDV0J+hKulnP6E252B+GxGD6U1Ert8FwDQhkHX8iPOnlG09fitJ2NRl2heeaMiTXRDPABgubJ8pQA2f8ICOpHC7tuRaXaYWygUb0dWXCARUGjejnK7Rt8MEGfsNzI1hCLFC0MgQ0BY5XgRU5MCyrcqE6eQko8PxIWUprVwkrL/pFCltM0XM0RKN3Xb2WPgTkOZADAgmNCi7pFBpg2Cqw3NMP+tdLTGyu48xidts5kQAHA53Y0gi23jPAUNdu3MONCwwrPHCw0JBjEpaJXpMtsRJaPsxNklyHI7eR6H+EyAFr+Wu1tt+t7CSZCs/r/ONq6YFQWqy4bqrYWpLdVSUwspAADFht6u04NaSe5T0RpQ5HuGETJrbi5gZQYBsMQLACyomOgGejrYU4n1xIuDldwDAJr07YFSVPQzFfQdrKC5A146CsG4RnTvQch3ggndi56+BzucCEwxwnndLnYfcElnIhsD7AwjcGUO7aN2GZtrQe0xRteBuq7ddhf+saFMAHALdK1FNZuBa+sGTUCphKGE9aQzzU53X4hSIQDQYIW4+iXXwQkyPbSiHrDIHnuw4wd7MHkyMNDhKrwhI9zDMe6C+OWIeUU66f88q+/5bW7dywGKJYYbYCkFACAwoaGjCxYFSTgRSEC5uQUnMwggJV4AoFF7WjR34OQTl+u6GA8ACGwBZLCYUyD5eAHV7zrQDF7gSAHQnu60i91p7NkG57E7n9gb3yRlBYFnVZ0DJdhGB0owrpauzG3XaTVwoUwAoBYNGLV0sHKDraU9FQquNhPfk9rG91ypqz/kOwT2Ff2wRbbifQr3p/RAgEhX/K4dAJNcD2hetJu2v4D6iES54v9LDbPOdVxpeGK4AJRSAAAAkeoFrAgEwNzcgMkMNuASLwBQ4ERFj2Z9C5NPHLAW4wEAESz5Ixpc0Gxo9DqIUKyDlO8LiF/T1n/2LCb8d+qfvfXzbgzq18A/vhj2xwCb7fLg95bz4BvVQeTDRAPfs50lK1CV+dDjBRMAYJZ2qrlhmsbZkYMtCwKQBbuE1bV75mcPPbrSByhaGu+r6q74MPzus25ffqCBnb4/swfE/1X++1BdqH41n57m2UV39mbKtBUa2mmbMo3pijBXLQnXETtN1rJbid0/qYtdNeobpJrXZAEACO6JN86opJvmSq6FXDqt6U59KTfLta0uNqRy3fe3l9E7xFJQxtJ6l5XlmwRl3FqUsjiR5/hA8mtVILxavKcfPQIzjR8zj6aU0NEUTq9YsFYCk4oaMWHNAbo0owAArgLCMdMz3fQbIcYmoPTE498wUXHN1csxAqmtFVQVYBekfFwGOzu1EwAIaI62uZxooaSCmmx1baLjCXe16l0UDwBM42vzP+c+S4rv0ZvT+KnCeCoMky8lrfE+wV/o7xv8lSlwh7fNvHCDt6hPxC3ekBPogDfibDrhjTmjzngztdu6sDq3oEwAqGKgk0bt4WGdKgd7GXRPCcU3pWykNMvNhACAJeBgC5e+hhWkArOyM1uuUIZptsCztwaaxTKI7YL2wm6yA8/1mfYPU3HjUuX1KQBnOHmBh/jMaqX+RvfOlLzGFyswVv/5nL+qwNpM09lQw1qYyv3LNLWUAgBQtGHq9EzXU+FMjE4ApdqfxL9n9oXJmpsjaq4W5B2kK+oCAAInIjqQ2unBmkoswqGsG+YS8QBAffvuICOXfWTvG9vkQmal8dMDHYybhpAOtnwH6OB6noLlW6xwckiCBU4vEsHwLvLqlxUipK5Eqiy5bXfAVCB3xgqbPjjaSZ3GT5erYy7mJPexY9tc83aj0UwmAKgPafrsqfd4u5kxCHwVTEoOXDSdkWJlivj2HlSaEAB4pvs7qADXNEPvQYaZdI7HwY6zdXAiCB3E1JznlOvllt0FxUOllxDdpDdXOB5bcZf9EyOGg9qlFABAB0CqB+UqkAd0bs4AZwZ5KC3qAgA+ELKIIPOJAqcUDwBMt+3DwhFADSZsdgrqHsYnHwss+W6wGTwghcCyITCnXeRuq6UdwSsTyWPjVv6TwOTENNl4g/AptNhBapOVjAWtZrcn3FAslgkABRanFo1XEGybnj8GlxCBkjV2ui/HdD9v/xrmsdqFjZTKBItmxfcSFEjigQDRrfhdewJmzdTXA9cuZRLtdCWyFf/LTuD5Jbfu9VpBi2EDU0oBABboSL3ZSWiBYsAdK8CCys0JRGZwARZ1AYAFOyrqvcdZiHwiwSzGAwA5MAKoAB85c+CyMWl88l1gMbhBsP/ga70JnBvwnJXpxVHhNbLd7ylG7fI9tRH4kDISAKY4gQate1Cx0nMYOyWmaQiB4cRZeURPolI7P5cY/UImFqe7Ptx3/mWSDm4C7Hlb3c4bwRCm6nPMAqbyj/fYoyx8Pw9W77Z5aBpW6sERWsYBCUkKeAXWLb65e3yvxWCRRWniEIzl7Qhf+rFTQr83mCUQtK1DrWnuwj82gX2cp0vK7f0a1a075sa4iCnp6FqsoRcVp9w98OxdpKHRn9KNK15VN3oEIzK7mIWuGWyVGuwGfH58x4KvDEIVM0FsFm8AgAZKzNwfK7L4dlFptgaVQf58X62yzAIAREdJlnTZznr7jw+6Pg3I4MydDgg9ICaG9wtI+lDr5R2brvFXBIEa4LFH1uJN5c04CEpJNg2d7DKdYo6NJnEgQMyzHVxKb9MEHa7ZW3tum9WxwijycNI0itQ3Tseox9mncAd3S9gKAAvg4Bnm8X2a85Vj852EwM6fX+PDqV2BaNC+L6ymBfnXy8rqC87WjZkp7GZJFwDoQGpBlNOxqx5QLjFd5xYHWdoDAHgoTxQohRMl2pWp/K6jBeWweQh21aMmGNsDM+swNzJw/yeYg+Hu8zVkjX+fYAocLnMQbIvFSa/aQg4ul2NGsexGKwqOblKi7ehmSjQe3Wzy20e35cUyAcDF5RmyattdanbQoEvjVCWcnnK8G+okCgGAnj2LpRmWQ8kVbNGZZfbQjsahpsg+HeLVEBA0midLc2eZLlBPJYeBwipvDhNL8B2sGeN2zkTsBPCbzBUA3k8zd8L5lf4BFAVeedXP+pya8zsaJwb9TGdSFwCQVIIoH5oY6ANyKjFlvHYQyT0A4BhVOFAKG5d0tLP8igqaDUJ5BxOGj1YfboqJfR5AB4FPSAB/fLBY0OHfW24JjfDS9pawJex8oti6E0lAtu5ZyUa27l3JSLZGKbstXjTAYpkAIDpOsWpYczY/GMiSKPMIuL37Qk/vHbvJxvCCOa4rQwAHxDJztFHfg4iyvb9wI4iMts1BTpQ5UHo49E7S3c/QD0Annn/AwVGYJm4FgAUF8Qzz+J76M3cZZcEisIDOzQVkZrAAFXUBgAIpiwwyn2ium2I8AABwRA/B8CZofHxssLIPARG8979uBxVQPFzcElzhpa13YUso+USxdXskAdm6c5KNbN1zkpFs3efsNnnRaBXLBADRMc2qYc1cfjCQKVFmF57dD83ptfkYPWNU0zVv76h7ErsCwMKnSJNzAFH4eD4jhDIktZVbYwT3W+YdReCT0BUAFmjG08zt698j/RelKpAHVG7OAGYGeSgu6gIAPhCySCDyieK6FOMBgAYjegA6bDb5hixcNhaNL/tgsMPrkauPZ5Hh/xTVx9cy8jhHMpzD47/4Fx99uptiNG6wG0M4Wxt16Kmzte735N/vgqq3BxDt4vuLXcuP+m5O/KrHNQOEt3e3r3MTR7zVhdiXtWt+OywrmazPDUA93Fd82qtWXlzDyREPXF0sFF2rpHiSRAqkm9O0vnks6JXW0auyN3kfrYqZzW01yFo6JSEMGEDoBHISrfXXnaGBn2PjjPi+NnGstVVr1s/TIu6iYgQ+YbAPYGN56wZnTGXU89pAVxIAAudXACJYLd7u5Hvn3hQsXE/1FcZ4gX0WQHXr/hQ/PRI6rf9AIZYYkUnwuCN2bL5AhOglScUiRHdVXGRT9J9hTa0H+dZKTgIfURn9ZCuJxD1q+feF48pEzVHxf6ZtDotC6aiPBpTXnYNmibyhxiWQ16hJGk2TTk5j49pcHznrISXLcPjoXjyL7qO12v4raIhVQOLpe8qCLLNZZPeMTX6tkvcoY1N+3Lg+clEl6S7CRFWURYeLjv0yT9uU/urrwkbNt+Ms+ysCjcAKz7N1tc6uFqHVQYvQoX32t/je8bVtNyQQP6rWCrvAa/vDNeWZ7nnOsDUxfEVIgQxzPmSaC5kFfrecfUoKW/lHUhGY0xBayFMsQBzRTW9d/5m3qdcTVj9/h9BZWAf9ScJkpocTjamoWmXZOJMEhuMGgWpWHGmUyE9msihjgijVMayAsVUeG8zpC7L6YqEHGeBIIiJpAW808RWYRE6HofNLAmKkXFs70Nxl/70AMe1jfUm+wKJJxLalbtlCU+ABmc2IWeVjgVYyuIh+SrLeyQ9DXUScL8SpKUA+bTEtCIgKOa3jvWSVu0B/3AqoqHepvrEA3nB0LSQxy3dMX8RpZJ5BSUMAqYumdWepHnuI/XQewBJXXw2mrjhzjlCehsGI6MSKvXqaNFQvncKU+fAmGIGsBHNDlRBk1eaU+3Gvu/yN+g7BRp1z0FUQkPXkZRjxEzE3VLJZQcFsxoJ5aAtb/zLKbBpk6aQYjInSGrQlnrnzuvOfOYV5qjQtT0XJd5oq+pYJmV39gxMgLlB9uLT9vNhCMpk7A9PJeasWPBbOUlxIJEBqorrIesY35MkdxrFj9WrFDCDCkeyg7Je92OW05tDhKwiEnIWGwKkRpXURVNugtDIoMtm/XAKxpYZnzkT0YYnwxifqwmBJbqW0PtTNZvDU3te/d6b0Pt0X6kNuuKGHIxKDnyDu2Nq9Y3DYcPzDEtHiWZFDck++iCdgE9esQsy40FLokvtZ61HRKCrLTUIfBssNEEmHqbqfik6yMHX2w3v8hqGXdqyQjp0LDb8qhT7G/2Nvu73a78QS+5pYL6H5r9inSqjp8DJNqLnqoP7NvdlQMYSs0W3lopkwOX8O678qIepfbHXEH+ZGCq6yLd6yUA98mJLRse4/6Keyoa+zBb+bnzYhVeddHdxu6zBFhgxX6d63qeoJ6K4wu/seG7C+x49C6HWkkMTli+C1RBMSUdnmAiFYPRAPDHtUHqLPeReao6lgFEeI3EhzfReP1gjC8KlrdklHZoSX7Bj1W0Jnj7Ymv5tnADH3FDh+nVIytDyo1grvA0Do1k1IpVgE7nU8bFBDGRZD69nFSy3UvJf1OWwFrIhmWt90NtqgBDvj0fNHycyDc9QRRGvvgGUshqGtX42vAsO4tSt1DvJQ6UkBEIc+aXWOTVa99+WbOxDhMwRyYCZY7zYk3oihjI4Bj3kL7zfJ+BKQWzHwKH3DpQTdqeg7ED9yoRnQNJDCf7jcillJGhJxBYjYAdKwAaBsJ18S6D9nXmo4/0Lh+nPA8d9ZmIKPXeTN3dBwYB9C0UZp3KYoqKdEXz9k9zMNeD/9a0DyAwKKOmik5CAYeynb8raKJhY0Hc1g6fuEgWwmDO1mktqcDtBQXN5nqXnccYk8F1vfqQz7LE8mGKhHfkgsgwrUyHhBBdQO9F0QmHPB9MQU/YoUL/aNBXi5wPbup2Oa7DLrnACEWxzoLQ9QcTySOhYFZXvgQXcG8zE6q7xukivOOz8H44YT7rJJikywt0kwt1viT6vxy5oDz83yTouI78Z9Ux4EDbiWewhiI0fXSWVKSd+nUSdo2ZnBazv9m/rI9l1cH06KAswFolWytH4qZgmUJoE+lawZcgBlmXclXECDeU123a198j4H7Sq6GWUOTmj6tmqPJxGlopoSbbSo04Ci+jsTiUrROSNhs29ox7p2O98gnnrWh0S6UopfF8fRVZG6/o0nMEt8YpJH0iYKH3oXtdURpgo+zZI0pOnsWBZ5ha+gCftYn2KLHKSbUFQMC49QBm31FifBBwFENHeL0iTllYE5hRs57GbQ0LCI/z+gc5v+qZGBUY9HHYBU100FmUDfBVpn2QrLNamEbNhNWA+ynkyYvoLkZw1HdlmJ0dBB4ZhdmB/+DXVx3/Te3NZymCwMGM4MACcAvRGom6bwE2eKhIqHYVOtV2TgmoQDYw3qHl2HwrD+tM2+1ULm12r5nr4QjRzihyLnP4/edfJtsQWxdvD9YyfJxv/OeGDXhlF0x59Xv+UVvZm9XWFedVoyfQH2I0ztSxo20r1ZKcNmYXJC6PmIRwpNZp9S6lYVLsiUe5jR7JE35OFk1Ozsgojavt1k1ER7IohaZnd7lG8tmreZuYf2C43UlDQOfKx3WICBfv2VmUMjfcmdMTRyJOZ+KZGQ1eolpSWsOZ4qVm/qTnxP/6pP528flWdyglLkU5m6vnxPWUUFAptK2lE3ulEYfoiUlKlzR2TZ4EbuZDYDZwBYRfpZzvraIWXfTgZGt9t5YGE4435gov8/AwAC69pNBjLaXTJwe7sSckCDL15JSOvAiswKkb8HZr4YSLFd4EOchsPx6SL4efP+zAj6uIh2tqyebeyKLeqWraPrvGNyalt0n0tqRy99JfD5NOIPi4QCuTSTZyCZN0z+k9JewzvYJKhG7Kvkb+C/VPzjt3To9L7d5CPHfeXJembyomMU6pqBrBpcPgBncB8GdHkXgBPdZwEt7v4AnFtN0Hgz+wBM4RpYtPUuANO+Bhal2K0/DeT3zp9CPzGBb5MOCQhmi0oUuC4oHJzeUqkCV1gI22uNUzTGm2htZcG/r5QHAIYtTE5JBObnIiy/e4LVSVwaKCltZzKRuLu3rqBNp/eIkDZylGZ5iKMqoI01UReLUOSCj7DIgoEucKMXV4qKb6PKqT8HAj1Djqx/H3a5Fs8Gi2FZ+QVnERFZbSKHHHUN4TdjKApEeG9djAnBN8VfZPXMWsKxZZFvEb/SfJZOfvylx66TqaA2UjxdEG3TyEsSoUQtvZGkAxmzSov9x5toHtyz8+LXAiW68vpsbSnysrUogBb735H6ym8QdV5goZgU/qlQSMj3zjAIVzuFlfZP67IzcKUqA9hWiySaQiksO6PW6oZFO+vkQXcTKJX+asdnsYO7k2364jUgyVxH4jyuT3jl4jOFaOd4PCYixU28cAzA9kxmxEccZ5W+vgP7GIguiEjJc8x5CBsyX2gGQXvtHjQN7C3qAzjYxrKe0y+8RXAt7c4qEQixhKmPGUrUVqHR1/z8iMlni/EVOA29I+fINkuIQEDH59HwqBSfmitPhR/PM0RfBOLM/nyc0Nog1BON5D3QWzrGkMLaEbEkwqTR+V8f3y5gv+n0zn5M850OGBtfAApiQVsVfwwXEJVCH4WQTAl/5dvKHUF8UwJeSWeMRFdgUTnArtnOOdusnXNyWne2c153bnJid8ad2TK4GVI/a0jjrGKyxNhJQC/g6u+U5vLvFLv+O8c+gM7ufQGdYZ+ANyA0BBLy/OULODoFRJg6VoJwIUpx1Q5ZlDeqYRIVFgcTza1wmBQ7Iff+Oo6b7nq0qyjgQSqJSbUwnrDfOQaHtLm1/1GHd/PueSO0kCCUiSxb2Meps4Bad7mIfw39a1lJi0VlI765sx+ESHyMMyLHtuOD0QTK2yLayTMT3spDbUne9K0rp5iUA6XTrEpMk0tzs16wkk8oZzMhe8OHHoWA0sJIJsVXdjWnatsyay3IZRzCeqwY671Eza1dvLGVDCRJOfQDe0TMcB+sHoNJQemqQa2jjXaNyVlbGbtDQ4rfXSh8VfcN6N4xFR1rcp5Z4Jn9OCXcM9NGjSWbZIrBesmF1/iN86BGWmtvuQKJcpVGyYqbTdqAscRuR7cAD1d0p9z5TtnBGAYDRwqt+9ySNJvONDrn2TsDj3pWzmhQWN9R2oF27vxz1ZstYWeyUfI8qFMm5r4MDo+Ctsr+87qX0hum3GVWMnQlG4XCKSnql5PcV/e1RK0sW6K3/viVL6QqwJZkrPRasrNa1YLJxCg+GZMCM0dGRTYrUwDWo88FEaDCcG70apOyr8mXjNXqk7Fa3i6NKI7DKxNmJAwVrMlqh+XWSFHUOrAlVO+1ZGKWliI9qia9ymoJ2UHZqqmWJNZPLdFzQEZDk2Q45f4dufuyS8o1FRlzScWW+ZMeT7YpV1TIuaDiCIr7ur3KycRbtD+jTZyQbYnxmJKzKZThW4vzhdl9lTFufS6uqRIakE5ZNJACeJEQBS5xGgvljbLLN12Dk46bL0dx8TVwgfyy8XfXztmllhRfw7TpInvu/If6SrqmIuEr9krZsr8Ejc0Ts7hEvkwtsUEfGUterwtS5J98OfW5N1wzR8RbUgdCYq9GpuZvp5gHNEM5lZAFJCgJXbElXuiGByUFsMUl/yzkL4nILR4EgzmP4SVD9vyBVOu+ppTAacGj+v65MAWLr55QTV9kMTCfw+GiTCPM25vmGY/4E9+yD9T4hx4XX8pG/iT80Mx8Svng1YFTYKHgtXYqFz4CoTLA647tVU4I7tyfqyMsZX3XHfbFqSVtvZbbn9Hy/ORLoKNYofGbgo28BLeJapnGfgPig6vMrYu9okWpg2IzOyG3fiXpFeW834Q9yuNjJRF0nRjE0fZ7vv05MmviuhRP1dQP13cpQY3Ikf2AJU6UujIlOM5LzEXAi7QYN+iv1OL4Jgwau3Tresb39peHUu+2w591fvm9jY/Ivs5d2VHqqf694D4e9Hb1JnH3/Sx7XOag75knrm9oEFkEfZOChrCJy6RxVY+mUo/OKE6M34npq4GyF8enXlZf1ZBQSj4p8X1PA7hdkMREmnEgCa4iE8CU/Bp4oVCI5sKRaYp+tlQKweAJoJHwJpU7fHwOEQmhk/ntgyLZIGJB6ASXF5aWA6pT76qitdCeKT2QTYcFbffZ1s/7pqnywq3rWziqIKyvGnWIqlexPNQ1nJ+UP3vNTEIzjQksk/Lvy7DvKzGlLMBK/bC2AFjt2Ce+g0kg8gXdVfVW2wk7bstlfOjQAniWAA5wENiA6eLHcmubmEzvObFM+m6z77tB2qlNNcF/EKZWYU4Ty5gjOB0uBgt0GiGcofPoxOJgI0rc4oZRvCWB88saKH8wK6IFCRf4WgmuKMa9kg85JXjvEFKptgC+bQC2ADkDIISw06Li6lgbBlzSOcTlSitaDvhmAdyg0eFisQYARUSlXyPXgqGZdImceg/s3rWzr6sweDPYfqBVDKbaAvh6ACJtg0lTqSZk3mJbZmQmr1qDjAD2hwMGW7fRK77mUitexpHlc1msfthDomF11HS+hC7iq4IvNJhUmg+ONqc8l5R0QmPL89cKWUdTS3zxP8T6bgBB/DPok2JZOob4BOVxrENbnShM98RMysmfaXwqnbBlKYEO54w9X4wABB1OY8eOc3zWgkCodEEh5HqSqJ+aWLVmE//JKkBVrlqdjiJD+Wp9ukD451E7eM/As1ZCpOO7NaSZ13mh8fqGkFptLBwQ5uZ/4mXwf+K7Z8hvL8UmOHxZ0xWokU6fXq0BbuFfC/Lcxv2btgYYUW/YWLekvdmoKxN6qXV8qmEZdfj9d+CAzJudUy91O1bu4og01lJkTOTFHFHRO9frAEkHTzydVJwAQFDCC5wh2TOK6+enMTnXwVNK5RvCOWAFB5I94RgXL4ALTyk1CHLVgmKpIH301fWB8ibto2hKqRhhxQbECESYwtmTffMwaPV5lDDippaKi6GcQVjSBboYG0AODD2g5xXgTQWzKvPV/4IUDNQtRxdMrVYCNU3lT7ZZT3nzCBBAYK8F8DEFjD3RHvLw3sIdSE0GBuhXAELBWbdzUzbxq1A+aYWnYEt7PIxyZgF61g81yJa18fRK+hEl8ifpxh+Piz/xC5QFTuGaOZJsaXYINUAved54PjbeFwUHS5w8kc28cYfGno4OJizliCkGweF0sazgAkhMF/MPxIfj6tWUe+Ve4CTZW2Azf+zx2dM5o8ufVzqdYIoJazr/+HB8sFhuUAJCZw7nm388giN/2eLT4QIzfDocTofzD0ekw8VwASqIMQUxBZ+gEsJMUTv36ivJg5fgcdKsCT6/7IFI7IlGfM7ZE0JF1ndZeh1c50uDytl1k5Gj+UagknbzWfiVteODp9prGD3Fgtek4I65leMugso978cunBIfI8221n9WdL51XyAVAoOdDcc23YDZPt2muhvoS+NhdIbUuylyusTq9HIafR4dP/1zwFurCzmnm6r14eC5Z5cyFG3Icp8oOmLk9xGiQ7ePyOWRv+CFxXxKHhWR9JXwYAj7aqzQy2HtFX4CAKDzUwop3Kj9nAr+BK8I6QgKQipCA4GIAB9BB09owkQtPHUtCgy3wfSvtCzG6sABoxRV4mtaLOZW1Nyhj+Xady2aLyn/yRJcP86JBX2JRXWvHh5fH0N0QTujs5anK1eD9TgfRhJQi3zDL8/hC/kPvW/l0yvzFWOuT7dGZWE4gdFVMT1mTkbBjApPlBihJORJxsYKbxSo6b8r2Ow9WrA3aoEFmxxLGinRqEjEp+FR0ClQN39bcNyzsT3m73wUWguBiACg+/yVXFrBKv9tCbcXUq5bz8Dppkjpq75IvmROd0fGWVSgyQXYJlmjUdOIYIfAQnCCHm64d9LUPqk6KO1NlLGPsiaBGjNqkikJxKGnpx6dEHNlRT7MBRZL1psDk4eR2gN+RXt4M6hZye2qt1iP3xyAkHb6qv2eABhSnUVPIfAUM0JHPAIAFsrs8V0BTIRzxLwph/SN1g9OfWku8e3rCXY36mYvCj41ooH7Y57cpc0s10f4Oc2+Fox36Xv2+QVnCiQEv17N4zMZZAhE/Z2259iqT2baI2Y86YwnA5225+mCdNl5YZKJpQNe8P2HzwAAL1Yz46XcICq45KiUaLaHEzNHIPyZX5f0fY21m899lfmKUfwwUbdx8cGO0E3mvTfUPUOIkNO9FDKA0ViJSQCz4h5bhvuCY2foju96LsPldrCrolih55QtV4rMRHaruo43hCnaOeKBljBczeXNkUm4E7CsEIgnWTyJHry2askAXIS+mt0TV/xV0QAA3W6/ay9u9c1uGkW+QTRnPMqcZXmIyAVr+mn7Ka8ERWFD/moxtAiEQoBTP4OmsArmMYz1Dmmyrt2cwUc0XF2mzHWHC8EeB12GF6FpolsFosagKaJ7Kz2/GlVi3QJxYC+R9Wslt/w6S03FSVwT7eXXXUpy9k0sEZAwcQZXhNsDTWX0SRffyIprm1dJhFynuhD2ObfW3jn50W86OT0J/r4XmCHpKqLHyQLjhhIcnVySdhY7Xv75xrapwWY/MFfwPTn1wjSgsSxdUgmDk7C9WAeMI8kjil2onrJLbrrkSXrasCGQ8p422/I3YfAiXoqnYd6LptEZDxLPS808G7YlzW3RG9ETZ50DN7Z7uevubJaamvpOn0qjdovkBBN3hkq8pcTk+Gv4L82LZQ6aETE7bBQJEB1takIqYVyKUPYZpkT/pbNOZ19smJMNSmTURiiK77wKlZvYu8LmXmQFWP7zwaDaHbgNzBdgNBa+vHgA4TtnwO9I5N2RXI7etwscg7GFisbJi5v6o+68k5pPCiuvaIPwvkjbzOn1smMR7lzRyUKHhGFpzmdRTfOTpKiTOng3ehoHW/5UFM2LkgUg2wgnbcjAmsh+y0zQJj03oA8HJVNColAPYW9cVszdrRntOO2c5OBNqqitHOD1ZP0TiiX+noPLDLTMsx+7FtpmpgUFUsK6clkVK5bnQTn0Dv1WRcoj5qmhf4DN6jPP0xBt/Kk2X5KxA7NmWjs+MBe/zQNFbF+2jvwy0QdG5m6jmaIAHigFhb5LobPU1/My/2TeurS61yasvwNNbVkdM8AgMPSx4oL0yRm1DPqYaWP63AR9vGtb+myCPnW3eX0OQV96Wre+GYK+EK1p3xzJm08RJniX4vz88O5aiH5EegRIWr1q7VMNjO4zY8TcR51Wb8Qp2sQwKeNCUcCG4X1Am0kK0Tfqpw5vLMnjBpLS7ZRUhu7wds3dlAu2/vlaiS6Q/s06h11CjxfxcaoUKzCcx45U9M900Flq4HaXoAEArBWC8LFJcl1vnB1BVAxuZnq9EbNEZ97cDDQ71cG+pUPMXnXtbE1DyZ3rkt0yPYWECgcR1x/UAEKmjYFkAgh3bQukI4DY3eZBLgLIPa0bNEUAmWhNoQH1On103C3+/K2r3vy17GFlcQub/XBW/focHAPICc6nUOAtQ3c/c2JLbrAERGZM0Lpy5F5igG4U8Nm8JoFojvsJL5M/y/zJAHjAg30e2srcWH5yx7VFylr1i2/ZzhZZkrIYSUIDZXLX2ofdKejVbE8P4SFaX9/O4HZ1/5+JuqXnUwfAtqGpuWHvC5xKQ0eqsoJAsLsJ5iBBYXlCAABvQdDJPcQYEAE6/9QOxDm1HaptpH1tL3YO6dAW+UAo1ji6WQ7UFbV/zRmoMWnr20fCpvF1ydcO72AMXxTviK93PFn74/M6cGg8L/4SUpNwwwPRWhMu4PzSBYGIvWfrCpnu+n43ONzQ3Zk/fJxmIOd9zufJ6nSP42x+nd7qB5jucv+YfcTQ3eHW2gCAuvGwtluFwQ2NkS/Ma2h+IvCbm8DcRuNyNZM9JfrMp/dmxbB/MPpW/vz0ri5dSwg03CgdFRnOih9cfEaCwD2nghM13EJ79R6hw220qMI4jTskJhIFOD6fLOn4CFxLB6rZBCJOikDM14zAhHtkDEHA73ediZn8qdYFg0kQ4veVe19nci5/dxNv9XfesugnyIdnOfOolbWxdO+x8K1Vh8mlxMtx05pL1G4i/gr+QYsdFK67TfrGLgV42nwEXlFA9qYaxEUB7WxqQTYU0N2mPOSWHqb8u92V6GFQv9ceTMFqXm4COKQ+yKsinh6LwZ/fAazWf6039dGtZH7/MZKprOkc4TOTLuBLVfOmjzX1OmDHkiQ/OfIHQN0bgVLX+JCYnHC/XhKS89DfbylLpxaALXq63RR6Hdaro05eyxyGixAO65PR7mY9V0iC3Lq3+x/10KBo9f65U0d+L020uPWOAMCdZaK9f9zrNROd+W3UJ4r16UbfnQqvELGaJe3VUPbXoL435ou+fzNxmkn96ZH3j6aQDix1jykaDGOGvv77oexh4UAmz9433Levmf0wG8+yc6l+DfW6db9XyeWvUveUTUiElu5dbconDnSvsKUKocJjqNTjN758m/v0EXl8NLp4fXpIEAHEFMfGE7oDWrlkQZ/Po2J1VRArAoi/nWy42Rbc8Y4AYEqLTvX3eoct7H7EEQV4rpTn0+DYhyu9ubVjWDPvhLU93kHs9bVwewDDhEv3POHt7LGDRL1L0ACARGKYBOcEJ1mFAcHdW6wN66vDMP3M9kxypRPQQ2XF95PTbu1g7aAt3TVPpRVEdmvJtLx081zfBkemU3w0Uyg7mi4hTVzCFr/uzbuyorQR+sOJaNI07YfeeCT+kO2QLDmbIkdBEaZZpTRxoZ2VJSZ8ixPahjMTfYjn1Bi4QxzlmOtyJo7SQ0nOqP2mKz8K6wO0v+3Pr9NmPctarUhmuybxustm3pwRt4U3XZ23xYB1Z4R598GfZWqGGhJXuTMCJ81CrgIuYGVuQH+t+y6oquVLm7wRNB5Kfw1Vg79mfCcKSFEWhPkO/nnQUa02yaStZCVle9twrJ0Qn4Dhxto9COnri5l3buRlSuCV5bDJScQkAbjcNSmWWj3oYJk0yZQvJT2/YoagJNO8d/cqfIpqvRSPdPTw/q0DPyDbIx0/oj8ryM9Ds/3se5JEONLqIfNfN39k/Sck41nltNPfT0eoWWoPvei5O1J3JG98l5d9XQGUrR9v8skdAU7/eDAwfzoVp5zDWL2qlHR4aw0o8xu4LBIWahVb3xrdY3U/rMBWW4UtkX/t2SJneC67unXOuL+WoV1QW2HXVnhQhqqJjdg0x5CoNpEtDZYzkGCh3XN2HcRyloIBAGyjZyaQbK+kpmKBskLNjj9sMKQJt9Nfk5iD6/O2BpoLa9i3hZhb1u5sB5recV6G2WOcbhayR3AGVuZ84Jasy52B7bR5rhq+5EIHY66O0WTgohNr0IytX6Pzn82lO5Pj4DZsqvvqF8pX1zgFiy92MTHTzFutXSjP6x5yRUiLdglda9JV3UKRebjnO3O8mtGEpg/3+tEWO3VSNBow98QxxFRb6m20rTF2V87GETJu/3C7EHanrSdKhGFw6Drh8Lpt5O4VoHiq6lPWdtQeZNdK5Fq7t2Ta/Onm3XzLZJhmXUetz7pM473r3/Ngxg6mfyDu6tqBuzn/46ZaAFIxCGd9OcrrmQYTWPdQ6dPvOO9Q0t6ah/IO7L8LxFEuvNyh4ui4VjpUqozjPGlAi/csEW1L4/ItJQ2VKu2Mg8B8bHLA9tT+XQ5Yu4vapWamWn/HXTGuEHKBdyV0gx7Y/UkDu+2QsKaBE1obNge4UevCHgK3afPYa77EvisIsP0oeZ21jY99atCOjxomXbp0CP+OIWojqOah3Fc7Ptw/Z3ucENRt/oTu7V+vrfvwL12zwA83rNQMBY2qkXr/G3dWIWGVfxfTxztWnIgF3Qx0hVxWDgrycMt53Ic8bV9QpwxBN51OGAAJdzqUMDFzgus1jJCss4fjQBjzMsTCEmx1+J/glnge3v0i/ZfWfw4TOuUAQxzSbfWEESzdc7GSf3e/tP7kMmE8lx2Wl1djmpDsuaxofeylk6uRUn3P1RV5tNF2FWgLuwcrvA3FcqgXDhDeeYIVIwH0q+sBcAQQNh+zntA1UIklhWbD7yHBWap9aHcHnhhGrEhHADAHFh6fG2SEI2Depj46r1hfr1+DC9+b5DUeRxlWorgfhYRAMTaueIhzxT0/o6CzeikYAHAO09k6zM1ce5VbOtGX6elmfqFunYzSZhGXeP2rvM5fp0VfMhH8iM/q++1T7zMjvNLGq77GtxUk5DTfShc7jXcuFq6k43LugpTtTrRgek3BNL21eW56lasMjDrLYDU3SbC9jPVqgJY4HGSATI2eZLxRHbt76J1qdswjQLGsioHIpQDFrGJh3KvDTkap6ncWW5yMUvOqdmYgRz8fz2wcR7ggYxe/Mf8ezLRz5+feSh19zQ78H1WkPNGOi6anWzbV9/zsswMAk1/Q/VF98LP7ICi2MyMGYfjyXAhXD6sz6vCuonwvt542Mj555mIAAMChF1qextCbMMFWgUSZzEe8Rfl8ggcp2D2LwQAAtBRQO8uqF+1sWr0zizuC3k5tXhPILbh+HSVoS67dAQIq5C6RIMNwQSwKMts2xq4d2cJ1mBrbYpPrMFPugu3u/kzaGVfH40XaSyfWs8XIu7wHu/IWsyVMufQn27tMau6ga1x301FEXmuXIwQAxw10rHIPz16kU2L9m4XS43t+FHCiNbi5tmKRgbbA9njZDVzi6B4ciK5t/7hoiNNs61UswkRfkbzRjkI6qg6T6MnT0woyu9LDg+E04AAAo1L/lBYm1eFtXpcwhQVRMKu36Z/L0e6S8NcLzQCAHbxFVOf2qLdiZIvlbZPOPxcWvFYdelcBR9XHNIC3+x1pAqzc6qcoJNXHR1LHgFptk2FAt3aZRtKY3+kgU4v3PT4YH5zcB2nkYFbzITgYih0dyWBcLPhsSKW+xwgmdCR40FllwEcX+NJyK6u/Ny4Pq3uUDxmwakvVBZUl0ar0jg1OPT748z/OHsb/N/QQW9nIqaS3xGeLozO2Yyn+Ox4zRMoVSJtBkrPcc41GIJFzgg0JpPWYdqUkl/Dk6MYxkbRJ0R49xencyZ+rwXV7A2EPl5nuLHAKByZQnnzpVkSyLpUMC0mLF52VOIkbmrJGjkDz7L1zUEh1VSRcHkOHXeXRrfZg8Kqu/FXXmgdU9+F5BFDfAGg8oRRQiSWFvsZNz7EX3MH5QnUv0RfGkhhx4yYBwA648h99YCxDF+aPC+EPPYOfz7YgOd5X0PveM+rnVYeeYebN0cFxLgYo0g1OKQwAOGhLxAazAn7dt/Vi8HdjwvO58/2vN28eex/g8+Ojzpg247mlzEXvHnkO6L1a8EQ7mfp8u5/bWN0WlsEAgI39HLsAKop0yqZxASEmnDHa2W0gvVbnDSTEqcfGHDMkZFK1s3iyid4ZXRAUAPWp2hjUFdQ3aFvQCNS3dhfQPCT66OqAGiRQ5y6DOcKBipTffBT4V5EN8S5pI0F7K92zQnQrUZwLAACcQMfuCAUwxwRFAmky5mwAzjB0xaAaDWEAgGuB6dJXy3HhN4tWbBccuAUPWpzq88QDSdSwuxugUbdjErpyuS4HNpTVcZApjmzAm8g1tDJT1zcCMSfrMk0o53EXprXK6ZjtDN0tnOX0No8dDiMJiZwlbBZib0wpsucGBtOlUcUMkHY8pLbtZ85Ff0GLW/5oYkm7Pl3J69NPs3ToB6fyNeec9ryRFkyjVxU/1ESapHn/HPpfIC3o6n9ga0B8t9HjaA9if1aBk/pt4n+TiT735J/uB3VtBZPBIkgcUvRt0pdw6AhxfiTbW7rS6i0Fccd6MLiqtSpbzKHBdWEVpsteyZ60f949yLPd1qduuSEK6fUajgI732mg7x6Rp2bP0XQOkKoGHAAg1WDQ+gULBjAKcXgas9qGGoCZze6MgYOGF5oBADS+XdmTpX9ZZ8zdYMOdsu6PDaT7tgadK8jorY1RBeDgbuQUNALs/qQlV4WRuG8Oc0NX2hojAt3VtphVkLvlLpjNTZoAO7LR7wUGJnmwLdDBXcYrNlgHnSB2E2KjLytsEcnWsp6eAjtzQe09gimCqhiCtU5lH5p5rUk+7voUhTcSAACmfN3EglP5WnlOf27UCaZ0UsUcJ2xFwWDKc8rFcC3HRzHQ67vA9PmIDZJumwMbnsrj0q1kxpdKJ4bs7Uusd8EMVYbh4AeBcP2f1BeHe7wGrdFkwRHt/Qx55GI5gxWbgWpnOx/NFqHnzk+1WF51H55HAHUGAMcKsjtgicWFdsHqgYvOLvrqAhXcYFQIPP99BACpoF3nP86CkwxzmD/qgrRs07u/vQ323ixbI/agZ9BkHWPhszOz3saCo5WDCphmCX3yYwMFR3umwTg3yf5t+GKKnbBsVgwbwAunu6/dLAk6eI2PfesKE3IlhU6A6alZGhR4mEJn2spewVO9EtdXbbp+gK4Z+3EXxK0rn2diuop4UpXBlfOT7Mm/h6Cq0fCpGuuCMNbAF7p/jYPNjVNqtzTO9tehdaLuTGqKWI/mxerjx3dlUfrb5k8odZ1dOCA31SR72qON0BuV4sZAXYnwU4lz9CbIK8JUKrKxzJD+YO7Oky2gbI0QVFciRHRbGSAg2tYFLCboQMbADgNOGTuGA3AZMyzCwdv87k1rgz9fVet7FU8S37rZz0jeHI13tRAAADiCauidCSjYENwrDie6eznGPAIgwzy3Ik4l4u+cDwYArJHeLoO/ZsFXM9MXCsX2ksMtMR6I0nKmQs/QV1ex+/DEyp00dHCZL6fjXiinUkYIFPIPNA1amWFD07Z1GQqaznCGoV3lmDsOqzyj1gvshC+x9kJUtSvFNERh640iMJCmOSAAyBpMkR9uGtracfuXbjBpy3JaUBlrMTbobns8d6AspjsSlGq2fyGCDHptvWnCvR+8hVdHMfZe4B/tXTon74qzugFIVLmic3EAANPLWhhy6W39XtL1Kk7XkgFdwRCzThHvaGbvgMQ2mQEAYoHB/g7Gl+D9uTjpH85JOXCH0iWXx3YEFZ0YPCv/rkHMVGspCbhJJq93UxmzBuS+K4UHptfubw2IJiNREcTE2mgaZK11cQ1IFGNwHwNj2dFgGFjiwaMDlr7HpDTIbhYPoggKubBEAXNb6rnxXRTZi0SnUHGq6qIOZjB9TR8BwGWBHRuP3d2sEKfuYjkNJiTjBSYNpHlXi5IJMMvLZWoJ3F07FVYBW26NtmuA1bX3225gDrUVVzd8jD6GKqe/rwqbW/B0BaH6A/X5+EICqPQAZE/IC9RiSaOn6fdQ4CJWFGgHo1SMqOhHALAEVzePfb1wB+OrgtQR8jmSTztL6bmcWLsArN9kc/XJY/fymgogbeUQAcMxz8eHnEnBGSwGAwDmfDqppmw9FWflwCmGc1X0volr9L5s5epn8vDVXuXB7Wm1jhZvVbGz5oM7/7t41favd++//fife+PD3MryGqE8eqfrGCrC1vDB7aZ/Jj9PVR/kUeB2m8EAgJRUAHv1BZwFvDTisim1C8yoPm+X4DZq2M8WlqjduRnQFAvJHOgbHTN6omAI7TLbDu+ESIwBc0iswXZYhcRmeSwLJG8Y8JXWufUDI4SzT0KlhiRtLyp+0u0OgVAdPDHMSMk4Q9tKq2OnGdr2uYJ2wIa93fI3DnPv6nAqeikTPYcfLgoDAIb0jrULqgA4l+I0rJTSalOfFzZoqCJsKjkXzc4FS7U7A1/8jPmyBi0YIQNxUlZm5phMVFqXZYMxGMOK4KacnS03uBOHdmuIJKcuHB6x6+9g/D+JsaX5lBZm/39/j/8BVLxy5pQarOp6I7QZFKo5IACAF+yJgSgmmpY0t2GFC5O2vOonjfFUSzB+8x6dl2D0ridY/z1EBbpiPJESKuiKNp4zHpeJV1HaBb6qAHTmZ6n4siYOSKIZD8NOmtL85JCj6wOtrwr2ybvCwo5Ar5pOAIDeYV/7mU784ZCoHIV+GR/CRFAPL9QOkByvHi0ghWdbBWq7yQwA8BKc7Zq2awCd4mMsAXTX/rkIcq8O3WNAdbUxvgEc3o3GDW2l7f7CeVOm7zgk3l1x0tbmHHAu1uXOwNa6C6kaZKrjGgVtZIpwggMOGOKuExMM5m64Kva/S+2MIbeM2f/f7xOhDQ/hwMsKWoSAas4DIeP62yK48qKaWhA5E0E3ypPl7xxgd6EAAGAO5GTzF3oa4lWVIJureE1ZSKJ9gdE10jjWongKGO9lJOVl/K7j/0W2bPvn+3Drf/Zg87cglrtXhSH+2u/j0eUE7tWHMJcWaev2ACFeKY0v4G8qGK5IOHMcvGEE309e79B28qscVtOAbHFUaAOitQzRWqgzcreZh7mtc89zi6zkIcitFNX5YABAHCa1VsHVm7mfqbPScKjh5fSCJH6tof9L+vv6uPWpryoJez6948M7VDedwe7TOwHYhCk4RqbQefQ028JPLQoDANJshCnrC6QDEhlxk46XAWtX6F3y8EFvrx6bRWbI/jU5A8tPcj0p92AAXOiEgF35XByxkDaGPYFYaetC9OB0RKwhYyAwVztJYvvdSNHjYmFPSMd/1inf0e94n36o999UHX7hvMxf+DFpaAZJ3DixlIcp9LeMkGwUlMDanPg3KPO7yidJvXHRM51hTgHm9AInwyWcx+nMtBcqprbQmQJxFAy6LLhGeoPfhZO3f3drbiY7O0+F6cwFJCihz3gfqmBuzgkDAManVVXL1tXYpdNM9sAMYNaEc5WLtbH2WZ03Ja1vath3ho1Nj5U2c1LV4B8WnIWoF+VQRBDGQbpSlMZe4NcU9Pwkb6gkkW/4w626ZtNJwsEQdJ2MuILsWTAF+mmyLvkD+FT+CcF6KjzIcWIF5ilc6IJsyy2DtpA2ZtGEttJty8KAtobuwiJCLrYdoNWgy7Wfs07s6sR67kNHNlTFkhFVIa+nUsRxKatAcw2McVFk5JJyeDqwp7p/rgAy8tsj+Dacpol4U+wY6DLrnxx0Pb68nYJ8ncLtWIvG1B0GdtEiNxu4Ga4L5IueC4oTC5idcW0bZsYWTy0ryP5e2hp2cR5588OvEuHeENRY/wd+gaeeWYu7vt+IW9mpx3H7/vE7nuFhh6dJ+hk2kGmcJwG+Yk+Lvxl6ssISfPkkku8QOKj9bMCC7cFvaZVAmUU44kCP7Tdfq9qV891AIPcirduHo/6FQM3C2UuI4Qe31FqOBmirjr3x0zsV+kUTqjOZFwuDbuIKErqcOddRgcA6615enHLHxd9maKDSF+uQPaWw02DtBsA17AAAIOxl9IuZQF9ANG5hrBOGxau3Ds9laKfwrYVmAEDEYKWKtjEI0hybAQVV/k1ABbXo0dJb2PNMkRdq8FUIc1daCFT4O4pxSx8/pYAf4JsBfOwui/DSrWrz4QlTBfEuVG+mVeWU7jNJwikAyk/rmxAKeqxL1NmGIQZwGCLsNhDndxRmvD/xE9jxX0Em4e73sSWhh7P/UEamG5x4W2wVR7nLnBdCOY4OkEOCxoXFAzAs1rNuYJuXVRYH2Bo3o4sgxzUGvOEiSxYAgK4x+f3x3g1u4To23FBX5jLZFCCOdYlRsSBvuwsldYCCrctVvNUSqzKuu+huF3KJtkUBkcvY2ieDPHbXY6TNDx+1z2YeTbjH/MG3u/tP3t5A/wy4kmwmZlNnR2+6fL7RrqjgVRaDAQAHFWxtaf0arm1WDEsK+X08a/PeNZbeF5+plr2+qoPbC3VOiNj21DhtJ3xTgatiR1OHtQK8YYNSXQBn85waBY0UJGsxGADAU4HwKgwG4Zvav9S7h5W2GH/Wx6FtviD4bl9sWIfRqM0p3N+B4TXUzU8Tvn9uHpmlQtxcqqJUtOIL5K16mGwnjg2HwpsiPhLsuo/p1Gmy5zIOKmiKih501YqKtFY9Zks2r674l5Mza8zV7P863Tf9qtocqqPvE6lvjPrvCS1CMmE85aWQGrogSERZGWnwxbZFrsMXGYOMKVxaynMOkIZspgcpn3msxvlWVvKtohruZL0wb4X8xZvQnmjBHQnbn27dMz0hEymQuGkAAEgWuJLWucyEOwpcDxe8bQQ65z4DAv3L8HOVd6+0qapgMxgAoDoVj11e10Hum0khZx63RBlVYu9UoXc9FWP4V/rqwNxExZVhNBwmZ4xMXmr2uQPtqhZKpcMMCzk5YuzpqLIyZ0DHsXU5BzruMIbzIM93DtDNlfLSdmhvG5CbxYlMRh0qOZYj5Y0h9smmUJVcsr1kdH1xdH1BdH0F0/X9dM02mim1eKOrJJrWiHLGyPaS0vUZdE3+c+J5S7f30zWf0lipRTpdicw5hwyG4EoTp/9qFFmowXUrqi5sIiXctrUgMitgEAtqjckGxMs5boKPauDcUn0a/JfNhvXuDr4Hth6qifu+cVjpsFpX6iP3w9nvMn6kutByExbVhJ/SNdOO1gJeZW7Ipz1W63zQxB3qwdoy9QaEqu1fHYVp/Gri/e6KOHn7adnAtAi3ntbhfA55EzzG5r6tk7c3peumADcvDO4wx//BTx/GbV8WDUzICZdkaFU7CrP6JMwdz94juFSDGQBwDIQWOtqAIWCtRslNnxn72RjpHylrpqZuJwPkxJqzqbCayr+75zVt6F1bMjW7qUSonjXO4tTpGIfMuaAslMgqbJIlP2Bm969s0afumU7bAed16vPQ6SSm8SMlNftvpt+Mmw2nHGGvCborDTRX6dNlr4W9nW1iVBqhGcmkU4A2Gq3amskcNO6zLjO9ch6iMdtdmGFtckZ0mOYE5IzPCZ6LoC0XLYITAySH69ALMfFlhbuGeCLrUadDt5NafUkVYwhKMQ1kR7Cb/NYmobmmBQAAg9HqJrcvITR7xNXIdIMYXChxB3mqLjG+CTQzXYuypekkgxbM5WrNbLSKL7k7CcEVq+4TXaVAcEXxfv1VZIJr7Kpivz64q731t+j/Fxo6l8QIL0AqRH8oQycvx+/ti+LoD5fGF//K4BOdT1Yb8CgTLB5c9sU2rQo9fS9Zv5v0uBAGAKS1WgHVuqarUe6NRjxCD9nr4mDgFzx87jRotXJwk1ITO8lV8B6phnXYS26ttapiQR29G6EPQ7wOgYkwAMBeAjIGjbaqORvgdN6Yw+tAsxWdUlS1ZPAoxBvmXbMYhSy9IR2dHGXcIZnaSWWxi+2kFg1KnaO+r8BbDTTHOuoT5q3GgHmUd57xSvpd47IX3BH6VLs8AABMo+bIMw2h5KDQgxg6JFMtVfJcSzSkn8s7O2XgdJK6JNZxbPf2VNhIrowqR00+TzroSXgd8Ow9j0LFHxkENkjCCHH3c37FPxcyK55oXS4AT2IMF3LnYmkCraLRXlmdKsfGsf7aJNoDp86UOoRHKpFVj9CtMhGNV41v1z/Inrll6QkVUakZbHOlPsi+t8gW2cecWnZ+LXuP9xKXaWc20ZiarTdyKmqGIQ4Npo737xDE9oXNWSS7bS1UBDtljaVFqqtMN96CufIkFnfH/qEKeZWz79wQNuQeUjkaBevufHF3x8nbKxaCFaypYbP3sUqpw3upuIfcR6oMd7uS83UAgOOKihhxJWXDcGXL1sMKctqZjvBq77lmAMCh+HRlW8IKTLYNV3r+X9/993aUoiTOkxT3rkDf3vyf+XuFrwKNetwKyrpbi5mL37uyfI+gu584vL2CPe/n9g+p6/ZK8lvvL3EGM65h3/n1lmjHmG0isu15X9ayVBOu+jMGSQa0yt4MjT/WLyP8nRLDJohSyuqdyXQLbtsN3kKBXbnbsBcUwXUig4O+uJwa787kARZ0EhHv5qIqNOjMg3MoFZH9V8Zg/DBPs/CTuGHgzR/VuAAADLa3/89oo68mV82D8cMcdAYuGgxG4o/DGhMACMt6j7LLU24G1vG294qtNL7OfjOxwkKXmXQVeJVKlN78UIqW05eszbSYwoX3iqAYXTQcCwAU1La2n53dhxUUOnr9O4hC1cNOsw+D3wAYL3TwmZFby4HQKCDI5I42+6Nm1egSFC+FAQA76O4ZhAAT9Gf3tufFyMuWvCbCx9+TPLq9NFjpDvZQvyLUayethS3ExXjkYr+CDltjn14/3tf6LDEPuU4fn5X2XBW3C81zF0yq4vZsDN4xtBZ0z60dAmu9qhaDAQAHh3ZnugtsGKG037Oa3r3Pll+Um9J8FkLXqs9zIUE7JZ1hrVzH3ESFbkDuvmPK9p+Z9uwH3aN7PJsq7vVNr12XGsSZ3Lp8MJNv/FXyVLkgXg3kCdsYXxvy3OoXX850St4uxuDLZMcoU4ADlJ7dZIrLY4PKISiTN6zw7qa+92GMz65grmcc0HEk+/cx+B5Jn4K/N4xmuXFldyOqsWn6kHCt0FcFP9XBzfcT+/kBXXUCnGLACoHI1sX/zqsV63KPoYQG1g3964Dbhv7VEmevBynsEMJs6aIH+A3YOQBjKIwXewqwhifIscrtDAY/vx2l+b0oHJ5DMsSJtRjMVe8PXU/djVB7XIFAzhYMeDSyuV3urD1142583+I32Z2NWc03BJI4Oo3ew1QLpql0kLYoFInsqzpYe/No6WJL4Dn5wZcML+kXj4sOt7LX9Ql5wU7+r0+eDSRPhFs9+kwzH0bC+4Q/pBCV/N9j99bG99MjXrah7FP888CcJRPL5hfHSwJBMXaHLgSlY4N0IzjVaoznicLGGehOWry0qR25IAwAcBzqHb7OglNVikjl5MVzhY6KDK8zL7uBMjNd8DkvInPTuZHbgrBoZ4BVas3fgLW0C8KuDiXagLW3bQy7loB1pH5h53pMxDpdY+cXvM5ujwPEprnO7qFLy+ZA27RDtFRDm6MjtVeBMuxHcppXmih/rS/rLcCctbfx7yMZ15v9SO74SiPnMQEAa8bfNMjlhDct5Rrvgenh+qeDXJqkLpj94kBMsHnaGi9trhsow2krprBQZvO9NzVDoivLjG2I855042Qv6qQGo5Mhh5/5ML3dtLnZge3OzGyH0JQryQo0I7gZxjW+LYQ5bWI52VmIp0k+Fmsz5PMLxRNdcW9QX9qJWIyVee04ez8dcvZGUVGVvkcKMONiZ7PfKgVm1xRcRheGApmY50MVnO7FYADAjApUp76gawCRPM8MvUGNnpbApPWVbtlHOz/R/mwbDbp1IG1Gf58TPI8RcnXELe94+9Qy08Ba1iXV6/hQ8iYuQwrQHxlA4H66IqtX5VibvGGOfThx5zD6y/G3a2GBG7kie5xiOfR6yhlFqJxXonHYV6G/PExfYCdvz6UDXYQ76syf6CFdhsdA9dW/5O0PcpEcBK+0WAEAKAHI6R1yhaEkiIUzSGr1TAM6BRAwz9VrsGQF6akykJ2bZD9B3YJnA0JEpG8MvbBYURHtVuglUAxXw2cQsVxJkYFwfS4Bu3CvEnywDFItJBPx10XMrDpvIz6qaOmFgXLEJ0wGmFVVHqhfDkdWnZysI+WchhO1CRrFpYYEtq/TaYqODxGZ5eqjqZUd7umoAICUu/DDgfPwtM0T27J+eeck+c1z4by4mQ3luluLQfW9RMBL2We4wPOaxnCciCR2ktU8FNj8Er/D/o/SH4be//bMaS23l3LG1IsVvXbULkuH3GzimLOp7o4iiFRRyXgWYAgi1VFKg+lm6J+s7cfOJnpd4D9SHW5RGABQBzTowDdhpnLYEjyPoZfC056d5+5GrnjrSvjmcHgxcZWt3DCg+GSGZM59b1DisTPZymsJIQfrklWuU38nU/qHYCyk1MgTCcO92bNlGD2Ewz/FffCn4E7Y9xMfuroecun6/G5w9+qUsx7/BdRn/2A/gOe49gdftOrTCi8BqAHSb1fOQydWHq5SsmL5ejYbTp5uaGQG1FxuBAYw5SccEFU98jfgGwcWPaqaSnh8TDp6BK7k+eWFeP++s3kQ6PK7sSSwZOMFX1iH5+gSOPi9XH+6b3Y/cBe/Njjxd3h9Lub2VIfg7m/Wkp+fFaehNuqdqY7ORDGO8ewz/p9h5vPT4qo55YurCjzaLX8STLKf3ya4xZamKR30krko8TSYZDFNOu0u7rmLOqZigLFAU5AvYd9lS8pn7Ic+RzyBW5/D3K5n5gsjJ6Lt2NBHfV5KuWVZWr71XOmHmOFbXqFzXlvpmWjWXY6UoLYL+SJh09cnt+Q3hubO8COP6War8uqA+M9XqMh1l2+vFpfL4TU4H7gWB1cBfE7g+UFteZ7vI05o+u3xUsP9UZK3bgCNNCoAAI0D6NY76sWwwgYZaQyKByN1wjQ1oHfxTuXzPe7tCgq3GAwAMFRgKBN+05NcZkfAmOepBTipzpueqSzvJEXPhN9wHt9IQGs3tlLAJ5EEH6A72McDtjmqTJBB2bEBO1WKjpk1YIdWdMvCgB2NYi6sDNhrt25EiT9gb/afYgEQx7Vvp94/l4lQs3y6CpjUYRYL6FszcVtDtcmxChhMZolEADDXAGfpIG4dgHO/+42ekjghnfPv9q0OWvv8q/5UZR8eYx/f3Bvb+L6w7/pON2u7fbO85b0+3MlVn3053tMWO4O5xmTC1TofFrnRPXjqV+QxerGjYvs5jkrsR0f07/RUYf0w5vURO62d6WOAT+g4YLNWNuULi6qrWhCPU+jskS+PeK7S4LlRhzWPfrpIJ9ILzzZo5yfpZcvwbpisaQijY3lrQK64Oq/nkHdP3AUr4aEYG/qyG18xuJYrb+j2zYsdi1sFzZjG586pDdm9b/ZVu28Ca8fKT3aktXL+4rMD4H4jsyPodkZvG7OjPnfMKFeh/TmbB1kgnkauWMd0NbZUxN/JXs5nzij+XXnBF2UTNX/7m3YL63UvByhLwwXhxY7E6cOb7J8rx/4V9POIDU/l+xnxOsT4TbQn6svnbM8VFhiirzobqG7CMllCe++j7cI3F2l9Fnpwe67vKl14wWIFACDG2yl0vCDbVVBV5mBCT8efBwLEyqMvkagiXnxaGABgxJsqw98xPJ0dgTkzzxVnlhvJ2jP0dummQxlAX+Xm2ef5idunR18xMJThcjCJIR0Cbqf687AUB0F1F29XYG9sDGpV4AjbgoYKnMQX0HSLaEPrRhmJjq0BI2ANl+jKA/LuN0k3zNWcDWcUnDBQ+h7AOTO5krUrz+cekJFCPLOL/0THPo/AKTDmixuvK0vq9Ulp3dBwnWkOLa/4R9nkfs4U+aMIo00vYzBL1SeYrb3XoZplSZPq1Mvt2iUSAcDShVxM8UOzkFaK9Q8CpveiHw20NW0tlmkafNyGfV41X7yO/PcUnp3XZ+c1DM43ifNdG/8MbPHaM7ctvH7Bfe58+qy89rq+m+ziscCOY86oWkGDYscthaWA1uVBK5rxV1p9XuVEpti6T79c8Tg7i9Gl/YPz9uvXa4xrQ7a9TcBvPdn3rNsxnjiOveaCMABAc/iioafZem8NEzrTrSm8MECeZ+JARW/YPKvz4gUe8cSeqK0GiQz5/ETRF6Y8InJsl0NmmKSmSUfPzGTmhZOJe7MtW4OchAbDdjJnvzG7bfu2xQH21EJsOTxPXp8nr2ExvnyIdPR26W1/eH5x+D6ensGb1zDs4OA6HwX4qryTBV9CT8HeStOs6KvOZqiL3kwhONHhH+b156T7iGeuqDX6s9CDb73cd5M5wHONCgCAF8CWip1N5zMV2J7S4Pq0qkRnTa1mH8XLjT6SpoF5dvCLXtcnl02dqpxH8t42gwEAvps8UZ92+ka2PkQKETOT9WOHRTjexQxntaCiMg97QDODWT2nPlXwjN+Y1fcVA0N5UfojCuMOSN76sUtoaYQkcZ5DsGRjMJweBbcIz226ZcYtwteaC7MqsHXtG6sALNASsNAEKkiqDCJpMGIJVNt96k6qusBNfp1x5rVkx2sHMvorxoZ/qfU/87VzW1T9Hqi2arYe58Xt4n/WAYCthkgunYswtQKy/iD02p+bEGyVpIofsiQOxfsnBW7rgr8iQaruFF3BbUh3SrUU7SwapCkq//ZDm2P8bd+VPw8n6NvuWj/1sZt6S3d2UOFzb/eMqosIfIhLKXYsxK2UBuOkVa1BZePpFoUBAO4YpoHRVhcsm4VdjefJ6W2KNzo7b6NS9I7T7Znw9o7D1lSeBafbBFm3W5CCM9Ayh2ZhH8yWdrkwmG2D4Qbcon3bPnDLNmLRzKJzqCt5Ps+lYuchzZfhu/7UP+Hl9g2YZmXOe1PfTU4BaSxWAADSzb7uLTXPFd7aGLxG8e7Ka2P60duYUxPgqIYwAGCKfdsWB6xcYPA2Rt4dkd5MZR4xM4ArA7QKq0uxr+YniqC4snpAsQ2CdBewJYTHQbA4DzigBqeqmNkYj/Ex+gWHh1HKDCfiYt/YBnFjC9iDgqriRCmDN7KbvaEhH7bV4/9o8iqpt0UijZeK23fqXPbwbLEu9l5qH4qOLfxsXPvOyZqOi7ptV29mkEylzceyh1rHKduSdPqEVtt98zl85h7vsomK8+M9/w++WIvOoaq8J3yCf7UYvCR8OKm+lE/yGH2CB+m5Dv6JidLoIU/mh/hiOQXtjzhatQ85YkdsD7v/8VPmJEog7ZUKj2jCxvO6LsXNCcLK7+niPQryHDEdafxurmo3xH/8VbK/jwV5rg03y/tvC9T1Rd8JKI2usEZSQgV1ss8+gJtjtpcD","base64")).toString()),wq}var tEe=new Map([[G.makeIdent(null,"fsevents").identHash,Zye],[G.makeIdent(null,"resolve").identHash,$ye],[G.makeIdent(null,"typescript").identHash,eEe]]),Lct={hooks:{registerPackageExtensions:async(t,e)=>{for(let[r,s]of Eq)e(G.parseDescriptor(r,!0),s)},getBuiltinPatch:async(t,e)=>{let r="compat/";if(!e.startsWith(r))return;let s=G.parseIdent(e.slice(r.length)),a=tEe.get(s.identHash)?.();return typeof a<"u"?a:null},reduceDependency:async(t,e,r,s)=>typeof tEe.get(t.identHash)>"u"?t:G.makeDescriptor(t,G.makeRange({protocol:"patch:",source:G.stringifyDescriptor(t),selector:`optional!builtin`,params:null}))}},Mct=Lct;var _q={};Vt(_q,{ConstraintsCheckCommand:()=>ZC,ConstraintsQueryCommand:()=>zC,ConstraintsSourceCommand:()=>XC,default:()=>nut});Ge();Ge();iS();var YC=class{constructor(e){this.project=e}createEnvironment(){let e=new WC(["cwd","ident"]),r=new WC(["workspace","type","ident"]),s=new WC(["ident"]),a={manifestUpdates:new Map,reportedErrors:new Map},n=new Map,c=new Map;for(let f of this.project.storedPackages.values()){let p=Array.from(f.peerDependencies.values(),h=>[G.stringifyIdent(h),h.range]);n.set(f.locatorHash,{workspace:null,ident:G.stringifyIdent(f),version:f.version,dependencies:new Map,peerDependencies:new Map(p.filter(([h])=>f.peerDependenciesMeta.get(h)?.optional!==!0)),optionalPeerDependencies:new Map(p.filter(([h])=>f.peerDependenciesMeta.get(h)?.optional===!0))})}for(let f of this.project.storedPackages.values()){let p=n.get(f.locatorHash);p.dependencies=new Map(Array.from(f.dependencies.values(),h=>{let E=this.project.storedResolutions.get(h.descriptorHash);if(typeof E>"u")throw new Error("Assertion failed: The resolution should have been registered");let C=n.get(E);if(typeof C>"u")throw new Error("Assertion failed: The package should have been registered");return[G.stringifyIdent(h),C]})),p.dependencies.delete(p.ident)}for(let f of this.project.workspaces){let p=G.stringifyIdent(f.anchoredLocator),h=f.manifest.exportTo({}),E=n.get(f.anchoredLocator.locatorHash);if(typeof E>"u")throw new Error("Assertion failed: The package should have been registered");let C=(R,N,{caller:U=Ui.getCaller()}={})=>{let W=nS(R),ee=je.getMapWithDefault(a.manifestUpdates,f.cwd),ie=je.getMapWithDefault(ee,W),ue=je.getSetWithDefault(ie,N);U!==null&&ue.add(U)},S=R=>C(R,void 0,{caller:Ui.getCaller()}),P=R=>{je.getArrayWithDefault(a.reportedErrors,f.cwd).push(R)},I=e.insert({cwd:f.relativeCwd,ident:p,manifest:h,pkg:E,set:C,unset:S,error:P});c.set(f,I);for(let R of Ut.allDependencies)for(let N of f.manifest[R].values()){let U=G.stringifyIdent(N),W=()=>{C([R,U],void 0,{caller:Ui.getCaller()})},ee=ue=>{C([R,U],ue,{caller:Ui.getCaller()})},ie=null;if(R!=="peerDependencies"&&(R!=="dependencies"||!f.manifest.devDependencies.has(N.identHash))){let ue=f.anchoredPackage.dependencies.get(N.identHash);if(ue){if(typeof ue>"u")throw new Error("Assertion failed: The dependency should have been registered");let le=this.project.storedResolutions.get(ue.descriptorHash);if(typeof le>"u")throw new Error("Assertion failed: The resolution should have been registered");let me=n.get(le);if(typeof me>"u")throw new Error("Assertion failed: The package should have been registered");ie=me}}r.insert({workspace:I,ident:U,range:N.range,type:R,resolution:ie,update:ee,delete:W,error:P})}}for(let f of this.project.storedPackages.values()){let p=this.project.tryWorkspaceByLocator(f);if(!p)continue;let h=c.get(p);if(typeof h>"u")throw new Error("Assertion failed: The workspace should have been registered");let E=n.get(f.locatorHash);if(typeof E>"u")throw new Error("Assertion failed: The package should have been registered");E.workspace=h}return{workspaces:e,dependencies:r,packages:s,result:a}}async process(){let e=this.createEnvironment(),r={Yarn:{workspace:a=>e.workspaces.find(a)[0]??null,workspaces:a=>e.workspaces.find(a),dependency:a=>e.dependencies.find(a)[0]??null,dependencies:a=>e.dependencies.find(a),package:a=>e.packages.find(a)[0]??null,packages:a=>e.packages.find(a)}},s=await this.project.loadUserConfig();return s?.constraints?(await s.constraints(r),e.result):null}};Ge();Ge();Yt();var zC=class extends ft{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.query=ge.String()}static{this.paths=[["constraints","query"]]}static{this.usage=ot.Usage({category:"Constraints-related commands",description:"query the constraints fact database",details:` + This command will output all matches to the given prolog query. + `,examples:[["List all dependencies throughout the workspace","yarn constraints query 'workspace_has_dependency(_, DependencyName, _, _).'"]]})}async execute(){let{Constraints:r}=await Promise.resolve().then(()=>(lS(),aS)),s=await ze.find(this.context.cwd,this.context.plugins),{project:a}=await Tt.find(s,this.context.cwd),n=await r.find(a),c=this.query;return c.endsWith(".")||(c=`${c}.`),(await Ot.start({configuration:s,json:this.json,stdout:this.context.stdout},async p=>{for await(let h of n.query(c)){let E=Array.from(Object.entries(h)),C=E.length,S=E.reduce((P,[I])=>Math.max(P,I.length),0);for(let P=0;P(lS(),aS)),s=await ze.find(this.context.cwd,this.context.plugins),{project:a}=await Tt.find(s,this.context.cwd),n=await r.find(a);this.context.stdout.write(this.verbose?n.fullSource:n.source)}};Ge();Ge();Yt();iS();var ZC=class extends ft{constructor(){super(...arguments);this.fix=ge.Boolean("--fix",!1,{description:"Attempt to automatically fix unambiguous issues, following a multi-pass process"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"})}static{this.paths=[["constraints"]]}static{this.usage=ot.Usage({category:"Constraints-related commands",description:"check that the project constraints are met",details:` + This command will run constraints on your project and emit errors for each one that is found but isn't met. If any error is emitted the process will exit with a non-zero exit code. + + If the \`--fix\` flag is used, Yarn will attempt to automatically fix the issues the best it can, following a multi-pass process (with a maximum of 10 iterations). Some ambiguous patterns cannot be autofixed, in which case you'll have to manually specify the right resolution. + + For more information as to how to write constraints, please consult our dedicated page on our website: https://yarnpkg.com/features/constraints. + `,examples:[["Check that all constraints are satisfied","yarn constraints"],["Autofix all unmet constraints","yarn constraints --fix"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s}=await Tt.find(r,this.context.cwd);await s.restoreInstallState();let a=await s.loadUserConfig(),n;if(a?.constraints)n=new YC(s);else{let{Constraints:h}=await Promise.resolve().then(()=>(lS(),aS));n=await h.find(s)}let c,f=!1,p=!1;for(let h=this.fix?10:1;h>0;--h){let E=await n.process();if(!E)break;let{changedWorkspaces:C,remainingErrors:S}=iF(s,E,{fix:this.fix}),P=[];for(let[I,R]of C){let N=I.manifest.indent;I.manifest=new Ut,I.manifest.indent=N,I.manifest.load(R),P.push(I.persistManifest())}if(await Promise.all(P),!(C.size>0&&h>1)){c=rEe(S,{configuration:r}),f=!1,p=!0;for(let[,I]of S)for(let R of I)R.fixable?f=!0:p=!1}}if(c.children.length===0)return 0;if(f){let h=p?`Those errors can all be fixed by running ${he.pretty(r,"yarn constraints --fix",he.Type.CODE)}`:`Errors prefixed by '\u2699' can be fixed by running ${he.pretty(r,"yarn constraints --fix",he.Type.CODE)}`;await Ot.start({configuration:r,stdout:this.context.stdout,includeNames:!1,includeFooter:!1},async E=>{E.reportInfo(0,h),E.reportSeparator()})}return c.children=je.sortMap(c.children,h=>h.value[1]),xs.emitTree(c,{configuration:r,stdout:this.context.stdout,json:this.json,separators:1}),1}};iS();var rut={configuration:{enableConstraintsChecks:{description:"If true, constraints will run during installs",type:"BOOLEAN",default:!1},constraintsPath:{description:"The path of the constraints file.",type:"ABSOLUTE_PATH",default:"./constraints.pro"}},commands:[zC,XC,ZC],hooks:{async validateProjectAfterInstall(t,{reportError:e}){if(!t.configuration.get("enableConstraintsChecks"))return;let r=await t.loadUserConfig(),s;if(r?.constraints)s=new YC(t);else{let{Constraints:c}=await Promise.resolve().then(()=>(lS(),aS));s=await c.find(t)}let a=await s.process();if(!a)return;let{remainingErrors:n}=iF(t,a);if(n.size!==0)if(t.configuration.isCI)for(let[c,f]of n)for(let p of f)e(84,`${he.pretty(t.configuration,c.anchoredLocator,he.Type.IDENT)}: ${p.text}`);else e(84,`Constraint check failed; run ${he.pretty(t.configuration,"yarn constraints",he.Type.CODE)} for more details`)}}},nut=rut;var Hq={};Vt(Hq,{CreateCommand:()=>$C,DlxCommand:()=>ew,default:()=>sut});Ge();Yt();var $C=class extends ft{constructor(){super(...arguments);this.pkg=ge.String("-p,--package",{description:"The package to run the provided command from"});this.quiet=ge.Boolean("-q,--quiet",!1,{description:"Only report critical errors instead of printing the full install logs"});this.command=ge.String();this.args=ge.Proxy()}static{this.paths=[["create"]]}async execute(){let r=[];this.pkg&&r.push("--package",this.pkg),this.quiet&&r.push("--quiet");let s=this.command.replace(/^(@[^@/]+)(@|$)/,"$1/create$2"),a=G.parseDescriptor(s),n=a.name.match(/^create(-|$)/)?a:a.scope?G.makeIdent(a.scope,`create-${a.name}`):G.makeIdent(null,`create-${a.name}`),c=G.stringifyIdent(n);return a.range!=="unknown"&&(c+=`@${a.range}`),this.cli.run(["dlx",...r,c,...this.args])}};Ge();Ge();Dt();Yt();var ew=class extends ft{constructor(){super(...arguments);this.packages=ge.Array("-p,--package",{description:"The package(s) to install before running the command"});this.quiet=ge.Boolean("-q,--quiet",!1,{description:"Only report critical errors instead of printing the full install logs"});this.command=ge.String();this.args=ge.Proxy()}static{this.paths=[["dlx"]]}static{this.usage=ot.Usage({description:"run a package in a temporary environment",details:"\n This command will install a package within a temporary environment, and run its binary script if it contains any. The binary will run within the current cwd.\n\n By default Yarn will download the package named `command`, but this can be changed through the use of the `-p,--package` flag which will instruct Yarn to still run the same command but from a different package.\n\n Using `yarn dlx` as a replacement of `yarn add` isn't recommended, as it makes your project non-deterministic (Yarn doesn't keep track of the packages installed through `dlx` - neither their name, nor their version).\n ",examples:[["Use create-vite to scaffold a new Vite project","yarn dlx create-vite"],["Install multiple packages for a single command",`yarn dlx -p typescript -p ts-node ts-node --transpile-only -e "console.log('hello!')"`]]})}async execute(){return ze.telemetry=null,await ce.mktempPromise(async r=>{let s=J.join(r,`dlx-${process.pid}`);await ce.mkdirPromise(s),await ce.writeFilePromise(J.join(s,"package.json"),`{} +`),await ce.writeFilePromise(J.join(s,"yarn.lock"),"");let a=J.join(s,".yarnrc.yml"),n=await ze.findProjectCwd(this.context.cwd),f={enableGlobalCache:!(await ze.find(this.context.cwd,null,{strict:!1})).get("enableGlobalCache"),enableTelemetry:!1,logFilters:[{code:Yf(68),level:he.LogLevel.Discard}]},p=n!==null?J.join(n,".yarnrc.yml"):null;p!==null&&ce.existsSync(p)?(await ce.copyFilePromise(p,a),await ze.updateConfiguration(s,N=>{let U=je.toMerged(N,f);return Array.isArray(N.plugins)&&(U.plugins=N.plugins.map(W=>{let ee=typeof W=="string"?W:W.path,ie=fe.isAbsolute(ee)?ee:fe.resolve(fe.fromPortablePath(n),ee);return typeof W=="string"?ie:{path:ie,spec:W.spec}})),U})):await ce.writeJsonPromise(a,f);let h=this.packages??[this.command],E=G.parseDescriptor(this.command).name,C=await this.cli.run(["add","--fixed","--",...h],{cwd:s,quiet:this.quiet});if(C!==0)return C;this.quiet||this.context.stdout.write(` +`);let S=await ze.find(s,this.context.plugins),{project:P,workspace:I}=await Tt.find(S,s);if(I===null)throw new ar(P.cwd,s);await P.restoreInstallState();let R=await In.getWorkspaceAccessibleBinaries(I);return R.has(E)===!1&&R.size===1&&typeof this.packages>"u"&&(E=Array.from(R)[0][0]),await In.executeWorkspaceAccessibleBinary(I,E,this.args,{packageAccessibleBinaries:R,cwd:this.context.cwd,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr})})}};var iut={commands:[$C,ew]},sut=iut;var qq={};Vt(qq,{ExecFetcher:()=>uS,ExecResolver:()=>fS,default:()=>lut,execUtils:()=>lF});Ge();Ge();Dt();var cA="exec:";var lF={};Vt(lF,{loadGeneratorFile:()=>cS,makeLocator:()=>Gq,makeSpec:()=>PEe,parseSpec:()=>jq});Ge();Dt();function jq(t){let{params:e,selector:r}=G.parseRange(t),s=fe.toPortablePath(r);return{parentLocator:e&&typeof e.locator=="string"?G.parseLocator(e.locator):null,path:s}}function PEe({parentLocator:t,path:e,generatorHash:r,protocol:s}){let a=t!==null?{locator:G.stringifyLocator(t)}:{},n=typeof r<"u"?{hash:r}:{};return G.makeRange({protocol:s,source:e,selector:e,params:{...n,...a}})}function Gq(t,{parentLocator:e,path:r,generatorHash:s,protocol:a}){return G.makeLocator(t,PEe({parentLocator:e,path:r,generatorHash:s,protocol:a}))}async function cS(t,e,r){let{parentLocator:s,path:a}=G.parseFileStyleRange(t,{protocol:e}),n=J.isAbsolute(a)?{packageFs:new Sn(vt.root),prefixPath:vt.dot,localPath:vt.root}:await r.fetcher.fetch(s,r),c=n.localPath?{packageFs:new Sn(vt.root),prefixPath:J.relative(vt.root,n.localPath)}:n;n!==c&&n.releaseFs&&n.releaseFs();let f=c.packageFs,p=J.join(c.prefixPath,a);return await f.readFilePromise(p,"utf8")}var uS=class{supports(e,r){return!!e.reference.startsWith(cA)}getLocalPath(e,r){let{parentLocator:s,path:a}=G.parseFileStyleRange(e.reference,{protocol:cA});if(J.isAbsolute(a))return a;let n=r.fetcher.getLocalPath(s,r);return n===null?null:J.resolve(n,a)}async fetch(e,r){let s=r.checksums.get(e.locatorHash)||null,[a,n,c]=await r.cache.fetchPackageFromCache(e,s,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e),loader:()=>this.fetchFromDisk(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:G.getIdentVendorPath(e),localPath:this.getLocalPath(e,r),checksum:c}}async fetchFromDisk(e,r){let s=await cS(e.reference,cA,r);return ce.mktempPromise(async a=>{let n=J.join(a,"generator.js");return await ce.writeFilePromise(n,s),ce.mktempPromise(async c=>{if(await this.generatePackage(c,e,n,r),!ce.existsSync(J.join(c,"build")))throw new Error("The script should have generated a build directory");return await ps.makeArchiveFromDirectory(J.join(c,"build"),{prefixPath:G.getIdentVendorPath(e),compressionLevel:r.project.configuration.get("compressionLevel")})})})}async generatePackage(e,r,s,a){return await ce.mktempPromise(async n=>{let c=await In.makeScriptEnv({project:a.project,binFolder:n}),f=J.join(e,"runtime.js");return await ce.mktempPromise(async p=>{let h=J.join(p,"buildfile.log"),E=J.join(e,"generator"),C=J.join(e,"build");await ce.mkdirPromise(E),await ce.mkdirPromise(C);let S={tempDir:fe.fromPortablePath(E),buildDir:fe.fromPortablePath(C),locator:G.stringifyLocator(r)};await ce.writeFilePromise(f,` + // Expose 'Module' as a global variable + Object.defineProperty(global, 'Module', { + get: () => require('module'), + configurable: true, + enumerable: false, + }); + + // Expose non-hidden built-in modules as global variables + for (const name of Module.builtinModules.filter((name) => name !== 'module' && !name.startsWith('_'))) { + Object.defineProperty(global, name, { + get: () => require(name), + configurable: true, + enumerable: false, + }); + } + + // Expose the 'execEnv' global variable + Object.defineProperty(global, 'execEnv', { + value: { + ...${JSON.stringify(S)}, + }, + enumerable: true, + }); + `);let P=c.NODE_OPTIONS||"",I=/\s*--require\s+\S*\.pnp\.c?js\s*/g;P=P.replace(I," ").trim(),c.NODE_OPTIONS=P;let{stdout:R,stderr:N}=a.project.configuration.getSubprocessStreams(h,{header:`# This file contains the result of Yarn generating a package (${G.stringifyLocator(r)}) +`,prefix:G.prettyLocator(a.project.configuration,r),report:a.report}),{code:U}=await qr.pipevp(process.execPath,["--require",fe.fromPortablePath(f),fe.fromPortablePath(s),G.stringifyIdent(r)],{cwd:e,env:c,stdin:null,stdout:R,stderr:N});if(U!==0)throw ce.detachTemp(p),new Error(`Package generation failed (exit code ${U}, logs can be found here: ${he.pretty(a.project.configuration,h,he.Type.PATH)})`)})})}};Ge();Ge();var out=2,fS=class{supportsDescriptor(e,r){return!!e.range.startsWith(cA)}supportsLocator(e,r){return!!e.reference.startsWith(cA)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,s){return G.bindDescriptor(e,{locator:G.stringifyLocator(r)})}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,s){if(!s.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let{path:a,parentLocator:n}=jq(e.range);if(n===null)throw new Error("Assertion failed: The descriptor should have been bound");let c=await cS(G.makeRange({protocol:cA,source:a,selector:a,params:{locator:G.stringifyLocator(n)}}),cA,s.fetchOptions),f=Nn.makeHash(`${out}`,c).slice(0,6);return[Gq(e,{parentLocator:n,path:a,generatorHash:f,protocol:cA})]}async getSatisfying(e,r,s,a){let[n]=await this.getCandidates(e,r,a);return{locators:s.filter(c=>c.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let s=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await je.releaseAfterUseAsync(async()=>await Ut.find(s.prefixPath,{baseFs:s.packageFs}),s.releaseFs);return{...e,version:a.version||"0.0.0",languageName:a.languageName||r.project.configuration.get("defaultLanguageName"),linkType:"HARD",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};var aut={fetchers:[uS],resolvers:[fS]},lut=aut;var Yq={};Vt(Yq,{FileFetcher:()=>gS,FileResolver:()=>dS,TarballFileFetcher:()=>mS,TarballFileResolver:()=>yS,default:()=>fut,fileUtils:()=>xm});Ge();Dt();var tw=/^(?:[a-zA-Z]:[\\/]|\.{0,2}\/)/,AS=/^[^?]*\.(?:tar\.gz|tgz)(?:::.*)?$/,es="file:";var xm={};Vt(xm,{fetchArchiveFromLocator:()=>hS,makeArchiveFromLocator:()=>cF,makeBufferFromLocator:()=>Wq,makeLocator:()=>rw,makeSpec:()=>xEe,parseSpec:()=>pS});Ge();Dt();function pS(t){let{params:e,selector:r}=G.parseRange(t),s=fe.toPortablePath(r);return{parentLocator:e&&typeof e.locator=="string"?G.parseLocator(e.locator):null,path:s}}function xEe({parentLocator:t,path:e,hash:r,protocol:s}){let a=t!==null?{locator:G.stringifyLocator(t)}:{},n=typeof r<"u"?{hash:r}:{};return G.makeRange({protocol:s,source:e,selector:e,params:{...n,...a}})}function rw(t,{parentLocator:e,path:r,hash:s,protocol:a}){return G.makeLocator(t,xEe({parentLocator:e,path:r,hash:s,protocol:a}))}async function hS(t,e){let{parentLocator:r,path:s}=G.parseFileStyleRange(t.reference,{protocol:es}),a=J.isAbsolute(s)?{packageFs:new Sn(vt.root),prefixPath:vt.dot,localPath:vt.root}:await e.fetcher.fetch(r,e),n=a.localPath?{packageFs:new Sn(vt.root),prefixPath:J.relative(vt.root,a.localPath)}:a;a!==n&&a.releaseFs&&a.releaseFs();let c=n.packageFs,f=J.join(n.prefixPath,s);return await je.releaseAfterUseAsync(async()=>await c.readFilePromise(f),n.releaseFs)}async function cF(t,{protocol:e,fetchOptions:r,inMemory:s=!1}){let{parentLocator:a,path:n}=G.parseFileStyleRange(t.reference,{protocol:e}),c=J.isAbsolute(n)?{packageFs:new Sn(vt.root),prefixPath:vt.dot,localPath:vt.root}:await r.fetcher.fetch(a,r),f=c.localPath?{packageFs:new Sn(vt.root),prefixPath:J.relative(vt.root,c.localPath)}:c;c!==f&&c.releaseFs&&c.releaseFs();let p=f.packageFs,h=J.join(f.prefixPath,n);return await je.releaseAfterUseAsync(async()=>await ps.makeArchiveFromDirectory(h,{baseFs:p,prefixPath:G.getIdentVendorPath(t),compressionLevel:r.project.configuration.get("compressionLevel"),inMemory:s}),f.releaseFs)}async function Wq(t,{protocol:e,fetchOptions:r}){return(await cF(t,{protocol:e,fetchOptions:r,inMemory:!0})).getBufferAndClose()}var gS=class{supports(e,r){return!!e.reference.startsWith(es)}getLocalPath(e,r){let{parentLocator:s,path:a}=G.parseFileStyleRange(e.reference,{protocol:es});if(J.isAbsolute(a))return a;let n=r.fetcher.getLocalPath(s,r);return n===null?null:J.resolve(n,a)}async fetch(e,r){let s=r.checksums.get(e.locatorHash)||null,[a,n,c]=await r.cache.fetchPackageFromCache(e,s,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${G.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the disk`),loader:()=>this.fetchFromDisk(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:G.getIdentVendorPath(e),localPath:this.getLocalPath(e,r),checksum:c}}async fetchFromDisk(e,r){return cF(e,{protocol:es,fetchOptions:r})}};Ge();Ge();var cut=2,dS=class{supportsDescriptor(e,r){return e.range.match(tw)?!0:!!e.range.startsWith(es)}supportsLocator(e,r){return!!e.reference.startsWith(es)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,s){return tw.test(e.range)&&(e=G.makeDescriptor(e,`${es}${e.range}`)),G.bindDescriptor(e,{locator:G.stringifyLocator(r)})}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,s){if(!s.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let{path:a,parentLocator:n}=pS(e.range);if(n===null)throw new Error("Assertion failed: The descriptor should have been bound");let c=await Wq(G.makeLocator(e,G.makeRange({protocol:es,source:a,selector:a,params:{locator:G.stringifyLocator(n)}})),{protocol:es,fetchOptions:s.fetchOptions}),f=Nn.makeHash(`${cut}`,c).slice(0,6);return[rw(e,{parentLocator:n,path:a,hash:f,protocol:es})]}async getSatisfying(e,r,s,a){let[n]=await this.getCandidates(e,r,a);return{locators:s.filter(c=>c.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let s=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await je.releaseAfterUseAsync(async()=>await Ut.find(s.prefixPath,{baseFs:s.packageFs}),s.releaseFs);return{...e,version:a.version||"0.0.0",languageName:a.languageName||r.project.configuration.get("defaultLanguageName"),linkType:"HARD",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};Ge();var mS=class{supports(e,r){return AS.test(e.reference)?!!e.reference.startsWith(es):!1}getLocalPath(e,r){return null}async fetch(e,r){let s=r.checksums.get(e.locatorHash)||null,[a,n,c]=await r.cache.fetchPackageFromCache(e,s,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${G.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the disk`),loader:()=>this.fetchFromDisk(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:G.getIdentVendorPath(e),checksum:c}}async fetchFromDisk(e,r){let s=await hS(e,r);return await ps.convertToZip(s,{configuration:r.project.configuration,prefixPath:G.getIdentVendorPath(e),stripComponents:1})}};Ge();Ge();Ge();var yS=class{supportsDescriptor(e,r){return AS.test(e.range)?!!(e.range.startsWith(es)||tw.test(e.range)):!1}supportsLocator(e,r){return AS.test(e.reference)?!!e.reference.startsWith(es):!1}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,s){return tw.test(e.range)&&(e=G.makeDescriptor(e,`${es}${e.range}`)),G.bindDescriptor(e,{locator:G.stringifyLocator(r)})}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,s){if(!s.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let{path:a,parentLocator:n}=pS(e.range);if(n===null)throw new Error("Assertion failed: The descriptor should have been bound");let c=rw(e,{parentLocator:n,path:a,hash:"",protocol:es}),f=await hS(c,s.fetchOptions),p=Nn.makeHash(f).slice(0,6);return[rw(e,{parentLocator:n,path:a,hash:p,protocol:es})]}async getSatisfying(e,r,s,a){let[n]=await this.getCandidates(e,r,a);return{locators:s.filter(c=>c.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let s=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await je.releaseAfterUseAsync(async()=>await Ut.find(s.prefixPath,{baseFs:s.packageFs}),s.releaseFs);return{...e,version:a.version||"0.0.0",languageName:a.languageName||r.project.configuration.get("defaultLanguageName"),linkType:"HARD",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};var uut={fetchers:[mS,gS],resolvers:[yS,dS]},fut=uut;var Kq={};Vt(Kq,{GithubFetcher:()=>ES,default:()=>put,githubUtils:()=>uF});Ge();Dt();var uF={};Vt(uF,{invalidGithubUrlMessage:()=>TEe,isGithubUrl:()=>Vq,parseGithubUrl:()=>Jq});var kEe=ut(Ie("querystring")),QEe=[/^https?:\/\/(?:([^/]+?)@)?github.com\/([^/#]+)\/([^/#]+)\/tarball\/([^/#]+)(?:#(.*))?$/,/^https?:\/\/(?:([^/]+?)@)?github.com\/([^/#]+)\/([^/#]+?)(?:\.git)?(?:#(.*))?$/];function Vq(t){return t?QEe.some(e=>!!t.match(e)):!1}function Jq(t){let e;for(let f of QEe)if(e=t.match(f),e)break;if(!e)throw new Error(TEe(t));let[,r,s,a,n="master"]=e,{commit:c}=kEe.default.parse(n);return n=c||n.replace(/[^:]*:/,""),{auth:r,username:s,reponame:a,treeish:n}}function TEe(t){return`Input cannot be parsed as a valid GitHub URL ('${t}').`}var ES=class{supports(e,r){return!!Vq(e.reference)}getLocalPath(e,r){return null}async fetch(e,r){let s=r.checksums.get(e.locatorHash)||null,[a,n,c]=await r.cache.fetchPackageFromCache(e,s,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${G.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from GitHub`),loader:()=>this.fetchFromNetwork(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:G.getIdentVendorPath(e),checksum:c}}async fetchFromNetwork(e,r){let s=await nn.get(this.getLocatorUrl(e,r),{configuration:r.project.configuration});return await ce.mktempPromise(async a=>{let n=new Sn(a);await ps.extractArchiveTo(s,n,{stripComponents:1});let c=ka.splitRepoUrl(e.reference),f=J.join(a,"package.tgz");await In.prepareExternalProject(a,f,{configuration:r.project.configuration,report:r.report,workspace:c.extra.workspace,locator:e});let p=await ce.readFilePromise(f);return await ps.convertToZip(p,{configuration:r.project.configuration,prefixPath:G.getIdentVendorPath(e),stripComponents:1})})}getLocatorUrl(e,r){let{auth:s,username:a,reponame:n,treeish:c}=Jq(e.reference);return`https://${s?`${s}@`:""}github.com/${a}/${n}/archive/${c}.tar.gz`}};var Aut={hooks:{async fetchHostedRepository(t,e,r){if(t!==null)return t;let s=new ES;if(!s.supports(e,r))return null;try{return await s.fetch(e,r)}catch{return null}}}},put=Aut;var zq={};Vt(zq,{TarballHttpFetcher:()=>CS,TarballHttpResolver:()=>wS,default:()=>gut});Ge();function IS(t){let e;try{e=new URL(t)}catch{return!1}return!(e.protocol!=="http:"&&e.protocol!=="https:"||!e.pathname.match(/(\.tar\.gz|\.tgz|\/[^.]+)$/))}var CS=class{supports(e,r){return IS(e.reference)}getLocalPath(e,r){return null}async fetch(e,r){let s=r.checksums.get(e.locatorHash)||null,[a,n,c]=await r.cache.fetchPackageFromCache(e,s,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${G.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the remote server`),loader:()=>this.fetchFromNetwork(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:G.getIdentVendorPath(e),checksum:c}}async fetchFromNetwork(e,r){let s=await nn.get(e.reference,{configuration:r.project.configuration});return await ps.convertToZip(s,{configuration:r.project.configuration,prefixPath:G.getIdentVendorPath(e),stripComponents:1})}};Ge();Ge();var wS=class{supportsDescriptor(e,r){return IS(e.range)}supportsLocator(e,r){return IS(e.reference)}shouldPersistResolution(e,r){return!0}bindDescriptor(e,r,s){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,s){return[G.convertDescriptorToLocator(e)]}async getSatisfying(e,r,s,a){let[n]=await this.getCandidates(e,r,a);return{locators:s.filter(c=>c.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let s=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await je.releaseAfterUseAsync(async()=>await Ut.find(s.prefixPath,{baseFs:s.packageFs}),s.releaseFs);return{...e,version:a.version||"0.0.0",languageName:a.languageName||r.project.configuration.get("defaultLanguageName"),linkType:"HARD",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};var hut={fetchers:[CS],resolvers:[wS]},gut=hut;var Xq={};Vt(Xq,{InitCommand:()=>z0,InitInitializerCommand:()=>nw,default:()=>mut});Yt();Ge();Ge();Dt();Yt();var z0=class extends ft{constructor(){super(...arguments);this.private=ge.Boolean("-p,--private",!1,{description:"Initialize a private package"});this.workspace=ge.Boolean("-w,--workspace",!1,{description:"Initialize a workspace root with a `packages/` directory"});this.install=ge.String("-i,--install",!1,{tolerateBoolean:!0,description:"Initialize a package with a specific bundle that will be locked in the project"});this.name=ge.String("-n,--name",{description:"Initialize a package with the given name"});this.usev2=ge.Boolean("-2",!1,{hidden:!0});this.yes=ge.Boolean("-y,--yes",{hidden:!0})}static{this.paths=[["init"]]}static{this.usage=ot.Usage({description:"create a new package",details:"\n This command will setup a new package in your local directory.\n\n If the `-p,--private` or `-w,--workspace` options are set, the package will be private by default.\n\n If the `-w,--workspace` option is set, the package will be configured to accept a set of workspaces in the `packages/` directory.\n\n If the `-i,--install` option is given a value, Yarn will first download it using `yarn set version` and only then forward the init call to the newly downloaded bundle. Without arguments, the downloaded bundle will be `latest`.\n\n The initial settings of the manifest can be changed by using the `initScope` and `initFields` configuration values. Additionally, Yarn will generate an EditorConfig file whose rules can be altered via `initEditorConfig`, and will initialize a Git repository in the current directory.\n ",examples:[["Create a new package in the local directory","yarn init"],["Create a new private package in the local directory","yarn init -p"],["Create a new package and store the Yarn release inside","yarn init -i=latest"],["Create a new private package and defines it as a workspace root","yarn init -w"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),s=typeof this.install=="string"?this.install:this.usev2||this.install===!0?"latest":null;return s!==null?await this.executeProxy(r,s):await this.executeRegular(r)}async executeProxy(r,s){if(r.projectCwd!==null&&r.projectCwd!==this.context.cwd)throw new nt("Cannot use the --install flag from within a project subdirectory");ce.existsSync(this.context.cwd)||await ce.mkdirPromise(this.context.cwd,{recursive:!0});let a=J.join(this.context.cwd,Er.lockfile);ce.existsSync(a)||await ce.writeFilePromise(a,"");let n=await this.cli.run(["set","version",s],{quiet:!0});if(n!==0)return n;let c=[];return this.private&&c.push("-p"),this.workspace&&c.push("-w"),this.name&&c.push(`-n=${this.name}`),this.yes&&c.push("-y"),await ce.mktempPromise(async f=>{let{code:p}=await qr.pipevp("yarn",["init",...c],{cwd:this.context.cwd,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr,env:await In.makeScriptEnv({binFolder:f})});return p})}async initialize(){}async executeRegular(r){let s=null;try{s=(await Tt.find(r,this.context.cwd)).project}catch{s=null}ce.existsSync(this.context.cwd)||await ce.mkdirPromise(this.context.cwd,{recursive:!0});let a=await Ut.tryFind(this.context.cwd),n=a??new Ut,c=Object.fromEntries(r.get("initFields").entries());n.load(c),n.name=n.name??G.makeIdent(r.get("initScope"),this.name??J.basename(this.context.cwd)),n.packageManager=fn&&je.isTaggedYarnVersion(fn)?`yarn@${fn}`:null,(!a&&this.workspace||this.private)&&(n.private=!0),this.workspace&&n.workspaceDefinitions.length===0&&(await ce.mkdirPromise(J.join(this.context.cwd,"packages"),{recursive:!0}),n.workspaceDefinitions=[{pattern:"packages/*"}]);let f={};n.exportTo(f);let p=J.join(this.context.cwd,Ut.fileName);await ce.changeFilePromise(p,`${JSON.stringify(f,null,2)} +`,{automaticNewlines:!0});let h=[p],E=J.join(this.context.cwd,"README.md");if(ce.existsSync(E)||(await ce.writeFilePromise(E,`# ${G.stringifyIdent(n.name)} +`),h.push(E)),!s||s.cwd===this.context.cwd){let C=J.join(this.context.cwd,Er.lockfile);ce.existsSync(C)||(await ce.writeFilePromise(C,""),h.push(C));let P=[".yarn/*","!.yarn/patches","!.yarn/plugins","!.yarn/releases","!.yarn/sdks","!.yarn/versions","","# Whether you use PnP or not, the node_modules folder is often used to store","# build artifacts that should be gitignored","node_modules","","# Swap the comments on the following lines if you wish to use zero-installs","# In that case, don't forget to run `yarn config set enableGlobalCache false`!","# Documentation here: https://yarnpkg.com/features/caching#zero-installs","","#!.yarn/cache",".pnp.*"].map(ue=>`${ue} +`).join(""),I=J.join(this.context.cwd,".gitignore");ce.existsSync(I)||(await ce.writeFilePromise(I,P),h.push(I));let N=["/.yarn/** linguist-vendored","/.yarn/releases/* binary","/.yarn/plugins/**/* binary","/.pnp.* binary linguist-generated"].map(ue=>`${ue} +`).join(""),U=J.join(this.context.cwd,".gitattributes");ce.existsSync(U)||(await ce.writeFilePromise(U,N),h.push(U));let W={"*":{charset:"utf-8",endOfLine:"lf",indentSize:2,indentStyle:"space",insertFinalNewline:!0}};je.mergeIntoTarget(W,r.get("initEditorConfig"));let ee=`root = true +`;for(let[ue,le]of Object.entries(W)){ee+=` +[${ue}] +`;for(let[me,pe]of Object.entries(le)){let Be=me.replace(/[A-Z]/g,Ce=>`_${Ce.toLowerCase()}`);ee+=`${Be} = ${pe} +`}}let ie=J.join(this.context.cwd,".editorconfig");ce.existsSync(ie)||(await ce.writeFilePromise(ie,ee),h.push(ie)),await this.cli.run(["install"],{quiet:!0}),await this.initialize(),ce.existsSync(J.join(this.context.cwd,".git"))||(await qr.execvp("git",["init"],{cwd:this.context.cwd}),await qr.execvp("git",["add","--",...h],{cwd:this.context.cwd}),await qr.execvp("git",["commit","--allow-empty","-m","First commit"],{cwd:this.context.cwd}))}}};var nw=class extends z0{constructor(){super(...arguments);this.initializer=ge.String();this.argv=ge.Proxy()}static{this.paths=[["init"]]}async initialize(){this.context.stdout.write(` +`),await this.cli.run(["dlx",this.initializer,...this.argv],{quiet:!0})}};var dut={configuration:{initScope:{description:"Scope used when creating packages via the init command",type:"STRING",default:null},initFields:{description:"Additional fields to set when creating packages via the init command",type:"MAP",valueDefinition:{description:"",type:"ANY"}},initEditorConfig:{description:"Extra rules to define in the generator editorconfig",type:"MAP",valueDefinition:{description:"",type:"ANY"}}},commands:[z0,nw]},mut=dut;var JW={};Vt(JW,{SearchCommand:()=>Iw,UpgradeInteractiveCommand:()=>Cw,default:()=>Dgt});Ge();var FEe=ut(Ie("os"));function iw({stdout:t}){if(FEe.default.endianness()==="BE")throw new Error("Interactive commands cannot be used on big-endian systems because ink depends on yoga-layout-prebuilt which only supports little-endian architectures");if(!t.isTTY)throw new Error("Interactive commands can only be used inside a TTY environment")}Yt();var YIe=ut(g9()),d9={appId:"OFCNCOG2CU",apiKey:"6fe4476ee5a1832882e326b506d14126",indexName:"npm-search"},hAt=(0,YIe.default)(d9.appId,d9.apiKey).initIndex(d9.indexName),m9=async(t,e=0)=>await hAt.search(t,{analyticsTags:["yarn-plugin-interactive-tools"],attributesToRetrieve:["name","version","owner","repository","humanDownloadsLast30Days"],page:e,hitsPerPage:10});var CD=["regular","dev","peer"],Iw=class extends ft{static{this.paths=[["search"]]}static{this.usage=ot.Usage({category:"Interactive commands",description:"open the search interface",details:` + This command opens a fullscreen terminal interface where you can search for and install packages from the npm registry. + `,examples:[["Open the search window","yarn search"]]})}async execute(){iw(this.context);let{Gem:e}=await Promise.resolve().then(()=>(WF(),LW)),{ScrollableItems:r}=await Promise.resolve().then(()=>(KF(),JF)),{useKeypress:s}=await Promise.resolve().then(()=>(yD(),w2e)),{useMinistore:a}=await Promise.resolve().then(()=>(GW(),jW)),{renderForm:n}=await Promise.resolve().then(()=>($F(),ZF)),{default:c}=await Promise.resolve().then(()=>ut(T2e())),{Box:f,Text:p}=await Promise.resolve().then(()=>ut(Wc())),{default:h,useEffect:E,useState:C}=await Promise.resolve().then(()=>ut(hn())),S=await ze.find(this.context.cwd,this.context.plugins),P=()=>h.createElement(f,{flexDirection:"row"},h.createElement(f,{flexDirection:"column",width:48},h.createElement(f,null,h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},""),"/",h.createElement(p,{bold:!0,color:"cyanBright"},"")," to move between packages.")),h.createElement(f,null,h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"")," to select a package.")),h.createElement(f,null,h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"")," again to change the target."))),h.createElement(f,{flexDirection:"column"},h.createElement(f,{marginLeft:1},h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"")," to install the selected packages.")),h.createElement(f,{marginLeft:1},h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"")," to abort.")))),I=()=>h.createElement(h.Fragment,null,h.createElement(f,{width:15},h.createElement(p,{bold:!0,underline:!0,color:"gray"},"Owner")),h.createElement(f,{width:11},h.createElement(p,{bold:!0,underline:!0,color:"gray"},"Version")),h.createElement(f,{width:10},h.createElement(p,{bold:!0,underline:!0,color:"gray"},"Downloads"))),R=()=>h.createElement(f,{width:17},h.createElement(p,{bold:!0,underline:!0,color:"gray"},"Target")),N=({hit:pe,active:Be})=>{let[Ce,g]=a(pe.name,null);s({active:Be},(Ae,se)=>{if(se.name!=="space")return;if(!Ce){g(CD[0]);return}let Z=CD.indexOf(Ce)+1;Z===CD.length?g(null):g(CD[Z])},[Ce,g]);let we=G.parseIdent(pe.name),ye=G.prettyIdent(S,we);return h.createElement(f,null,h.createElement(f,{width:45},h.createElement(p,{bold:!0,wrap:"wrap"},ye)),h.createElement(f,{width:14,marginLeft:1},h.createElement(p,{bold:!0,wrap:"truncate"},pe.owner.name)),h.createElement(f,{width:10,marginLeft:1},h.createElement(p,{italic:!0,wrap:"truncate"},pe.version)),h.createElement(f,{width:16,marginLeft:1},h.createElement(p,null,pe.humanDownloadsLast30Days)))},U=({name:pe,active:Be})=>{let[Ce]=a(pe,null),g=G.parseIdent(pe);return h.createElement(f,null,h.createElement(f,{width:47},h.createElement(p,{bold:!0}," - ",G.prettyIdent(S,g))),CD.map(we=>h.createElement(f,{key:we,width:14,marginLeft:1},h.createElement(p,null," ",h.createElement(e,{active:Ce===we})," ",h.createElement(p,{bold:!0},we)))))},W=()=>h.createElement(f,{marginTop:1},h.createElement(p,null,"Powered by Algolia.")),ie=await n(({useSubmit:pe})=>{let Be=a();pe(Be);let Ce=Array.from(Be.keys()).filter(j=>Be.get(j)!==null),[g,we]=C(""),[ye,Ae]=C(0),[se,Z]=C([]),De=j=>{j.match(/\t| /)||we(j)},Re=async()=>{Ae(0);let j=await m9(g);j.query===g&&Z(j.hits)},mt=async()=>{let j=await m9(g,ye+1);j.query===g&&j.page-1===ye&&(Ae(j.page),Z([...se,...j.hits]))};return E(()=>{g?Re():Z([])},[g]),h.createElement(f,{flexDirection:"column"},h.createElement(P,null),h.createElement(f,{flexDirection:"row",marginTop:1},h.createElement(p,{bold:!0},"Search: "),h.createElement(f,{width:41},h.createElement(c,{value:g,onChange:De,placeholder:"i.e. babel, webpack, react...",showCursor:!1})),h.createElement(I,null)),se.length?h.createElement(r,{radius:2,loop:!1,children:se.map(j=>h.createElement(N,{key:j.name,hit:j,active:!1})),willReachEnd:mt}):h.createElement(p,{color:"gray"},"Start typing..."),h.createElement(f,{flexDirection:"row",marginTop:1},h.createElement(f,{width:49},h.createElement(p,{bold:!0},"Selected:")),h.createElement(R,null)),Ce.length?Ce.map(j=>h.createElement(U,{key:j,name:j,active:!1})):h.createElement(p,{color:"gray"},"No selected packages..."),h.createElement(W,null))},{},{stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr});if(typeof ie>"u")return 1;let ue=Array.from(ie.keys()).filter(pe=>ie.get(pe)==="regular"),le=Array.from(ie.keys()).filter(pe=>ie.get(pe)==="dev"),me=Array.from(ie.keys()).filter(pe=>ie.get(pe)==="peer");return ue.length&&await this.cli.run(["add",...ue]),le.length&&await this.cli.run(["add","--dev",...le]),me&&await this.cli.run(["add","--peer",...me]),0}};Ge();Yt();YG();var U2e=ut(Ai()),M2e=/^((?:[\^~]|>=?)?)([0-9]+)(\.[0-9]+)(\.[0-9]+)((?:-\S+)?)$/;function _2e(t,e){return t.length>0?[t.slice(0,e)].concat(_2e(t.slice(e),e)):[]}var Cw=class extends ft{static{this.paths=[["upgrade-interactive"]]}static{this.usage=ot.Usage({category:"Interactive commands",description:"open the upgrade interface",details:` + This command opens a fullscreen terminal interface where you can see any out of date packages used by your application, their status compared to the latest versions available on the remote registry, and select packages to upgrade. + `,examples:[["Open the upgrade window","yarn upgrade-interactive"]]})}async execute(){iw(this.context);let{ItemOptions:e}=await Promise.resolve().then(()=>(L2e(),O2e)),{Pad:r}=await Promise.resolve().then(()=>(VW(),N2e)),{ScrollableItems:s}=await Promise.resolve().then(()=>(KF(),JF)),{useMinistore:a}=await Promise.resolve().then(()=>(GW(),jW)),{renderForm:n}=await Promise.resolve().then(()=>($F(),ZF)),{Box:c,Text:f}=await Promise.resolve().then(()=>ut(Wc())),{default:p,useEffect:h,useRef:E,useState:C}=await Promise.resolve().then(()=>ut(hn())),S=await ze.find(this.context.cwd,this.context.plugins),{project:P,workspace:I}=await Tt.find(S,this.context.cwd),R=await Kr.find(S);if(!I)throw new ar(P.cwd,this.context.cwd);await P.restoreInstallState({restoreResolutions:!1});let N=this.context.stdout.rows-7,U=(we,ye)=>{let Ae=mde(we,ye),se="";for(let Z of Ae)Z.added?se+=he.pretty(S,Z.value,"green"):Z.removed||(se+=Z.value);return se},W=(we,ye)=>{if(we===ye)return ye;let Ae=G.parseRange(we),se=G.parseRange(ye),Z=Ae.selector.match(M2e),De=se.selector.match(M2e);if(!Z||!De)return U(we,ye);let Re=["gray","red","yellow","green","magenta"],mt=null,j="";for(let rt=1;rt{let se=await Xu.fetchDescriptorFrom(we,Ae,{project:P,cache:R,preserveModifier:ye,workspace:I});return se!==null?se.range:we.range},ie=async we=>{let ye=U2e.default.valid(we.range)?`^${we.range}`:we.range,[Ae,se]=await Promise.all([ee(we,we.range,ye).catch(()=>null),ee(we,we.range,"latest").catch(()=>null)]),Z=[{value:null,label:we.range}];return Ae&&Ae!==we.range?Z.push({value:Ae,label:W(we.range,Ae)}):Z.push({value:null,label:""}),se&&se!==Ae&&se!==we.range?Z.push({value:se,label:W(we.range,se)}):Z.push({value:null,label:""}),Z},ue=()=>p.createElement(c,{flexDirection:"row"},p.createElement(c,{flexDirection:"column",width:49},p.createElement(c,{marginLeft:1},p.createElement(f,null,"Press ",p.createElement(f,{bold:!0,color:"cyanBright"},""),"/",p.createElement(f,{bold:!0,color:"cyanBright"},"")," to select packages.")),p.createElement(c,{marginLeft:1},p.createElement(f,null,"Press ",p.createElement(f,{bold:!0,color:"cyanBright"},""),"/",p.createElement(f,{bold:!0,color:"cyanBright"},"")," to select versions."))),p.createElement(c,{flexDirection:"column"},p.createElement(c,{marginLeft:1},p.createElement(f,null,"Press ",p.createElement(f,{bold:!0,color:"cyanBright"},"")," to install.")),p.createElement(c,{marginLeft:1},p.createElement(f,null,"Press ",p.createElement(f,{bold:!0,color:"cyanBright"},"")," to abort.")))),le=()=>p.createElement(c,{flexDirection:"row",paddingTop:1,paddingBottom:1},p.createElement(c,{width:50},p.createElement(f,{bold:!0},p.createElement(f,{color:"greenBright"},"?")," Pick the packages you want to upgrade.")),p.createElement(c,{width:17},p.createElement(f,{bold:!0,underline:!0,color:"gray"},"Current")),p.createElement(c,{width:17},p.createElement(f,{bold:!0,underline:!0,color:"gray"},"Range")),p.createElement(c,{width:17},p.createElement(f,{bold:!0,underline:!0,color:"gray"},"Latest"))),me=({active:we,descriptor:ye,suggestions:Ae})=>{let[se,Z]=a(ye.descriptorHash,null),De=G.stringifyIdent(ye),Re=Math.max(0,45-De.length);return p.createElement(p.Fragment,null,p.createElement(c,null,p.createElement(c,{width:45},p.createElement(f,{bold:!0},G.prettyIdent(S,ye)),p.createElement(r,{active:we,length:Re})),p.createElement(e,{active:we,options:Ae,value:se,skewer:!0,onChange:Z,sizes:[17,17,17]})))},pe=({dependencies:we})=>{let[ye,Ae]=C(we.map(()=>null)),se=E(!0),Z=async De=>{let Re=await ie(De);return Re.filter(mt=>mt.label!=="").length<=1?null:{descriptor:De,suggestions:Re}};return h(()=>()=>{se.current=!1},[]),h(()=>{let De=Math.trunc(N*1.75),Re=we.slice(0,De),mt=we.slice(De),j=_2e(mt,N),rt=Re.map(Z).reduce(async(Fe,Ne)=>{await Fe;let Pe=await Ne;Pe!==null&&se.current&&Ae(Ve=>{let ke=Ve.findIndex(Ue=>Ue===null),it=[...Ve];return it[ke]=Pe,it})},Promise.resolve());j.reduce((Fe,Ne)=>Promise.all(Ne.map(Pe=>Promise.resolve().then(()=>Z(Pe)))).then(async Pe=>{Pe=Pe.filter(Ve=>Ve!==null),await Fe,se.current&&Ae(Ve=>{let ke=Ve.findIndex(it=>it===null);return Ve.slice(0,ke).concat(Pe).concat(Ve.slice(ke+Pe.length))})}),rt).then(()=>{se.current&&Ae(Fe=>Fe.filter(Ne=>Ne!==null))})},[]),ye.length?p.createElement(s,{radius:N>>1,children:ye.map((De,Re)=>De!==null?p.createElement(me,{key:Re,active:!1,descriptor:De.descriptor,suggestions:De.suggestions}):p.createElement(f,{key:Re},"Loading..."))}):p.createElement(f,null,"No upgrades found")},Ce=await n(({useSubmit:we})=>{we(a());let ye=new Map;for(let se of P.workspaces)for(let Z of["dependencies","devDependencies"])for(let De of se.manifest[Z].values())P.tryWorkspaceByDescriptor(De)===null&&(De.range.startsWith("link:")||ye.set(De.descriptorHash,De));let Ae=je.sortMap(ye.values(),se=>G.stringifyDescriptor(se));return p.createElement(c,{flexDirection:"column"},p.createElement(ue,null),p.createElement(le,null),p.createElement(pe,{dependencies:Ae}))},{},{stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr});if(typeof Ce>"u")return 1;let g=!1;for(let we of P.workspaces)for(let ye of["dependencies","devDependencies"]){let Ae=we.manifest[ye];for(let se of Ae.values()){let Z=Ce.get(se.descriptorHash);typeof Z<"u"&&Z!==null&&(Ae.set(se.identHash,G.makeDescriptor(se,Z)),g=!0)}}return g?await P.installWithNewReport({quiet:this.context.quiet,stdout:this.context.stdout},{cache:R}):0}};var Sgt={commands:[Iw,Cw]},Dgt=Sgt;var zW={};Vt(zW,{default:()=>kgt});Ge();var BD="jsr:";Ge();Ge();function ww(t){let e=t.range.slice(4);if(Fr.validRange(e))return G.makeDescriptor(t,`npm:${G.stringifyIdent(G.wrapIdentIntoScope(t,"jsr"))}@${e}`);let r=G.tryParseDescriptor(e,!0);if(r!==null)return G.makeDescriptor(t,`npm:${G.stringifyIdent(G.wrapIdentIntoScope(r,"jsr"))}@${r.range}`);throw new Error(`Invalid range: ${t.range}`)}function Bw(t){return G.makeLocator(G.wrapIdentIntoScope(t,"jsr"),`npm:${t.reference.slice(4)}`)}function KW(t){return G.makeLocator(G.unwrapIdentFromScope(t,"jsr"),`jsr:${t.reference.slice(4)}`)}var eN=class{supports(e,r){return e.reference.startsWith(BD)}getLocalPath(e,r){let s=Bw(e);return r.fetcher.getLocalPath(s,r)}fetch(e,r){let s=Bw(e);return r.fetcher.fetch(s,r)}};var tN=class{supportsDescriptor(e,r){return!!e.range.startsWith(BD)}supportsLocator(e,r){return!!e.reference.startsWith(BD)}shouldPersistResolution(e,r){let s=Bw(e);return r.resolver.shouldPersistResolution(s,r)}bindDescriptor(e,r,s){return e}getResolutionDependencies(e,r){return{inner:ww(e)}}async getCandidates(e,r,s){let a=s.project.configuration.normalizeDependency(ww(e));return(await s.resolver.getCandidates(a,r,s)).map(c=>KW(c))}async getSatisfying(e,r,s,a){let n=a.project.configuration.normalizeDependency(ww(e));return a.resolver.getSatisfying(n,r,s,a)}async resolve(e,r){let s=Bw(e),a=await r.resolver.resolve(s,r);return{...a,...KW(a)}}};var bgt=["dependencies","devDependencies","peerDependencies"];function Pgt(t,e){for(let r of bgt)for(let s of t.manifest.getForScope(r).values()){if(!s.range.startsWith("jsr:"))continue;let a=ww(s),n=r==="dependencies"?G.makeDescriptor(s,"unknown"):null,c=n!==null&&t.manifest.ensureDependencyMeta(n).optional?"optionalDependencies":r;e[c][G.stringifyIdent(s)]=a.range}}var xgt={hooks:{beforeWorkspacePacking:Pgt},resolvers:[tN],fetchers:[eN]},kgt=xgt;var XW={};Vt(XW,{LinkFetcher:()=>vD,LinkResolver:()=>SD,PortalFetcher:()=>DD,PortalResolver:()=>bD,default:()=>Tgt});Ge();Dt();var rh="portal:",nh="link:";var vD=class{supports(e,r){return!!e.reference.startsWith(nh)}getLocalPath(e,r){let{parentLocator:s,path:a}=G.parseFileStyleRange(e.reference,{protocol:nh});if(J.isAbsolute(a))return a;let n=r.fetcher.getLocalPath(s,r);return n===null?null:J.resolve(n,a)}async fetch(e,r){let{parentLocator:s,path:a}=G.parseFileStyleRange(e.reference,{protocol:nh}),n=J.isAbsolute(a)?{packageFs:new Sn(vt.root),prefixPath:vt.dot,localPath:vt.root}:await r.fetcher.fetch(s,r),c=n.localPath?{packageFs:new Sn(vt.root),prefixPath:J.relative(vt.root,n.localPath),localPath:vt.root}:n;n!==c&&n.releaseFs&&n.releaseFs();let f=c.packageFs,p=J.resolve(c.localPath??c.packageFs.getRealPath(),c.prefixPath,a);return n.localPath?{packageFs:new Sn(p,{baseFs:f}),releaseFs:c.releaseFs,prefixPath:vt.dot,discardFromLookup:!0,localPath:p}:{packageFs:new Hf(p,{baseFs:f}),releaseFs:c.releaseFs,prefixPath:vt.dot,discardFromLookup:!0}}};Ge();Dt();var SD=class{supportsDescriptor(e,r){return!!e.range.startsWith(nh)}supportsLocator(e,r){return!!e.reference.startsWith(nh)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,s){return G.bindDescriptor(e,{locator:G.stringifyLocator(r)})}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,s){let a=e.range.slice(nh.length);return[G.makeLocator(e,`${nh}${fe.toPortablePath(a)}`)]}async getSatisfying(e,r,s,a){let[n]=await this.getCandidates(e,r,a);return{locators:s.filter(c=>c.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){return{...e,version:"0.0.0",languageName:r.project.configuration.get("defaultLanguageName"),linkType:"SOFT",conditions:null,dependencies:new Map,peerDependencies:new Map,dependenciesMeta:new Map,peerDependenciesMeta:new Map,bin:new Map}}};Ge();Dt();var DD=class{supports(e,r){return!!e.reference.startsWith(rh)}getLocalPath(e,r){let{parentLocator:s,path:a}=G.parseFileStyleRange(e.reference,{protocol:rh});if(J.isAbsolute(a))return a;let n=r.fetcher.getLocalPath(s,r);return n===null?null:J.resolve(n,a)}async fetch(e,r){let{parentLocator:s,path:a}=G.parseFileStyleRange(e.reference,{protocol:rh}),n=J.isAbsolute(a)?{packageFs:new Sn(vt.root),prefixPath:vt.dot,localPath:vt.root}:await r.fetcher.fetch(s,r),c=n.localPath?{packageFs:new Sn(vt.root),prefixPath:J.relative(vt.root,n.localPath),localPath:vt.root}:n;n!==c&&n.releaseFs&&n.releaseFs();let f=c.packageFs,p=J.resolve(c.localPath??c.packageFs.getRealPath(),c.prefixPath,a);return n.localPath?{packageFs:new Sn(p,{baseFs:f}),releaseFs:c.releaseFs,prefixPath:vt.dot,localPath:p}:{packageFs:new Hf(p,{baseFs:f}),releaseFs:c.releaseFs,prefixPath:vt.dot}}};Ge();Ge();Dt();var bD=class{supportsDescriptor(e,r){return!!e.range.startsWith(rh)}supportsLocator(e,r){return!!e.reference.startsWith(rh)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,s){return G.bindDescriptor(e,{locator:G.stringifyLocator(r)})}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,s){let a=e.range.slice(rh.length);return[G.makeLocator(e,`${rh}${fe.toPortablePath(a)}`)]}async getSatisfying(e,r,s,a){let[n]=await this.getCandidates(e,r,a);return{locators:s.filter(c=>c.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let s=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await je.releaseAfterUseAsync(async()=>await Ut.find(s.prefixPath,{baseFs:s.packageFs}),s.releaseFs);return{...e,version:a.version||"0.0.0",languageName:a.languageName||r.project.configuration.get("defaultLanguageName"),linkType:"SOFT",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};var Qgt={fetchers:[vD,DD],resolvers:[SD,bD]},Tgt=Qgt;var FY={};Vt(FY,{NodeModulesLinker:()=>jD,NodeModulesMode:()=>kY,PnpLooseLinker:()=>GD,default:()=>Kdt});Dt();Ge();Dt();Dt();var $W=(t,e)=>`${t}@${e}`,H2e=(t,e)=>{let r=e.indexOf("#"),s=r>=0?e.substring(r+1):e;return $W(t,s)};var G2e=(t,e={})=>{let r=e.debugLevel||Number(process.env.NM_DEBUG_LEVEL||-1),s=e.check||r>=9,a=e.hoistingLimits||new Map,n={check:s,debugLevel:r,hoistingLimits:a,fastLookupPossible:!0},c;n.debugLevel>=0&&(c=Date.now());let f=Ugt(t,n),p=!1,h=0;do{let E=eY(f,[f],new Set([f.locator]),new Map,n);p=E.anotherRoundNeeded||E.isGraphChanged,n.fastLookupPossible=!1,h++}while(p);if(n.debugLevel>=0&&console.log(`hoist time: ${Date.now()-c}ms, rounds: ${h}`),n.debugLevel>=1){let E=PD(f);if(eY(f,[f],new Set([f.locator]),new Map,n).isGraphChanged)throw new Error(`The hoisting result is not terminal, prev tree: +${E}, next tree: +${PD(f)}`);let S=q2e(f);if(S)throw new Error(`${S}, after hoisting finished: +${PD(f)}`)}return n.debugLevel>=2&&console.log(PD(f)),_gt(f)},Rgt=t=>{let e=t[t.length-1],r=new Map,s=new Set,a=n=>{if(!s.has(n)){s.add(n);for(let c of n.hoistedDependencies.values())r.set(c.name,c);for(let c of n.dependencies.values())n.peerNames.has(c.name)||a(c)}};return a(e),r},Fgt=t=>{let e=t[t.length-1],r=new Map,s=new Set,a=new Set,n=(c,f)=>{if(s.has(c))return;s.add(c);for(let h of c.hoistedDependencies.values())if(!f.has(h.name)){let E;for(let C of t)E=C.dependencies.get(h.name),E&&r.set(E.name,E)}let p=new Set;for(let h of c.dependencies.values())p.add(h.name);for(let h of c.dependencies.values())c.peerNames.has(h.name)||n(h,p)};return n(e,a),r},j2e=(t,e)=>{if(e.decoupled)return e;let{name:r,references:s,ident:a,locator:n,dependencies:c,originalDependencies:f,hoistedDependencies:p,peerNames:h,reasons:E,isHoistBorder:C,hoistPriority:S,dependencyKind:P,hoistedFrom:I,hoistedTo:R}=e,N={name:r,references:new Set(s),ident:a,locator:n,dependencies:new Map(c),originalDependencies:new Map(f),hoistedDependencies:new Map(p),peerNames:new Set(h),reasons:new Map(E),decoupled:!0,isHoistBorder:C,hoistPriority:S,dependencyKind:P,hoistedFrom:new Map(I),hoistedTo:new Map(R)},U=N.dependencies.get(r);return U&&U.ident==N.ident&&N.dependencies.set(r,N),t.dependencies.set(N.name,N),N},Ngt=(t,e)=>{let r=new Map([[t.name,[t.ident]]]);for(let a of t.dependencies.values())t.peerNames.has(a.name)||r.set(a.name,[a.ident]);let s=Array.from(e.keys());s.sort((a,n)=>{let c=e.get(a),f=e.get(n);if(f.hoistPriority!==c.hoistPriority)return f.hoistPriority-c.hoistPriority;{let p=c.dependents.size+c.peerDependents.size;return f.dependents.size+f.peerDependents.size-p}});for(let a of s){let n=a.substring(0,a.indexOf("@",1)),c=a.substring(n.length+1);if(!t.peerNames.has(n)){let f=r.get(n);f||(f=[],r.set(n,f)),f.indexOf(c)<0&&f.push(c)}}return r},ZW=t=>{let e=new Set,r=(s,a=new Set)=>{if(!a.has(s)){a.add(s);for(let n of s.peerNames)if(!t.peerNames.has(n)){let c=t.dependencies.get(n);c&&!e.has(c)&&r(c,a)}e.add(s)}};for(let s of t.dependencies.values())t.peerNames.has(s.name)||r(s);return e},eY=(t,e,r,s,a,n=new Set)=>{let c=e[e.length-1];if(n.has(c))return{anotherRoundNeeded:!1,isGraphChanged:!1};n.add(c);let f=Hgt(c),p=Ngt(c,f),h=t==c?new Map:a.fastLookupPossible?Rgt(e):Fgt(e),E,C=!1,S=!1,P=new Map(Array.from(p.entries()).map(([R,N])=>[R,N[0]])),I=new Map;do{let R=Mgt(t,e,r,h,P,p,s,I,a);R.isGraphChanged&&(S=!0),R.anotherRoundNeeded&&(C=!0),E=!1;for(let[N,U]of p)U.length>1&&!c.dependencies.has(N)&&(P.delete(N),U.shift(),P.set(N,U[0]),E=!0)}while(E);for(let R of c.dependencies.values())if(!c.peerNames.has(R.name)&&!r.has(R.locator)){r.add(R.locator);let N=eY(t,[...e,R],r,I,a);N.isGraphChanged&&(S=!0),N.anotherRoundNeeded&&(C=!0),r.delete(R.locator)}return{anotherRoundNeeded:C,isGraphChanged:S}},Ogt=t=>{for(let[e,r]of t.dependencies)if(!t.peerNames.has(e)&&r.ident!==t.ident)return!0;return!1},Lgt=(t,e,r,s,a,n,c,f,{outputReason:p,fastLookupPossible:h})=>{let E,C=null,S=new Set;p&&(E=`${Array.from(e).map(N=>yo(N)).join("\u2192")}`);let P=r[r.length-1],R=!(s.ident===P.ident);if(p&&!R&&(C="- self-reference"),R&&(R=s.dependencyKind!==1,p&&!R&&(C="- workspace")),R&&s.dependencyKind===2&&(R=!Ogt(s),p&&!R&&(C="- external soft link with unhoisted dependencies")),R&&(R=!t.peerNames.has(s.name),p&&!R&&(C=`- cannot shadow peer: ${yo(t.originalDependencies.get(s.name).locator)} at ${E}`)),R){let N=!1,U=a.get(s.name);if(N=!U||U.ident===s.ident,p&&!N&&(C=`- filled by: ${yo(U.locator)} at ${E}`),N)for(let W=r.length-1;W>=1;W--){let ie=r[W].dependencies.get(s.name);if(ie&&ie.ident!==s.ident){N=!1;let ue=f.get(P);ue||(ue=new Set,f.set(P,ue)),ue.add(s.name),p&&(C=`- filled by ${yo(ie.locator)} at ${r.slice(0,W).map(le=>yo(le.locator)).join("\u2192")}`);break}}R=N}if(R&&(R=n.get(s.name)===s.ident,p&&!R&&(C=`- filled by: ${yo(c.get(s.name)[0])} at ${E}`)),R){let N=!0,U=new Set(s.peerNames);for(let W=r.length-1;W>=1;W--){let ee=r[W];for(let ie of U){if(ee.peerNames.has(ie)&&ee.originalDependencies.has(ie))continue;let ue=ee.dependencies.get(ie);ue&&t.dependencies.get(ie)!==ue&&(W===r.length-1?S.add(ue):(S=null,N=!1,p&&(C=`- peer dependency ${yo(ue.locator)} from parent ${yo(ee.locator)} was not hoisted to ${E}`))),U.delete(ie)}if(!N)break}R=N}if(R&&!h)for(let N of s.hoistedDependencies.values()){let U=a.get(N.name)||t.dependencies.get(N.name);if(!U||N.ident!==U.ident){R=!1,p&&(C=`- previously hoisted dependency mismatch, needed: ${yo(N.locator)}, available: ${yo(U?.locator)}`);break}}return S!==null&&S.size>0?{isHoistable:2,dependsOn:S,reason:C}:{isHoistable:R?0:1,reason:C}},rN=t=>`${t.name}@${t.locator}`,Mgt=(t,e,r,s,a,n,c,f,p)=>{let h=e[e.length-1],E=new Set,C=!1,S=!1,P=(U,W,ee,ie,ue)=>{if(E.has(ie))return;let le=[...W,rN(ie)],me=[...ee,rN(ie)],pe=new Map,Be=new Map;for(let Ae of ZW(ie)){let se=Lgt(h,r,[h,...U,ie],Ae,s,a,n,f,{outputReason:p.debugLevel>=2,fastLookupPossible:p.fastLookupPossible});if(Be.set(Ae,se),se.isHoistable===2)for(let Z of se.dependsOn){let De=pe.get(Z.name)||new Set;De.add(Ae.name),pe.set(Z.name,De)}}let Ce=new Set,g=(Ae,se,Z)=>{if(!Ce.has(Ae)){Ce.add(Ae),Be.set(Ae,{isHoistable:1,reason:Z});for(let De of pe.get(Ae.name)||[])g(ie.dependencies.get(De),se,p.debugLevel>=2?`- peer dependency ${yo(Ae.locator)} from parent ${yo(ie.locator)} was not hoisted`:"")}};for(let[Ae,se]of Be)se.isHoistable===1&&g(Ae,se,se.reason);let we=!1;for(let Ae of Be.keys())if(!Ce.has(Ae)){S=!0;let se=c.get(ie);se&&se.has(Ae.name)&&(C=!0),we=!0,ie.dependencies.delete(Ae.name),ie.hoistedDependencies.set(Ae.name,Ae),ie.reasons.delete(Ae.name);let Z=h.dependencies.get(Ae.name);if(p.debugLevel>=2){let De=Array.from(W).concat([ie.locator]).map(mt=>yo(mt)).join("\u2192"),Re=h.hoistedFrom.get(Ae.name);Re||(Re=[],h.hoistedFrom.set(Ae.name,Re)),Re.push(De),ie.hoistedTo.set(Ae.name,Array.from(e).map(mt=>yo(mt.locator)).join("\u2192"))}if(!Z)h.ident!==Ae.ident&&(h.dependencies.set(Ae.name,Ae),ue.add(Ae));else for(let De of Ae.references)Z.references.add(De)}if(ie.dependencyKind===2&&we&&(C=!0),p.check){let Ae=q2e(t);if(Ae)throw new Error(`${Ae}, after hoisting dependencies of ${[h,...U,ie].map(se=>yo(se.locator)).join("\u2192")}: +${PD(t)}`)}let ye=ZW(ie);for(let Ae of ye)if(Ce.has(Ae)){let se=Be.get(Ae);if((a.get(Ae.name)===Ae.ident||!ie.reasons.has(Ae.name))&&se.isHoistable!==0&&ie.reasons.set(Ae.name,se.reason),!Ae.isHoistBorder&&me.indexOf(rN(Ae))<0){E.add(ie);let De=j2e(ie,Ae);P([...U,ie],le,me,De,R),E.delete(ie)}}},I,R=new Set(ZW(h)),N=Array.from(e).map(U=>rN(U));do{I=R,R=new Set;for(let U of I){if(U.locator===h.locator||U.isHoistBorder)continue;let W=j2e(h,U);P([],Array.from(r),N,W,R)}}while(R.size>0);return{anotherRoundNeeded:C,isGraphChanged:S}},q2e=t=>{let e=[],r=new Set,s=new Set,a=(n,c,f)=>{if(r.has(n)||(r.add(n),s.has(n)))return;let p=new Map(c);for(let h of n.dependencies.values())n.peerNames.has(h.name)||p.set(h.name,h);for(let h of n.originalDependencies.values()){let E=p.get(h.name),C=()=>`${Array.from(s).concat([n]).map(S=>yo(S.locator)).join("\u2192")}`;if(n.peerNames.has(h.name)){let S=c.get(h.name);(S!==E||!S||S.ident!==h.ident)&&e.push(`${C()} - broken peer promise: expected ${h.ident} but found ${S&&S.ident}`)}else{let S=f.hoistedFrom.get(n.name),P=n.hoistedTo.get(h.name),I=`${S?` hoisted from ${S.join(", ")}`:""}`,R=`${P?` hoisted to ${P}`:""}`,N=`${C()}${I}`;E?E.ident!==h.ident&&e.push(`${N} - broken require promise for ${h.name}${R}: expected ${h.ident}, but found: ${E.ident}`):e.push(`${N} - broken require promise: no required dependency ${h.name}${R} found`)}}s.add(n);for(let h of n.dependencies.values())n.peerNames.has(h.name)||a(h,p,n);s.delete(n)};return a(t,t.dependencies,t),e.join(` +`)},Ugt=(t,e)=>{let{identName:r,name:s,reference:a,peerNames:n}=t,c={name:s,references:new Set([a]),locator:$W(r,a),ident:H2e(r,a),dependencies:new Map,originalDependencies:new Map,hoistedDependencies:new Map,peerNames:new Set(n),reasons:new Map,decoupled:!0,isHoistBorder:!0,hoistPriority:0,dependencyKind:1,hoistedFrom:new Map,hoistedTo:new Map},f=new Map([[t,c]]),p=(h,E)=>{let C=f.get(h),S=!!C;if(!C){let{name:P,identName:I,reference:R,peerNames:N,hoistPriority:U,dependencyKind:W}=h,ee=e.hoistingLimits.get(E.locator);C={name:P,references:new Set([R]),locator:$W(I,R),ident:H2e(I,R),dependencies:new Map,originalDependencies:new Map,hoistedDependencies:new Map,peerNames:new Set(N),reasons:new Map,decoupled:!0,isHoistBorder:ee?ee.has(P):!1,hoistPriority:U||0,dependencyKind:W||0,hoistedFrom:new Map,hoistedTo:new Map},f.set(h,C)}if(E.dependencies.set(h.name,C),E.originalDependencies.set(h.name,C),S){let P=new Set,I=R=>{if(!P.has(R)){P.add(R),R.decoupled=!1;for(let N of R.dependencies.values())R.peerNames.has(N.name)||I(N)}};I(C)}else for(let P of h.dependencies)p(P,C)};for(let h of t.dependencies)p(h,c);return c},tY=t=>t.substring(0,t.indexOf("@",1)),_gt=t=>{let e={name:t.name,identName:tY(t.locator),references:new Set(t.references),dependencies:new Set},r=new Set([t]),s=(a,n,c)=>{let f=r.has(a),p;if(n===a)p=c;else{let{name:h,references:E,locator:C}=a;p={name:h,identName:tY(C),references:E,dependencies:new Set}}if(c.dependencies.add(p),!f){r.add(a);for(let h of a.dependencies.values())a.peerNames.has(h.name)||s(h,a,p);r.delete(a)}};for(let a of t.dependencies.values())s(a,t,e);return e},Hgt=t=>{let e=new Map,r=new Set([t]),s=c=>`${c.name}@${c.ident}`,a=c=>{let f=s(c),p=e.get(f);return p||(p={dependents:new Set,peerDependents:new Set,hoistPriority:0},e.set(f,p)),p},n=(c,f)=>{let p=!!r.has(f);if(a(f).dependents.add(c.ident),!p){r.add(f);for(let E of f.dependencies.values()){let C=a(E);C.hoistPriority=Math.max(C.hoistPriority,E.hoistPriority),f.peerNames.has(E.name)?C.peerDependents.add(f.ident):n(f,E)}}};for(let c of t.dependencies.values())t.peerNames.has(c.name)||n(t,c);return e},yo=t=>{if(!t)return"none";let e=t.indexOf("@",1),r=t.substring(0,e);r.endsWith("$wsroot$")&&(r=`wh:${r.replace("$wsroot$","")}`);let s=t.substring(e+1);if(s==="workspace:.")return".";if(s){let a=(s.indexOf("#")>0?s.split("#")[1]:s).replace("npm:","");return s.startsWith("virtual")&&(r=`v:${r}`),a.startsWith("workspace")&&(r=`w:${r}`,a=""),`${r}${a?`@${a}`:""}`}else return`${r}`};var PD=t=>{let e=0,r=(a,n,c="")=>{if(e>5e4||n.has(a))return"";e++;let f=Array.from(a.dependencies.values()).sort((h,E)=>h.name===E.name?0:h.name>E.name?1:-1),p="";n.add(a);for(let h=0;h":"")+(S!==E.name?`a:${E.name}:`:"")+yo(E.locator)+(C?` ${C}`:"")} +`,p+=r(E,n,`${c}${h5e4?` +Tree is too large, part of the tree has been dunped +`:"")};var xD=(s=>(s.WORKSPACES="workspaces",s.DEPENDENCIES="dependencies",s.NONE="none",s))(xD||{}),W2e="node_modules",rg="$wsroot$";var kD=(t,e)=>{let{packageTree:r,hoistingLimits:s,errors:a,preserveSymlinksRequired:n}=Ggt(t,e),c=null;if(a.length===0){let f=G2e(r,{hoistingLimits:s});c=Wgt(t,f,e)}return{tree:c,errors:a,preserveSymlinksRequired:n}},pA=t=>`${t.name}@${t.reference}`,nY=t=>{let e=new Map;for(let[r,s]of t.entries())if(!s.dirList){let a=e.get(s.locator);a||(a={target:s.target,linkType:s.linkType,locations:[],aliases:s.aliases},e.set(s.locator,a)),a.locations.push(r)}for(let r of e.values())r.locations=r.locations.sort((s,a)=>{let n=s.split(J.delimiter).length,c=a.split(J.delimiter).length;return a===s?0:n!==c?c-n:a>s?1:-1});return e},Y2e=(t,e)=>{let r=G.isVirtualLocator(t)?G.devirtualizeLocator(t):t,s=G.isVirtualLocator(e)?G.devirtualizeLocator(e):e;return G.areLocatorsEqual(r,s)},rY=(t,e,r,s)=>{if(t.linkType!=="SOFT")return!1;let a=fe.toPortablePath(r.resolveVirtual&&e.reference&&e.reference.startsWith("virtual:")?r.resolveVirtual(t.packageLocation):t.packageLocation);return J.contains(s,a)===null},jgt=t=>{let e=t.getPackageInformation(t.topLevel);if(e===null)throw new Error("Assertion failed: Expected the top-level package to have been registered");if(t.findPackageLocator(e.packageLocation)===null)throw new Error("Assertion failed: Expected the top-level package to have a physical locator");let s=fe.toPortablePath(e.packageLocation.slice(0,-1)),a=new Map,n={children:new Map},c=t.getDependencyTreeRoots(),f=new Map,p=new Set,h=(S,P)=>{let I=pA(S);if(p.has(I))return;p.add(I);let R=t.getPackageInformation(S);if(R){let N=P?pA(P):"";if(pA(S)!==N&&R.linkType==="SOFT"&&!S.reference.startsWith("link:")&&!rY(R,S,t,s)){let U=V2e(R,S,t);(!f.get(U)||S.reference.startsWith("workspace:"))&&f.set(U,S)}for(let[U,W]of R.packageDependencies)W!==null&&(R.packagePeers.has(U)||h(t.getLocator(U,W),S))}};for(let S of c)h(S,null);let E=s.split(J.sep);for(let S of f.values()){let P=t.getPackageInformation(S),R=fe.toPortablePath(P.packageLocation.slice(0,-1)).split(J.sep).slice(E.length),N=n;for(let U of R){let W=N.children.get(U);W||(W={children:new Map},N.children.set(U,W)),N=W}N.workspaceLocator=S}let C=(S,P)=>{if(S.workspaceLocator){let I=pA(P),R=a.get(I);R||(R=new Set,a.set(I,R)),R.add(S.workspaceLocator)}for(let I of S.children.values())C(I,S.workspaceLocator||P)};for(let S of n.children.values())C(S,n.workspaceLocator);return a},Ggt=(t,e)=>{let r=[],s=!1,a=new Map,n=jgt(t),c=t.getPackageInformation(t.topLevel);if(c===null)throw new Error("Assertion failed: Expected the top-level package to have been registered");let f=t.findPackageLocator(c.packageLocation);if(f===null)throw new Error("Assertion failed: Expected the top-level package to have a physical locator");let p=fe.toPortablePath(c.packageLocation.slice(0,-1)),h={name:f.name,identName:f.name,reference:f.reference,peerNames:c.packagePeers,dependencies:new Set,dependencyKind:1},E=new Map,C=(P,I)=>`${pA(I)}:${P}`,S=(P,I,R,N,U,W,ee,ie)=>{let ue=C(P,R),le=E.get(ue),me=!!le;!me&&R.name===f.name&&R.reference===f.reference&&(le=h,E.set(ue,h));let pe=rY(I,R,t,p);if(!le){let Ae=0;pe?Ae=2:I.linkType==="SOFT"&&R.name.endsWith(rg)&&(Ae=1),le={name:P,identName:R.name,reference:R.reference,dependencies:new Set,peerNames:Ae===1?new Set:I.packagePeers,dependencyKind:Ae},E.set(ue,le)}let Be;if(pe?Be=2:U.linkType==="SOFT"?Be=1:Be=0,le.hoistPriority=Math.max(le.hoistPriority||0,Be),ie&&!pe){let Ae=pA({name:N.identName,reference:N.reference}),se=a.get(Ae)||new Set;a.set(Ae,se),se.add(le.name)}let Ce=new Map(I.packageDependencies);if(e.project){let Ae=e.project.workspacesByCwd.get(fe.toPortablePath(I.packageLocation.slice(0,-1)));if(Ae){let se=new Set([...Array.from(Ae.manifest.peerDependencies.values(),Z=>G.stringifyIdent(Z)),...Array.from(Ae.manifest.peerDependenciesMeta.keys())]);for(let Z of se)Ce.has(Z)||(Ce.set(Z,W.get(Z)||null),le.peerNames.add(Z))}}let g=pA({name:R.name.replace(rg,""),reference:R.reference}),we=n.get(g);if(we)for(let Ae of we)Ce.set(`${Ae.name}${rg}`,Ae.reference);(I!==U||I.linkType!=="SOFT"||!pe&&(!e.selfReferencesByCwd||e.selfReferencesByCwd.get(ee)))&&N.dependencies.add(le);let ye=R!==f&&I.linkType==="SOFT"&&!R.name.endsWith(rg)&&!pe;if(!me&&!ye){let Ae=new Map;for(let[se,Z]of Ce)if(Z!==null){let De=t.getLocator(se,Z),Re=t.getLocator(se.replace(rg,""),Z),mt=t.getPackageInformation(Re);if(mt===null)throw new Error("Assertion failed: Expected the package to have been registered");let j=rY(mt,De,t,p);if(e.validateExternalSoftLinks&&e.project&&j){mt.packageDependencies.size>0&&(s=!0);for(let[Ve,ke]of mt.packageDependencies)if(ke!==null){let it=G.parseLocator(Array.isArray(ke)?`${ke[0]}@${ke[1]}`:`${Ve}@${ke}`);if(pA(it)!==pA(De)){let Ue=Ce.get(Ve);if(Ue){let x=G.parseLocator(Array.isArray(Ue)?`${Ue[0]}@${Ue[1]}`:`${Ve}@${Ue}`);Y2e(x,it)||r.push({messageName:71,text:`Cannot link ${G.prettyIdent(e.project.configuration,G.parseIdent(De.name))} into ${G.prettyLocator(e.project.configuration,G.parseLocator(`${R.name}@${R.reference}`))} dependency ${G.prettyLocator(e.project.configuration,it)} conflicts with parent dependency ${G.prettyLocator(e.project.configuration,x)}`})}else{let x=Ae.get(Ve);if(x){let w=x.target,b=G.parseLocator(Array.isArray(w)?`${w[0]}@${w[1]}`:`${Ve}@${w}`);Y2e(b,it)||r.push({messageName:71,text:`Cannot link ${G.prettyIdent(e.project.configuration,G.parseIdent(De.name))} into ${G.prettyLocator(e.project.configuration,G.parseLocator(`${R.name}@${R.reference}`))} dependency ${G.prettyLocator(e.project.configuration,it)} conflicts with dependency ${G.prettyLocator(e.project.configuration,b)} from sibling portal ${G.prettyIdent(e.project.configuration,G.parseIdent(x.portal.name))}`})}else Ae.set(Ve,{target:it.reference,portal:De})}}}}let rt=e.hoistingLimitsByCwd?.get(ee),Fe=j?ee:J.relative(p,fe.toPortablePath(mt.packageLocation))||vt.dot,Ne=e.hoistingLimitsByCwd?.get(Fe);S(se,mt,De,le,I,Ce,Fe,rt==="dependencies"||Ne==="dependencies"||Ne==="workspaces")}}};return S(f.name,c,f,h,c,c.packageDependencies,vt.dot,!1),{packageTree:h,hoistingLimits:a,errors:r,preserveSymlinksRequired:s}};function V2e(t,e,r){let s=r.resolveVirtual&&e.reference&&e.reference.startsWith("virtual:")?r.resolveVirtual(t.packageLocation):t.packageLocation;return fe.toPortablePath(s||t.packageLocation)}function qgt(t,e,r){let s=e.getLocator(t.name.replace(rg,""),t.reference),a=e.getPackageInformation(s);if(a===null)throw new Error("Assertion failed: Expected the package to be registered");return r.pnpifyFs?{linkType:"SOFT",target:fe.toPortablePath(a.packageLocation)}:{linkType:a.linkType,target:V2e(a,t,e)}}var Wgt=(t,e,r)=>{let s=new Map,a=(E,C,S)=>{let{linkType:P,target:I}=qgt(E,t,r);return{locator:pA(E),nodePath:C,target:I,linkType:P,aliases:S}},n=E=>{let[C,S]=E.split("/");return S?{scope:C,name:S}:{scope:null,name:C}},c=new Set,f=(E,C,S)=>{if(c.has(E))return;c.add(E);let P=Array.from(E.references).sort().join("#");for(let I of E.dependencies){let R=Array.from(I.references).sort().join("#");if(I.identName===E.identName.replace(rg,"")&&R===P)continue;let N=Array.from(I.references).sort(),U={name:I.identName,reference:N[0]},{name:W,scope:ee}=n(I.name),ie=ee?[ee,W]:[W],ue=J.join(C,W2e),le=J.join(ue,...ie),me=`${S}/${U.name}`,pe=a(U,S,N.slice(1)),Be=!1;if(pe.linkType==="SOFT"&&r.project){let Ce=r.project.workspacesByCwd.get(pe.target.slice(0,-1));Be=!!(Ce&&!Ce.manifest.name)}if(!I.name.endsWith(rg)&&!Be){let Ce=s.get(le);if(Ce){if(Ce.dirList)throw new Error(`Assertion failed: ${le} cannot merge dir node with leaf node`);{let ye=G.parseLocator(Ce.locator),Ae=G.parseLocator(pe.locator);if(Ce.linkType!==pe.linkType)throw new Error(`Assertion failed: ${le} cannot merge nodes with different link types ${Ce.nodePath}/${G.stringifyLocator(ye)} and ${S}/${G.stringifyLocator(Ae)}`);if(ye.identHash!==Ae.identHash)throw new Error(`Assertion failed: ${le} cannot merge nodes with different idents ${Ce.nodePath}/${G.stringifyLocator(ye)} and ${S}/s${G.stringifyLocator(Ae)}`);pe.aliases=[...pe.aliases,...Ce.aliases,G.parseLocator(Ce.locator).reference]}}s.set(le,pe);let g=le.split("/"),we=g.indexOf(W2e);for(let ye=g.length-1;we>=0&&ye>we;ye--){let Ae=fe.toPortablePath(g.slice(0,ye).join(J.sep)),se=g[ye],Z=s.get(Ae);if(!Z)s.set(Ae,{dirList:new Set([se])});else if(Z.dirList){if(Z.dirList.has(se))break;Z.dirList.add(se)}}}f(I,pe.linkType==="SOFT"?pe.target:le,me)}},p=a({name:e.name,reference:Array.from(e.references)[0]},"",[]),h=p.target;return s.set(h,p),f(e,h,""),s};Ge();Ge();Dt();Dt();eA();wc();var wY={};Vt(wY,{PnpInstaller:()=>Gm,PnpLinker:()=>sg,UnplugCommand:()=>Sw,default:()=>Cdt,getPnpPath:()=>og,jsInstallUtils:()=>gA,pnpUtils:()=>HD,quotePathIfNeeded:()=>QBe});Dt();var kBe=Ie("url");Ge();Ge();Dt();Dt();var J2e={DEFAULT:{collapsed:!1,next:{"*":"DEFAULT"}},TOP_LEVEL:{collapsed:!1,next:{fallbackExclusionList:"FALLBACK_EXCLUSION_LIST",packageRegistryData:"PACKAGE_REGISTRY_DATA","*":"DEFAULT"}},FALLBACK_EXCLUSION_LIST:{collapsed:!1,next:{"*":"FALLBACK_EXCLUSION_ENTRIES"}},FALLBACK_EXCLUSION_ENTRIES:{collapsed:!0,next:{"*":"FALLBACK_EXCLUSION_DATA"}},FALLBACK_EXCLUSION_DATA:{collapsed:!0,next:{"*":"DEFAULT"}},PACKAGE_REGISTRY_DATA:{collapsed:!1,next:{"*":"PACKAGE_REGISTRY_ENTRIES"}},PACKAGE_REGISTRY_ENTRIES:{collapsed:!0,next:{"*":"PACKAGE_STORE_DATA"}},PACKAGE_STORE_DATA:{collapsed:!1,next:{"*":"PACKAGE_STORE_ENTRIES"}},PACKAGE_STORE_ENTRIES:{collapsed:!0,next:{"*":"PACKAGE_INFORMATION_DATA"}},PACKAGE_INFORMATION_DATA:{collapsed:!1,next:{packageDependencies:"PACKAGE_DEPENDENCIES","*":"DEFAULT"}},PACKAGE_DEPENDENCIES:{collapsed:!1,next:{"*":"PACKAGE_DEPENDENCY"}},PACKAGE_DEPENDENCY:{collapsed:!0,next:{"*":"DEFAULT"}}};function Ygt(t,e,r){let s="";s+="[";for(let a=0,n=t.length;a"u"||(f!==0&&(a+=", "),a+=JSON.stringify(p),a+=": ",a+=nN(p,h,e,r).replace(/^ +/g,""),f+=1)}return a+="}",a}function Kgt(t,e,r){let s=Object.keys(t),a=`${r} `,n="";n+=r,n+=`{ +`;let c=0;for(let f=0,p=s.length;f"u"||(c!==0&&(n+=",",n+=` +`),n+=a,n+=JSON.stringify(h),n+=": ",n+=nN(h,E,e,a).replace(/^ +/g,""),c+=1)}return c!==0&&(n+=` +`),n+=r,n+="}",n}function nN(t,e,r,s){let{next:a}=J2e[r],n=a[t]||a["*"];return K2e(e,n,s)}function K2e(t,e,r){let{collapsed:s}=J2e[e];return Array.isArray(t)?s?Ygt(t,e,r):Vgt(t,e,r):typeof t=="object"&&t!==null?s?Jgt(t,e,r):Kgt(t,e,r):JSON.stringify(t)}function z2e(t){return K2e(t,"TOP_LEVEL","")}function QD(t,e){let r=Array.from(t);Array.isArray(e)||(e=[e]);let s=[];for(let n of e)s.push(r.map(c=>n(c)));let a=r.map((n,c)=>c);return a.sort((n,c)=>{for(let f of s){let p=f[n]f[c]?1:0;if(p!==0)return p}return 0}),a.map(n=>r[n])}function zgt(t){let e=new Map,r=QD(t.fallbackExclusionList||[],[({name:s,reference:a})=>s,({name:s,reference:a})=>a]);for(let{name:s,reference:a}of r){let n=e.get(s);typeof n>"u"&&e.set(s,n=new Set),n.add(a)}return Array.from(e).map(([s,a])=>[s,Array.from(a)])}function Xgt(t){return QD(t.fallbackPool||[],([e])=>e)}function Zgt(t){let e=[],r=t.dependencyTreeRoots.find(s=>t.packageRegistry.get(s.name)?.get(s.reference)?.packageLocation==="./");for(let[s,a]of QD(t.packageRegistry,([n])=>n===null?"0":`1${n}`)){if(s===null)continue;let n=[];e.push([s,n]);for(let[c,{packageLocation:f,packageDependencies:p,packagePeers:h,linkType:E,discardFromLookup:C}]of QD(a,([S])=>S===null?"0":`1${S}`)){if(c===null)continue;let S=[];s!==null&&c!==null&&!p.has(s)&&S.push([s,c]);for(let[U,W]of p)S.push([U,W]);let P=QD(S,([U])=>U),I=h&&h.size>0?Array.from(h):void 0,N={packageLocation:f,packageDependencies:P,packagePeers:I,linkType:E,discardFromLookup:C||void 0};n.push([c,N]),r&&s===r.name&&c===r.reference&&e.unshift([null,[[null,N]]])}}return e}function TD(t){return{__info:["This file is automatically generated. Do not touch it, or risk","your modifications being lost."],dependencyTreeRoots:t.dependencyTreeRoots,enableTopLevelFallback:t.enableTopLevelFallback||!1,ignorePatternData:t.ignorePattern||null,pnpZipBackend:t.pnpZipBackend,fallbackExclusionList:zgt(t),fallbackPool:Xgt(t),packageRegistryData:Zgt(t)}}var $2e=ut(Z2e());function eBe(t,e){return[t?`${t} +`:"",`/* eslint-disable */ +`,`// @ts-nocheck +`,`"use strict"; +`,` +`,e,` +`,(0,$2e.default)()].join("")}function $gt(t){return JSON.stringify(t,null,2)}function edt(t){return`'${t.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(/\n/g,`\\ +`)}'`}function tdt(t){return[`const RAW_RUNTIME_STATE = +`,`${edt(z2e(t))}; + +`,`function $$SETUP_STATE(hydrateRuntimeState, basePath) { +`,` return hydrateRuntimeState(JSON.parse(RAW_RUNTIME_STATE), {basePath: basePath || __dirname}); +`,`} +`].join("")}function rdt(){return[`function $$SETUP_STATE(hydrateRuntimeState, basePath) { +`,` const fs = require('fs'); +`,` const path = require('path'); +`,` const pnpDataFilepath = path.resolve(__dirname, ${JSON.stringify(Er.pnpData)}); +`,` return hydrateRuntimeState(JSON.parse(fs.readFileSync(pnpDataFilepath, 'utf8')), {basePath: basePath || __dirname}); +`,`} +`].join("")}function tBe(t){let e=TD(t),r=tdt(e);return eBe(t.shebang,r)}function rBe(t){let e=TD(t),r=rdt(),s=eBe(t.shebang,r);return{dataFile:$gt(e),loaderFile:s}}Dt();function sY(t,{basePath:e}){let r=fe.toPortablePath(e),s=J.resolve(r),a=t.ignorePatternData!==null?new RegExp(t.ignorePatternData):null,n=new Map,c=new Map(t.packageRegistryData.map(([C,S])=>[C,new Map(S.map(([P,I])=>{if(C===null!=(P===null))throw new Error("Assertion failed: The name and reference should be null, or neither should");let R=I.discardFromLookup??!1,N={name:C,reference:P},U=n.get(I.packageLocation);U?(U.discardFromLookup=U.discardFromLookup&&R,R||(U.locator=N)):n.set(I.packageLocation,{locator:N,discardFromLookup:R});let W=null;return[P,{packageDependencies:new Map(I.packageDependencies),packagePeers:new Set(I.packagePeers),linkType:I.linkType,discardFromLookup:R,get packageLocation(){return W||(W=J.join(s,I.packageLocation))}}]}))])),f=new Map(t.fallbackExclusionList.map(([C,S])=>[C,new Set(S)])),p=new Map(t.fallbackPool),h=t.dependencyTreeRoots,E=t.enableTopLevelFallback;return{basePath:r,dependencyTreeRoots:h,enableTopLevelFallback:E,fallbackExclusionList:f,pnpZipBackend:t.pnpZipBackend,fallbackPool:p,ignorePattern:a,packageLocatorsByLocations:n,packageRegistry:c}}Dt();Dt();var sh=Ie("module"),jm=Ie("url"),gY=Ie("util");var ta=Ie("url");var oBe=ut(Ie("assert"));var oY=Array.isArray,RD=JSON.stringify,FD=Object.getOwnPropertyNames,Hm=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),aY=(t,e)=>RegExp.prototype.exec.call(t,e),lY=(t,...e)=>RegExp.prototype[Symbol.replace].apply(t,e),ng=(t,...e)=>String.prototype.endsWith.apply(t,e),cY=(t,...e)=>String.prototype.includes.apply(t,e),uY=(t,...e)=>String.prototype.lastIndexOf.apply(t,e),ND=(t,...e)=>String.prototype.indexOf.apply(t,e),nBe=(t,...e)=>String.prototype.replace.apply(t,e),ig=(t,...e)=>String.prototype.slice.apply(t,e),hA=(t,...e)=>String.prototype.startsWith.apply(t,e),iBe=Map,sBe=JSON.parse;function OD(t,e,r){return class extends r{constructor(...s){super(e(...s)),this.code=t,this.name=`${r.name} [${t}]`}}}var aBe=OD("ERR_PACKAGE_IMPORT_NOT_DEFINED",(t,e,r)=>`Package import specifier "${t}" is not defined${e?` in package ${e}package.json`:""} imported from ${r}`,TypeError),fY=OD("ERR_INVALID_MODULE_SPECIFIER",(t,e,r=void 0)=>`Invalid module "${t}" ${e}${r?` imported from ${r}`:""}`,TypeError),lBe=OD("ERR_INVALID_PACKAGE_TARGET",(t,e,r,s=!1,a=void 0)=>{let n=typeof r=="string"&&!s&&r.length&&!hA(r,"./");return e==="."?((0,oBe.default)(s===!1),`Invalid "exports" main target ${RD(r)} defined in the package config ${t}package.json${a?` imported from ${a}`:""}${n?'; targets must start with "./"':""}`):`Invalid "${s?"imports":"exports"}" target ${RD(r)} defined for '${e}' in the package config ${t}package.json${a?` imported from ${a}`:""}${n?'; targets must start with "./"':""}`},Error),LD=OD("ERR_INVALID_PACKAGE_CONFIG",(t,e,r)=>`Invalid package config ${t}${e?` while importing ${e}`:""}${r?`. ${r}`:""}`,Error),cBe=OD("ERR_PACKAGE_PATH_NOT_EXPORTED",(t,e,r=void 0)=>e==="."?`No "exports" main defined in ${t}package.json${r?` imported from ${r}`:""}`:`Package subpath '${e}' is not defined by "exports" in ${t}package.json${r?` imported from ${r}`:""}`,Error);var sN=Ie("url");function uBe(t,e){let r=Object.create(null);for(let s=0;se):t+e}MD(r,t,s,c,a)}aY(ABe,ig(t,2))!==null&&MD(r,t,s,c,a);let p=new URL(t,s),h=p.pathname,E=new URL(".",s).pathname;if(hA(h,E)||MD(r,t,s,c,a),e==="")return p;if(aY(ABe,e)!==null){let C=n?nBe(r,"*",()=>e):r+e;sdt(C,s,c,a)}return n?new URL(lY(pBe,p.href,()=>e)):new URL(e,p)}function adt(t){let e=+t;return`${e}`!==t?!1:e>=0&&e<4294967295}function vw(t,e,r,s,a,n,c,f){if(typeof e=="string")return odt(e,r,s,t,a,n,c,f);if(oY(e)){if(e.length===0)return null;let p;for(let h=0;hn?-1:n>a||r===-1?1:s===-1||t.length>e.length?-1:e.length>t.length?1:0}function ldt(t,e,r){if(typeof t=="string"||oY(t))return!0;if(typeof t!="object"||t===null)return!1;let s=FD(t),a=!1,n=0;for(let c=0;c=h.length&&ng(e,C)&&gBe(n,h)===1&&uY(h,"*")===E&&(n=h,c=ig(e,E,e.length-C.length))}}if(n){let p=r[n],h=vw(t,p,c,n,s,!0,!1,a);return h==null&&AY(e,t,s),h}AY(e,t,s)}function mBe({name:t,base:e,conditions:r,readFileSyncFn:s}){if(t==="#"||hA(t,"#/")||ng(t,"/")){let c="is not a valid internal imports specifier name";throw new fY(t,c,(0,ta.fileURLToPath)(e))}let a,n=fBe(e,s);if(n.exists){a=(0,ta.pathToFileURL)(n.pjsonPath);let c=n.imports;if(c)if(Hm(c,t)&&!cY(t,"*")){let f=vw(a,c[t],"",t,e,!1,!0,r);if(f!=null)return f}else{let f="",p,h=FD(c);for(let E=0;E=C.length&&ng(t,P)&&gBe(f,C)===1&&uY(C,"*")===S&&(f=C,p=ig(t,S,t.length-P.length))}}if(f){let E=c[f],C=vw(a,E,p,f,e,!0,!0,r);if(C!=null)return C}}}idt(t,a,e)}Dt();var udt=new Set(["BUILTIN_NODE_RESOLUTION_FAILED","MISSING_DEPENDENCY","MISSING_PEER_DEPENDENCY","QUALIFIED_PATH_RESOLUTION_FAILED","UNDECLARED_DEPENDENCY"]);function gs(t,e,r={},s){s??=udt.has(t)?"MODULE_NOT_FOUND":t;let a={configurable:!0,writable:!0,enumerable:!1};return Object.defineProperties(new Error(e),{code:{...a,value:s},pnpCode:{...a,value:t},data:{...a,value:r}})}function lf(t){return fe.normalize(fe.fromPortablePath(t))}var CBe=ut(EBe());function wBe(t){return fdt(),hY[t]}var hY;function fdt(){hY||(hY={"--conditions":[],...IBe(Adt()),...IBe(process.execArgv)})}function IBe(t){return(0,CBe.default)({"--conditions":[String],"-C":"--conditions"},{argv:t,permissive:!0})}function Adt(){let t=[],e=pdt(process.env.NODE_OPTIONS||"",t);return t.length,e}function pdt(t,e){let r=[],s=!1,a=!0;for(let n=0;nparseInt(t,10)),BBe=ml>19||ml===19&&ih>=2||ml===18&&ih>=13,UZt=ml===20&&ih<6||ml===19&&ih>=3,_Zt=ml>19||ml===19&&ih>=6,HZt=ml>=21||ml===20&&ih>=10||ml===18&&ih>=19,jZt=ml>=21||ml===20&&ih>=10||ml===18&&ih>=20,GZt=ml>=22;function vBe(t){if(process.env.WATCH_REPORT_DEPENDENCIES&&process.send)if(t=t.map(e=>fe.fromPortablePath(uo.resolveVirtual(fe.toPortablePath(e)))),BBe)process.send({"watch:require":t});else for(let e of t)process.send({"watch:require":e})}function dY(t,e){let r=Number(process.env.PNP_ALWAYS_WARN_ON_FALLBACK)>0,s=Number(process.env.PNP_DEBUG_LEVEL),a=/^(?![a-zA-Z]:[\\/]|\\\\|\.{0,2}(?:\/|$))((?:node:)?(?:@[^/]+\/)?[^/]+)\/*(.*|)$/,n=/^(\/|\.{1,2}(\/|$))/,c=/\/$/,f=/^\.{0,2}\//,p={name:null,reference:null},h=[],E=new Set;if(t.enableTopLevelFallback===!0&&h.push(p),e.compatibilityMode!==!1)for(let Fe of["react-scripts","gatsby"]){let Ne=t.packageRegistry.get(Fe);if(Ne)for(let Pe of Ne.keys()){if(Pe===null)throw new Error("Assertion failed: This reference shouldn't be null");h.push({name:Fe,reference:Pe})}}let{ignorePattern:C,packageRegistry:S,packageLocatorsByLocations:P}=t;function I(Fe,Ne){return{fn:Fe,args:Ne,error:null,result:null}}function R(Fe){let Ne=process.stderr?.hasColors?.()??process.stdout.isTTY,Pe=(it,Ue)=>`\x1B[${it}m${Ue}\x1B[0m`,Ve=Fe.error;console.error(Ve?Pe("31;1",`\u2716 ${Fe.error?.message.replace(/\n.*/s,"")}`):Pe("33;1","\u203C Resolution")),Fe.args.length>0&&console.error();for(let it of Fe.args)console.error(` ${Pe("37;1","In \u2190")} ${(0,gY.inspect)(it,{colors:Ne,compact:!0})}`);Fe.result&&(console.error(),console.error(` ${Pe("37;1","Out \u2192")} ${(0,gY.inspect)(Fe.result,{colors:Ne,compact:!0})}`));let ke=new Error().stack.match(/(?<=^ +)at.*/gm)?.slice(2)??[];if(ke.length>0){console.error();for(let it of ke)console.error(` ${Pe("38;5;244",it)}`)}console.error()}function N(Fe,Ne){if(e.allowDebug===!1)return Ne;if(Number.isFinite(s)){if(s>=2)return(...Pe)=>{let Ve=I(Fe,Pe);try{return Ve.result=Ne(...Pe)}catch(ke){throw Ve.error=ke}finally{R(Ve)}};if(s>=1)return(...Pe)=>{try{return Ne(...Pe)}catch(Ve){let ke=I(Fe,Pe);throw ke.error=Ve,R(ke),Ve}}}return Ne}function U(Fe){let Ne=g(Fe);if(!Ne)throw gs("INTERNAL","Couldn't find a matching entry in the dependency tree for the specified parent (this is probably an internal error)");return Ne}function W(Fe){if(Fe.name===null)return!0;for(let Ne of t.dependencyTreeRoots)if(Ne.name===Fe.name&&Ne.reference===Fe.reference)return!0;return!1}let ee=new Set(["node","require",...wBe("--conditions")]);function ie(Fe,Ne=ee,Pe){let Ve=Ae(J.join(Fe,"internal.js"),{resolveIgnored:!0,includeDiscardFromLookup:!0});if(Ve===null)throw gs("INTERNAL",`The locator that owns the "${Fe}" path can't be found inside the dependency tree (this is probably an internal error)`);let{packageLocation:ke}=U(Ve),it=J.join(ke,Er.manifest);if(!e.fakeFs.existsSync(it))return null;let Ue=JSON.parse(e.fakeFs.readFileSync(it,"utf8"));if(Ue.exports==null)return null;let x=J.contains(ke,Fe);if(x===null)throw gs("INTERNAL","unqualifiedPath doesn't contain the packageLocation (this is probably an internal error)");x!=="."&&!f.test(x)&&(x=`./${x}`);try{let w=dBe({packageJSONUrl:(0,jm.pathToFileURL)(fe.fromPortablePath(it)),packageSubpath:x,exports:Ue.exports,base:Pe?(0,jm.pathToFileURL)(fe.fromPortablePath(Pe)):null,conditions:Ne});return fe.toPortablePath((0,jm.fileURLToPath)(w))}catch(w){throw gs("EXPORTS_RESOLUTION_FAILED",w.message,{unqualifiedPath:lf(Fe),locator:Ve,pkgJson:Ue,subpath:lf(x),conditions:Ne},w.code)}}function ue(Fe,Ne,{extensions:Pe}){let Ve;try{Ne.push(Fe),Ve=e.fakeFs.statSync(Fe)}catch{}if(Ve&&!Ve.isDirectory())return e.fakeFs.realpathSync(Fe);if(Ve&&Ve.isDirectory()){let ke;try{ke=JSON.parse(e.fakeFs.readFileSync(J.join(Fe,Er.manifest),"utf8"))}catch{}let it;if(ke&&ke.main&&(it=J.resolve(Fe,ke.main)),it&&it!==Fe){let Ue=ue(it,Ne,{extensions:Pe});if(Ue!==null)return Ue}}for(let ke=0,it=Pe.length;ke{let x=JSON.stringify(Ue.name);if(Ve.has(x))return;Ve.add(x);let w=we(Ue);for(let b of w)if(U(b).packagePeers.has(Fe))ke(b);else{let F=Pe.get(b.name);typeof F>"u"&&Pe.set(b.name,F=new Set),F.add(b.reference)}};ke(Ne);let it=[];for(let Ue of[...Pe.keys()].sort())for(let x of[...Pe.get(Ue)].sort())it.push({name:Ue,reference:x});return it}function Ae(Fe,{resolveIgnored:Ne=!1,includeDiscardFromLookup:Pe=!1}={}){if(pe(Fe)&&!Ne)return null;let Ve=J.relative(t.basePath,Fe);Ve.match(n)||(Ve=`./${Ve}`),Ve.endsWith("/")||(Ve=`${Ve}/`);do{let ke=P.get(Ve);if(typeof ke>"u"||ke.discardFromLookup&&!Pe){Ve=Ve.substring(0,Ve.lastIndexOf("/",Ve.length-2)+1);continue}return ke.locator}while(Ve!=="");return null}function se(Fe){try{return e.fakeFs.readFileSync(fe.toPortablePath(Fe),"utf8")}catch(Ne){if(Ne.code==="ENOENT")return;throw Ne}}function Z(Fe,Ne,{considerBuiltins:Pe=!0}={}){if(Fe.startsWith("#"))throw new Error("resolveToUnqualified can not handle private import mappings");if(Fe==="pnpapi")return fe.toPortablePath(e.pnpapiResolution);if(Pe&&(0,sh.isBuiltin)(Fe))return null;let Ve=lf(Fe),ke=Ne&&lf(Ne);if(Ne&&pe(Ne)&&(!J.isAbsolute(Fe)||Ae(Fe)===null)){let x=me(Fe,Ne);if(x===!1)throw gs("BUILTIN_NODE_RESOLUTION_FAILED",`The builtin node resolution algorithm was unable to resolve the requested module (it didn't go through the pnp resolver because the issuer was explicitely ignored by the regexp) + +Require request: "${Ve}" +Required by: ${ke} +`,{request:Ve,issuer:ke});return fe.toPortablePath(x)}let it,Ue=Fe.match(a);if(Ue){if(!Ne)throw gs("API_ERROR","The resolveToUnqualified function must be called with a valid issuer when the path isn't a builtin nor absolute",{request:Ve,issuer:ke});let[,x,w]=Ue,b=Ae(Ne);if(!b){let Te=me(Fe,Ne);if(Te===!1)throw gs("BUILTIN_NODE_RESOLUTION_FAILED",`The builtin node resolution algorithm was unable to resolve the requested module (it didn't go through the pnp resolver because the issuer doesn't seem to be part of the Yarn-managed dependency tree). + +Require path: "${Ve}" +Required by: ${ke} +`,{request:Ve,issuer:ke});return fe.toPortablePath(Te)}let F=U(b).packageDependencies.get(x),z=null;if(F==null&&b.name!==null){let Te=t.fallbackExclusionList.get(b.name);if(!Te||!Te.has(b.reference)){for(let Ct=0,qt=h.length;CtW(lt))?X=gs("MISSING_PEER_DEPENDENCY",`${b.name} tried to access ${x} (a peer dependency) but it isn't provided by your application; this makes the require call ambiguous and unsound. + +Required package: ${x}${x!==Ve?` (via "${Ve}")`:""} +Required by: ${b.name}@${b.reference} (via ${ke}) +${Te.map(lt=>`Ancestor breaking the chain: ${lt.name}@${lt.reference} +`).join("")} +`,{request:Ve,issuer:ke,issuerLocator:Object.assign({},b),dependencyName:x,brokenAncestors:Te}):X=gs("MISSING_PEER_DEPENDENCY",`${b.name} tried to access ${x} (a peer dependency) but it isn't provided by its ancestors; this makes the require call ambiguous and unsound. + +Required package: ${x}${x!==Ve?` (via "${Ve}")`:""} +Required by: ${b.name}@${b.reference} (via ${ke}) + +${Te.map(lt=>`Ancestor breaking the chain: ${lt.name}@${lt.reference} +`).join("")} +`,{request:Ve,issuer:ke,issuerLocator:Object.assign({},b),dependencyName:x,brokenAncestors:Te})}else F===void 0&&(!Pe&&(0,sh.isBuiltin)(Fe)?W(b)?X=gs("UNDECLARED_DEPENDENCY",`Your application tried to access ${x}. While this module is usually interpreted as a Node builtin, your resolver is running inside a non-Node resolution context where such builtins are ignored. Since ${x} isn't otherwise declared in your dependencies, this makes the require call ambiguous and unsound. + +Required package: ${x}${x!==Ve?` (via "${Ve}")`:""} +Required by: ${ke} +`,{request:Ve,issuer:ke,dependencyName:x}):X=gs("UNDECLARED_DEPENDENCY",`${b.name} tried to access ${x}. While this module is usually interpreted as a Node builtin, your resolver is running inside a non-Node resolution context where such builtins are ignored. Since ${x} isn't otherwise declared in ${b.name}'s dependencies, this makes the require call ambiguous and unsound. + +Required package: ${x}${x!==Ve?` (via "${Ve}")`:""} +Required by: ${ke} +`,{request:Ve,issuer:ke,issuerLocator:Object.assign({},b),dependencyName:x}):W(b)?X=gs("UNDECLARED_DEPENDENCY",`Your application tried to access ${x}, but it isn't declared in your dependencies; this makes the require call ambiguous and unsound. + +Required package: ${x}${x!==Ve?` (via "${Ve}")`:""} +Required by: ${ke} +`,{request:Ve,issuer:ke,dependencyName:x}):X=gs("UNDECLARED_DEPENDENCY",`${b.name} tried to access ${x}, but it isn't declared in its dependencies; this makes the require call ambiguous and unsound. + +Required package: ${x}${x!==Ve?` (via "${Ve}")`:""} +Required by: ${b.name}@${b.reference} (via ${ke}) +`,{request:Ve,issuer:ke,issuerLocator:Object.assign({},b),dependencyName:x}));if(F==null){if(z===null||X===null)throw X||new Error("Assertion failed: Expected an error to have been set");F=z;let Te=X.message.replace(/\n.*/g,"");X.message=Te,!E.has(Te)&&s!==0&&(E.add(Te),process.emitWarning(X))}let $=Array.isArray(F)?{name:F[0],reference:F[1]}:{name:x,reference:F},oe=U($);if(!oe.packageLocation)throw gs("MISSING_DEPENDENCY",`A dependency seems valid but didn't get installed for some reason. This might be caused by a partial install, such as dev vs prod. + +Required package: ${$.name}@${$.reference}${$.name!==Ve?` (via "${Ve}")`:""} +Required by: ${b.name}@${b.reference} (via ${ke}) +`,{request:Ve,issuer:ke,dependencyLocator:Object.assign({},$)});let xe=oe.packageLocation;w?it=J.join(xe,w):it=xe}else if(J.isAbsolute(Fe))it=J.normalize(Fe);else{if(!Ne)throw gs("API_ERROR","The resolveToUnqualified function must be called with a valid issuer when the path isn't a builtin nor absolute",{request:Ve,issuer:ke});let x=J.resolve(Ne);Ne.match(c)?it=J.normalize(J.join(x,Fe)):it=J.normalize(J.join(J.dirname(x),Fe))}return J.normalize(it)}function De(Fe,Ne,Pe=ee,Ve){if(n.test(Fe))return Ne;let ke=ie(Ne,Pe,Ve);return ke?J.normalize(ke):Ne}function Re(Fe,{extensions:Ne=Object.keys(sh.Module._extensions)}={}){let Pe=[],Ve=ue(Fe,Pe,{extensions:Ne});if(Ve)return J.normalize(Ve);{vBe(Pe.map(Ue=>fe.fromPortablePath(Ue)));let ke=lf(Fe),it=Ae(Fe);if(it){let{packageLocation:Ue}=U(it),x=!0;try{e.fakeFs.accessSync(Ue)}catch(w){if(w?.code==="ENOENT")x=!1;else{let b=(w?.message??w??"empty exception thrown").replace(/^[A-Z]/,y=>y.toLowerCase());throw gs("QUALIFIED_PATH_RESOLUTION_FAILED",`Required package exists but could not be accessed (${b}). + +Missing package: ${it.name}@${it.reference} +Expected package location: ${lf(Ue)} +`,{unqualifiedPath:ke,extensions:Ne})}}if(!x){let w=Ue.includes("/unplugged/")?"Required unplugged package missing from disk. This may happen when switching branches without running installs (unplugged packages must be fully materialized on disk to work).":"Required package missing from disk. If you keep your packages inside your repository then restarting the Node process may be enough. Otherwise, try to run an install first.";throw gs("QUALIFIED_PATH_RESOLUTION_FAILED",`${w} + +Missing package: ${it.name}@${it.reference} +Expected package location: ${lf(Ue)} +`,{unqualifiedPath:ke,extensions:Ne})}}throw gs("QUALIFIED_PATH_RESOLUTION_FAILED",`Qualified path resolution failed: we looked for the following paths, but none could be accessed. + +Source path: ${ke} +${Pe.map(Ue=>`Not found: ${lf(Ue)} +`).join("")}`,{unqualifiedPath:ke,extensions:Ne})}}function mt(Fe,Ne,Pe){if(!Ne)throw new Error("Assertion failed: An issuer is required to resolve private import mappings");let Ve=mBe({name:Fe,base:(0,jm.pathToFileURL)(fe.fromPortablePath(Ne)),conditions:Pe.conditions??ee,readFileSyncFn:se});if(Ve instanceof URL)return Re(fe.toPortablePath((0,jm.fileURLToPath)(Ve)),{extensions:Pe.extensions});if(Ve.startsWith("#"))throw new Error("Mapping from one private import to another isn't allowed");return j(Ve,Ne,Pe)}function j(Fe,Ne,Pe={}){try{if(Fe.startsWith("#"))return mt(Fe,Ne,Pe);let{considerBuiltins:Ve,extensions:ke,conditions:it}=Pe,Ue=Z(Fe,Ne,{considerBuiltins:Ve});if(Fe==="pnpapi")return Ue;if(Ue===null)return null;let x=()=>Ne!==null?pe(Ne):!1,w=(!Ve||!(0,sh.isBuiltin)(Fe))&&!x()?De(Fe,Ue,it,Ne):Ue;return Re(w,{extensions:ke})}catch(Ve){throw Object.hasOwn(Ve,"pnpCode")&&Object.assign(Ve.data,{request:lf(Fe),issuer:Ne&&lf(Ne)}),Ve}}function rt(Fe){let Ne=J.normalize(Fe),Pe=uo.resolveVirtual(Ne);return Pe!==Ne?Pe:null}return{VERSIONS:Be,topLevel:Ce,getLocator:(Fe,Ne)=>Array.isArray(Ne)?{name:Ne[0],reference:Ne[1]}:{name:Fe,reference:Ne},getDependencyTreeRoots:()=>[...t.dependencyTreeRoots],getAllLocators(){let Fe=[];for(let[Ne,Pe]of S)for(let Ve of Pe.keys())Ne!==null&&Ve!==null&&Fe.push({name:Ne,reference:Ve});return Fe},getPackageInformation:Fe=>{let Ne=g(Fe);if(Ne===null)return null;let Pe=fe.fromPortablePath(Ne.packageLocation);return{...Ne,packageLocation:Pe}},findPackageLocator:Fe=>Ae(fe.toPortablePath(Fe)),resolveToUnqualified:N("resolveToUnqualified",(Fe,Ne,Pe)=>{let Ve=Ne!==null?fe.toPortablePath(Ne):null,ke=Z(fe.toPortablePath(Fe),Ve,Pe);return ke===null?null:fe.fromPortablePath(ke)}),resolveUnqualified:N("resolveUnqualified",(Fe,Ne)=>fe.fromPortablePath(Re(fe.toPortablePath(Fe),Ne))),resolveRequest:N("resolveRequest",(Fe,Ne,Pe)=>{let Ve=Ne!==null?fe.toPortablePath(Ne):null,ke=j(fe.toPortablePath(Fe),Ve,Pe);return ke===null?null:fe.fromPortablePath(ke)}),resolveVirtual:N("resolveVirtual",Fe=>{let Ne=rt(fe.toPortablePath(Fe));return Ne!==null?fe.fromPortablePath(Ne):null})}}Dt();var SBe=(t,e,r)=>{let s=TD(t),a=sY(s,{basePath:e}),n=fe.join(e,Er.pnpCjs);return dY(a,{fakeFs:r,pnpapiResolution:n})};var yY=ut(bBe());Yt();var gA={};Vt(gA,{checkManifestCompatibility:()=>PBe,extractBuildRequest:()=>oN,getExtractHint:()=>EY,hasBindingGyp:()=>IY});Ge();Dt();function PBe(t){return G.isPackageCompatible(t,Ui.getArchitectureSet())}function oN(t,e,r,{configuration:s}){let a=[];for(let n of["preinstall","install","postinstall"])e.manifest.scripts.has(n)&&a.push({type:0,script:n});return!e.manifest.scripts.has("install")&&e.misc.hasBindingGyp&&a.push({type:1,script:"node-gyp rebuild"}),a.length===0?null:t.linkType!=="HARD"?{skipped:!0,explain:n=>n.reportWarningOnce(6,`${G.prettyLocator(s,t)} lists build scripts, but is referenced through a soft link. Soft links don't support build scripts, so they'll be ignored.`)}:r&&r.built===!1?{skipped:!0,explain:n=>n.reportInfoOnce(5,`${G.prettyLocator(s,t)} lists build scripts, but its build has been explicitly disabled through configuration.`)}:!s.get("enableScripts")&&!r.built?{skipped:!0,explain:n=>n.reportWarningOnce(4,`${G.prettyLocator(s,t)} lists build scripts, but all build scripts have been disabled.`)}:PBe(t)?{skipped:!1,directives:a}:{skipped:!0,explain:n=>n.reportWarningOnce(76,`${G.prettyLocator(s,t)} The ${Ui.getArchitectureName()} architecture is incompatible with this package, build skipped.`)}}var gdt=new Set([".exe",".bin",".h",".hh",".hpp",".c",".cc",".cpp",".java",".jar",".node"]);function EY(t){return t.packageFs.getExtractHint({relevantExtensions:gdt})}function IY(t){let e=J.join(t.prefixPath,"binding.gyp");return t.packageFs.existsSync(e)}var HD={};Vt(HD,{getUnpluggedPath:()=>_D});Ge();Dt();function _D(t,{configuration:e}){return J.resolve(e.get("pnpUnpluggedFolder"),G.slugifyLocator(t))}var ddt=new Set([G.makeIdent(null,"open").identHash,G.makeIdent(null,"opn").identHash]),sg=class{constructor(){this.mode="strict";this.pnpCache=new Map}getCustomDataKey(){return JSON.stringify({name:"PnpLinker",version:2})}supportsPackage(e,r){return this.isEnabled(r)}async findPackageLocation(e,r){if(!this.isEnabled(r))throw new Error("Assertion failed: Expected the PnP linker to be enabled");let s=og(r.project).cjs;if(!ce.existsSync(s))throw new nt(`The project in ${he.pretty(r.project.configuration,`${r.project.cwd}/package.json`,he.Type.PATH)} doesn't seem to have been installed - running an install there might help`);let a=je.getFactoryWithDefault(this.pnpCache,s,()=>je.dynamicRequire(s,{cachingStrategy:je.CachingStrategy.FsTime})),n={name:G.stringifyIdent(e),reference:e.reference},c=a.getPackageInformation(n);if(!c)throw new nt(`Couldn't find ${G.prettyLocator(r.project.configuration,e)} in the currently installed PnP map - running an install might help`);return fe.toPortablePath(c.packageLocation)}async findPackageLocator(e,r){if(!this.isEnabled(r))return null;let s=og(r.project).cjs;if(!ce.existsSync(s))return null;let n=je.getFactoryWithDefault(this.pnpCache,s,()=>je.dynamicRequire(s,{cachingStrategy:je.CachingStrategy.FsTime})).findPackageLocator(fe.fromPortablePath(e));return n?G.makeLocator(G.parseIdent(n.name),n.reference):null}makeInstaller(e){return new Gm(e)}isEnabled(e){return!(e.project.configuration.get("nodeLinker")!=="pnp"||e.project.configuration.get("pnpMode")!==this.mode)}},Gm=class{constructor(e){this.opts=e;this.mode="strict";this.asyncActions=new je.AsyncActions(10);this.packageRegistry=new Map;this.virtualTemplates=new Map;this.isESMLoaderRequired=!1;this.customData={store:new Map};this.unpluggedPaths=new Set;this.opts=e}attachCustomData(e){this.customData=e}async installPackage(e,r,s){let a=G.stringifyIdent(e),n=e.reference,c=!!this.opts.project.tryWorkspaceByLocator(e),f=G.isVirtualLocator(e),p=e.peerDependencies.size>0&&!f,h=!p&&!c,E=!p&&e.linkType!=="SOFT",C,S;if(h||E){let ee=f?G.devirtualizeLocator(e):e;C=this.customData.store.get(ee.locatorHash),typeof C>"u"&&(C=await mdt(r),e.linkType==="HARD"&&this.customData.store.set(ee.locatorHash,C)),C.manifest.type==="module"&&(this.isESMLoaderRequired=!0),S=this.opts.project.getDependencyMeta(ee,e.version)}let P=h?oN(e,C,S,{configuration:this.opts.project.configuration}):null,I=E?await this.unplugPackageIfNeeded(e,C,r,S,s):r.packageFs;if(J.isAbsolute(r.prefixPath))throw new Error(`Assertion failed: Expected the prefix path (${r.prefixPath}) to be relative to the parent`);let R=J.resolve(I.getRealPath(),r.prefixPath),N=CY(this.opts.project.cwd,R),U=new Map,W=new Set;if(f){for(let ee of e.peerDependencies.values())U.set(G.stringifyIdent(ee),null),W.add(G.stringifyIdent(ee));if(!c){let ee=G.devirtualizeLocator(e);this.virtualTemplates.set(ee.locatorHash,{location:CY(this.opts.project.cwd,uo.resolveVirtual(R)),locator:ee})}}return je.getMapWithDefault(this.packageRegistry,a).set(n,{packageLocation:N,packageDependencies:U,packagePeers:W,linkType:e.linkType,discardFromLookup:r.discardFromLookup||!1}),{packageLocation:R,buildRequest:P}}async attachInternalDependencies(e,r){let s=this.getPackageInformation(e);for(let[a,n]of r){let c=G.areIdentsEqual(a,n)?n.reference:[G.stringifyIdent(n),n.reference];s.packageDependencies.set(G.stringifyIdent(a),c)}}async attachExternalDependents(e,r){for(let s of r)this.getDiskInformation(s).packageDependencies.set(G.stringifyIdent(e),e.reference)}async finalizeInstall(){if(this.opts.project.configuration.get("pnpMode")!==this.mode)return;let e=og(this.opts.project);if(this.isEsmEnabled()||await ce.removePromise(e.esmLoader),this.opts.project.configuration.get("nodeLinker")!=="pnp"){await ce.removePromise(e.cjs),await ce.removePromise(e.data),await ce.removePromise(e.esmLoader),await ce.removePromise(this.opts.project.configuration.get("pnpUnpluggedFolder"));return}for(let{locator:C,location:S}of this.virtualTemplates.values())je.getMapWithDefault(this.packageRegistry,G.stringifyIdent(C)).set(C.reference,{packageLocation:S,packageDependencies:new Map,packagePeers:new Set,linkType:"SOFT",discardFromLookup:!1});let r=this.opts.project.configuration.get("pnpFallbackMode"),s=this.opts.project.workspaces.map(({anchoredLocator:C})=>({name:G.stringifyIdent(C),reference:C.reference})),a=r!=="none",n=[],c=new Map,f=je.buildIgnorePattern([".yarn/sdks/**",...this.opts.project.configuration.get("pnpIgnorePatterns")]),p=this.packageRegistry,h=this.opts.project.configuration.get("pnpShebang"),E=this.opts.project.configuration.get("pnpZipBackend");if(r==="dependencies-only")for(let C of this.opts.project.storedPackages.values())this.opts.project.tryWorkspaceByLocator(C)&&n.push({name:G.stringifyIdent(C),reference:C.reference});return await this.asyncActions.wait(),await this.finalizeInstallWithPnp({dependencyTreeRoots:s,enableTopLevelFallback:a,fallbackExclusionList:n,fallbackPool:c,ignorePattern:f,pnpZipBackend:E,packageRegistry:p,shebang:h}),{customData:this.customData}}async transformPnpSettings(e){}isEsmEnabled(){if(this.opts.project.configuration.sources.has("pnpEnableEsmLoader"))return this.opts.project.configuration.get("pnpEnableEsmLoader");if(this.isESMLoaderRequired)return!0;for(let e of this.opts.project.workspaces)if(e.manifest.type==="module")return!0;return!1}async finalizeInstallWithPnp(e){let r=og(this.opts.project),s=await this.locateNodeModules(e.ignorePattern);if(s.length>0){this.opts.report.reportWarning(31,"One or more node_modules have been detected and will be removed. This operation may take some time.");for(let n of s)await ce.removePromise(n)}if(await this.transformPnpSettings(e),this.opts.project.configuration.get("pnpEnableInlining")){let n=tBe(e);await ce.changeFilePromise(r.cjs,n,{automaticNewlines:!0,mode:493}),await ce.removePromise(r.data)}else{let{dataFile:n,loaderFile:c}=rBe(e);await ce.changeFilePromise(r.cjs,c,{automaticNewlines:!0,mode:493}),await ce.changeFilePromise(r.data,n,{automaticNewlines:!0,mode:420})}this.isEsmEnabled()&&(this.opts.report.reportWarning(0,"ESM support for PnP uses the experimental loader API and is therefore experimental"),await ce.changeFilePromise(r.esmLoader,(0,yY.default)(),{automaticNewlines:!0,mode:420}));let a=this.opts.project.configuration.get("pnpUnpluggedFolder");if(this.unpluggedPaths.size===0)await ce.removePromise(a);else for(let n of await ce.readdirPromise(a)){let c=J.resolve(a,n);this.unpluggedPaths.has(c)||await ce.removePromise(c)}}async locateNodeModules(e){let r=[],s=e?new RegExp(e):null;for(let a of this.opts.project.workspaces){let n=J.join(a.cwd,"node_modules");if(s&&s.test(J.relative(this.opts.project.cwd,a.cwd))||!ce.existsSync(n))continue;let c=await ce.readdirPromise(n,{withFileTypes:!0}),f=c.filter(p=>!p.isDirectory()||p.name===".bin"||!p.name.startsWith("."));if(f.length===c.length)r.push(n);else for(let p of f)r.push(J.join(n,p.name))}return r}async unplugPackageIfNeeded(e,r,s,a,n){return this.shouldBeUnplugged(e,r,a)?this.unplugPackage(e,s,n):s.packageFs}shouldBeUnplugged(e,r,s){return typeof s.unplugged<"u"?s.unplugged:ddt.has(e.identHash)||e.conditions!=null?!0:r.manifest.preferUnplugged!==null?r.manifest.preferUnplugged:!!(oN(e,r,s,{configuration:this.opts.project.configuration})?.skipped===!1||r.misc.extractHint)}async unplugPackage(e,r,s){let a=_D(e,{configuration:this.opts.project.configuration});return this.opts.project.disabledLocators.has(e.locatorHash)?new _f(a,{baseFs:r.packageFs,pathUtils:J}):(this.unpluggedPaths.add(a),s.holdFetchResult(this.asyncActions.set(e.locatorHash,async()=>{let n=J.join(a,r.prefixPath,".ready");await ce.existsPromise(n)||(this.opts.project.storedBuildState.delete(e.locatorHash),await ce.mkdirPromise(a,{recursive:!0}),await ce.copyPromise(a,vt.dot,{baseFs:r.packageFs,overwrite:!1}),await ce.writeFilePromise(n,""))})),new Sn(a))}getPackageInformation(e){let r=G.stringifyIdent(e),s=e.reference,a=this.packageRegistry.get(r);if(!a)throw new Error(`Assertion failed: The package information store should have been available (for ${G.prettyIdent(this.opts.project.configuration,e)})`);let n=a.get(s);if(!n)throw new Error(`Assertion failed: The package information should have been available (for ${G.prettyLocator(this.opts.project.configuration,e)})`);return n}getDiskInformation(e){let r=je.getMapWithDefault(this.packageRegistry,"@@disk"),s=CY(this.opts.project.cwd,e);return je.getFactoryWithDefault(r,s,()=>({packageLocation:s,packageDependencies:new Map,packagePeers:new Set,linkType:"SOFT",discardFromLookup:!1}))}};function CY(t,e){let r=J.relative(t,e);return r.match(/^\.{0,2}\//)||(r=`./${r}`),r.replace(/\/?$/,"/")}async function mdt(t){let e=await Ut.tryFind(t.prefixPath,{baseFs:t.packageFs})??new Ut,r=new Set(["preinstall","install","postinstall"]);for(let s of e.scripts.keys())r.has(s)||e.scripts.delete(s);return{manifest:{scripts:e.scripts,preferUnplugged:e.preferUnplugged,type:e.type},misc:{extractHint:EY(t),hasBindingGyp:IY(t)}}}Ge();Ge();Yt();var xBe=ut(Go());var Sw=class extends ft{constructor(){super(...arguments);this.all=ge.Boolean("-A,--all",!1,{description:"Unplug direct dependencies from the entire project"});this.recursive=ge.Boolean("-R,--recursive",!1,{description:"Unplug both direct and transitive dependencies"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.patterns=ge.Rest()}static{this.paths=[["unplug"]]}static{this.usage=ot.Usage({description:"force the unpacking of a list of packages",details:"\n This command will add the selectors matching the specified patterns to the list of packages that must be unplugged when installed.\n\n A package being unplugged means that instead of being referenced directly through its archive, it will be unpacked at install time in the directory configured via `pnpUnpluggedFolder`. Note that unpacking packages this way is generally not recommended because it'll make it harder to store your packages within the repository. However, it's a good approach to quickly and safely debug some packages, and can even sometimes be required depending on the context (for example when the package contains shellscripts).\n\n Running the command will set a persistent flag inside your top-level `package.json`, in the `dependenciesMeta` field. As such, to undo its effects, you'll need to revert the changes made to the manifest and run `yarn install` to apply the modification.\n\n By default, only direct dependencies from the current workspace are affected. If `-A,--all` is set, direct dependencies from the entire project are affected. Using the `-R,--recursive` flag will affect transitive dependencies as well as direct ones.\n\n This command accepts glob patterns inside the scope and name components (not the range). Make sure to escape the patterns to prevent your own shell from trying to expand them.\n ",examples:[["Unplug the lodash dependency from the active workspace","yarn unplug lodash"],["Unplug all instances of lodash referenced by any workspace","yarn unplug lodash -A"],["Unplug all instances of lodash referenced by the active workspace and its dependencies","yarn unplug lodash -R"],["Unplug all instances of lodash, anywhere","yarn unplug lodash -AR"],["Unplug one specific version of lodash","yarn unplug lodash@1.2.3"],["Unplug all packages with the `@babel` scope","yarn unplug '@babel/*'"],["Unplug all packages (only for testing, not recommended)","yarn unplug -R '*'"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Tt.find(r,this.context.cwd),n=await Kr.find(r);if(!a)throw new ar(s.cwd,this.context.cwd);if(r.get("nodeLinker")!=="pnp")throw new nt("This command can only be used if the `nodeLinker` option is set to `pnp`");await s.restoreInstallState();let c=new Set(this.patterns),f=this.patterns.map(P=>{let I=G.parseDescriptor(P),R=I.range!=="unknown"?I:G.makeDescriptor(I,"*");if(!Fr.validRange(R.range))throw new nt(`The range of the descriptor patterns must be a valid semver range (${G.prettyDescriptor(r,R)})`);return N=>{let U=G.stringifyIdent(N);return!xBe.default.isMatch(U,G.stringifyIdent(R))||N.version&&!Fr.satisfiesWithPrereleases(N.version,R.range)?!1:(c.delete(P),!0)}}),p=()=>{let P=[];for(let I of s.storedPackages.values())!s.tryWorkspaceByLocator(I)&&!G.isVirtualLocator(I)&&f.some(R=>R(I))&&P.push(I);return P},h=P=>{let I=new Set,R=[],N=(U,W)=>{if(I.has(U.locatorHash))return;let ee=!!s.tryWorkspaceByLocator(U);if(!(W>0&&!this.recursive&&ee)&&(I.add(U.locatorHash),!s.tryWorkspaceByLocator(U)&&f.some(ie=>ie(U))&&R.push(U),!(W>0&&!this.recursive)))for(let ie of U.dependencies.values()){let ue=s.storedResolutions.get(ie.descriptorHash);if(!ue)throw new Error("Assertion failed: The resolution should have been registered");let le=s.storedPackages.get(ue);if(!le)throw new Error("Assertion failed: The package should have been registered");N(le,W+1)}};for(let U of P)N(U.anchoredPackage,0);return R},E,C;if(this.all&&this.recursive?(E=p(),C="the project"):this.all?(E=h(s.workspaces),C="any workspace"):(E=h([a]),C="this workspace"),c.size>1)throw new nt(`Patterns ${he.prettyList(r,c,he.Type.CODE)} don't match any packages referenced by ${C}`);if(c.size>0)throw new nt(`Pattern ${he.prettyList(r,c,he.Type.CODE)} doesn't match any packages referenced by ${C}`);E=je.sortMap(E,P=>G.stringifyLocator(P));let S=await Ot.start({configuration:r,stdout:this.context.stdout,json:this.json},async P=>{for(let I of E){let R=I.version??"unknown",N=s.topLevelWorkspace.manifest.ensureDependencyMeta(G.makeDescriptor(I,R));N.unplugged=!0,P.reportInfo(0,`Will unpack ${G.prettyLocator(r,I)} to ${he.pretty(r,_D(I,{configuration:r}),he.Type.PATH)}`),P.reportJson({locator:G.stringifyLocator(I),version:R})}await s.topLevelWorkspace.persistManifest(),this.json||P.reportSeparator()});return S.hasErrors()?S.exitCode():await s.installWithNewReport({json:this.json,stdout:this.context.stdout},{cache:n})}};var og=t=>({cjs:J.join(t.cwd,Er.pnpCjs),data:J.join(t.cwd,Er.pnpData),esmLoader:J.join(t.cwd,Er.pnpEsmLoader)}),QBe=t=>/\s/.test(t)?JSON.stringify(t):t;async function ydt(t,e,r){let s=/\s*--require\s+\S*\.pnp\.c?js\s*/g,a=/\s*--experimental-loader\s+\S*\.pnp\.loader\.mjs\s*/,n=(e.NODE_OPTIONS??"").replace(s," ").replace(a," ").trim();if(t.configuration.get("nodeLinker")!=="pnp"){e.NODE_OPTIONS=n||void 0;return}let c=og(t),f=`--require ${QBe(fe.fromPortablePath(c.cjs))}`;ce.existsSync(c.esmLoader)&&(f=`${f} --experimental-loader ${(0,kBe.pathToFileURL)(fe.fromPortablePath(c.esmLoader)).href}`),ce.existsSync(c.cjs)&&(e.NODE_OPTIONS=n?`${f} ${n}`:f)}async function Edt(t,e){let r=og(t);e(r.cjs),e(r.data),e(r.esmLoader),e(t.configuration.get("pnpUnpluggedFolder"))}var Idt={hooks:{populateYarnPaths:Edt,setupScriptEnvironment:ydt},configuration:{nodeLinker:{description:'The linker used for installing Node packages, one of: "pnp", "pnpm", or "node-modules"',type:"STRING",default:"pnp"},minizip:{description:"Whether Yarn should use minizip to extract archives",type:"BOOLEAN",default:!1},winLinkType:{description:"Whether Yarn should use Windows Junctions or symlinks when creating links on Windows.",type:"STRING",values:["junctions","symlinks"],default:"junctions"},pnpMode:{description:"If 'strict', generates standard PnP maps. If 'loose', merges them with the n_m resolution.",type:"STRING",default:"strict"},pnpShebang:{description:"String to prepend to the generated PnP script",type:"STRING",default:"#!/usr/bin/env node"},pnpIgnorePatterns:{description:"Array of glob patterns; files matching them will use the classic resolution",type:"STRING",default:[],isArray:!0},pnpZipBackend:{description:"Whether to use the experimental js implementation for the ZipFS",type:"STRING",values:["libzip","js"],default:"libzip"},pnpEnableEsmLoader:{description:"If true, Yarn will generate an ESM loader (`.pnp.loader.mjs`). If this is not explicitly set Yarn tries to automatically detect whether ESM support is required.",type:"BOOLEAN",default:!1},pnpEnableInlining:{description:"If true, the PnP data will be inlined along with the generated loader",type:"BOOLEAN",default:!0},pnpFallbackMode:{description:"If true, the generated PnP loader will follow the top-level fallback rule",type:"STRING",default:"dependencies-only"},pnpUnpluggedFolder:{description:"Folder where the unplugged packages must be stored",type:"ABSOLUTE_PATH",default:"./.yarn/unplugged"}},linkers:[sg],commands:[Sw]},Cdt=Idt;var UBe=ut(OBe());Yt();var xY=ut(Ie("crypto")),_Be=ut(Ie("fs")),HBe=1,Ti="node_modules",aN=".bin",jBe=".yarn-state.yml",Mdt=1e3,kY=(s=>(s.CLASSIC="classic",s.HARDLINKS_LOCAL="hardlinks-local",s.HARDLINKS_GLOBAL="hardlinks-global",s))(kY||{}),jD=class{constructor(){this.installStateCache=new Map}getCustomDataKey(){return JSON.stringify({name:"NodeModulesLinker",version:3})}supportsPackage(e,r){return this.isEnabled(r)}async findPackageLocation(e,r){if(!this.isEnabled(r))throw new Error("Assertion failed: Expected the node-modules linker to be enabled");let s=r.project.tryWorkspaceByLocator(e);if(s)return s.cwd;let a=await je.getFactoryWithDefault(this.installStateCache,r.project.cwd,async()=>await PY(r.project,{unrollAliases:!0}));if(a===null)throw new nt("Couldn't find the node_modules state file - running an install might help (findPackageLocation)");let n=a.locatorMap.get(G.stringifyLocator(e));if(!n){let p=new nt(`Couldn't find ${G.prettyLocator(r.project.configuration,e)} in the currently installed node_modules map - running an install might help`);throw p.code="LOCATOR_NOT_INSTALLED",p}let c=n.locations.sort((p,h)=>p.split(J.sep).length-h.split(J.sep).length),f=J.join(r.project.configuration.startingCwd,Ti);return c.find(p=>J.contains(f,p))||n.locations[0]}async findPackageLocator(e,r){if(!this.isEnabled(r))return null;let s=await je.getFactoryWithDefault(this.installStateCache,r.project.cwd,async()=>await PY(r.project,{unrollAliases:!0}));if(s===null)return null;let{locationRoot:a,segments:n}=lN(J.resolve(e),{skipPrefix:r.project.cwd}),c=s.locationTree.get(a);if(!c)return null;let f=c.locator;for(let p of n){if(c=c.children.get(p),!c)break;f=c.locator||f}return G.parseLocator(f)}makeInstaller(e){return new bY(e)}isEnabled(e){return e.project.configuration.get("nodeLinker")==="node-modules"}},bY=class{constructor(e){this.opts=e;this.localStore=new Map;this.realLocatorChecksums=new Map;this.customData={store:new Map}}attachCustomData(e){this.customData=e}async installPackage(e,r){let s=J.resolve(r.packageFs.getRealPath(),r.prefixPath),a=this.customData.store.get(e.locatorHash);if(typeof a>"u"&&(a=await Udt(e,r),e.linkType==="HARD"&&this.customData.store.set(e.locatorHash,a)),!G.isPackageCompatible(e,this.opts.project.configuration.getSupportedArchitectures()))return{packageLocation:null,buildRequest:null};let n=new Map,c=new Set;n.has(G.stringifyIdent(e))||n.set(G.stringifyIdent(e),e.reference);let f=e;if(G.isVirtualLocator(e)){f=G.devirtualizeLocator(e);for(let E of e.peerDependencies.values())n.set(G.stringifyIdent(E),null),c.add(G.stringifyIdent(E))}let p={packageLocation:`${fe.fromPortablePath(s)}/`,packageDependencies:n,packagePeers:c,linkType:e.linkType,discardFromLookup:r.discardFromLookup??!1};this.localStore.set(e.locatorHash,{pkg:e,customPackageData:a,dependencyMeta:this.opts.project.getDependencyMeta(e,e.version),pnpNode:p});let h=r.checksum?r.checksum.substring(r.checksum.indexOf("/")+1):null;return this.realLocatorChecksums.set(f.locatorHash,h),{packageLocation:s,buildRequest:null}}async attachInternalDependencies(e,r){let s=this.localStore.get(e.locatorHash);if(typeof s>"u")throw new Error("Assertion failed: Expected information object to have been registered");for(let[a,n]of r){let c=G.areIdentsEqual(a,n)?n.reference:[G.stringifyIdent(n),n.reference];s.pnpNode.packageDependencies.set(G.stringifyIdent(a),c)}}async attachExternalDependents(e,r){throw new Error("External dependencies haven't been implemented for the node-modules linker")}async finalizeInstall(){if(this.opts.project.configuration.get("nodeLinker")!=="node-modules")return;let e=new uo({baseFs:new $f({maxOpenFiles:80,readOnlyArchives:!0,customZipImplementation:ST})}),r=await PY(this.opts.project),s=this.opts.project.configuration.get("nmMode");(r===null||s!==r.nmMode)&&(this.opts.project.storedBuildState.clear(),r={locatorMap:new Map,binSymlinks:new Map,locationTree:new Map,nmMode:s,mtimeMs:0});let a=new Map(this.opts.project.workspaces.map(S=>{let P=this.opts.project.configuration.get("nmHoistingLimits");try{P=je.validateEnum(xD,S.manifest.installConfig?.hoistingLimits??P)}catch{let I=G.prettyWorkspace(this.opts.project.configuration,S);this.opts.report.reportWarning(57,`${I}: Invalid 'installConfig.hoistingLimits' value. Expected one of ${Object.values(xD).join(", ")}, using default: "${P}"`)}return[S.relativeCwd,P]})),n=new Map(this.opts.project.workspaces.map(S=>{let P=this.opts.project.configuration.get("nmSelfReferences");return P=S.manifest.installConfig?.selfReferences??P,[S.relativeCwd,P]})),c={VERSIONS:{std:1},topLevel:{name:null,reference:null},getLocator:(S,P)=>Array.isArray(P)?{name:P[0],reference:P[1]}:{name:S,reference:P},getDependencyTreeRoots:()=>this.opts.project.workspaces.map(S=>{let P=S.anchoredLocator;return{name:G.stringifyIdent(P),reference:P.reference}}),getPackageInformation:S=>{let P=S.reference===null?this.opts.project.topLevelWorkspace.anchoredLocator:G.makeLocator(G.parseIdent(S.name),S.reference),I=this.localStore.get(P.locatorHash);if(typeof I>"u")throw new Error("Assertion failed: Expected the package reference to have been registered");return I.pnpNode},findPackageLocator:S=>{let P=this.opts.project.tryWorkspaceByCwd(fe.toPortablePath(S));if(P!==null){let I=P.anchoredLocator;return{name:G.stringifyIdent(I),reference:I.reference}}throw new Error("Assertion failed: Unimplemented")},resolveToUnqualified:()=>{throw new Error("Assertion failed: Unimplemented")},resolveUnqualified:()=>{throw new Error("Assertion failed: Unimplemented")},resolveRequest:()=>{throw new Error("Assertion failed: Unimplemented")},resolveVirtual:S=>fe.fromPortablePath(uo.resolveVirtual(fe.toPortablePath(S)))},{tree:f,errors:p,preserveSymlinksRequired:h}=kD(c,{pnpifyFs:!1,validateExternalSoftLinks:!0,hoistingLimitsByCwd:a,project:this.opts.project,selfReferencesByCwd:n});if(!f){for(let{messageName:S,text:P}of p)this.opts.report.reportError(S,P);return}let E=nY(f);await Ydt(r,E,{baseFs:e,project:this.opts.project,report:this.opts.report,realLocatorChecksums:this.realLocatorChecksums,loadManifest:async S=>{let P=G.parseLocator(S),I=this.localStore.get(P.locatorHash);if(typeof I>"u")throw new Error("Assertion failed: Expected the slot to exist");return I.customPackageData.manifest}});let C=[];for(let[S,P]of E.entries()){if(WBe(S))continue;let I=G.parseLocator(S),R=this.localStore.get(I.locatorHash);if(typeof R>"u")throw new Error("Assertion failed: Expected the slot to exist");if(this.opts.project.tryWorkspaceByLocator(R.pkg))continue;let N=gA.extractBuildRequest(R.pkg,R.customPackageData,R.dependencyMeta,{configuration:this.opts.project.configuration});N&&C.push({buildLocations:P.locations,locator:I,buildRequest:N})}return h&&this.opts.report.reportWarning(72,`The application uses portals and that's why ${he.pretty(this.opts.project.configuration,"--preserve-symlinks",he.Type.CODE)} Node option is required for launching it`),{customData:this.customData,records:C}}};async function Udt(t,e){let r=await Ut.tryFind(e.prefixPath,{baseFs:e.packageFs})??new Ut,s=new Set(["preinstall","install","postinstall"]);for(let a of r.scripts.keys())s.has(a)||r.scripts.delete(a);return{manifest:{bin:r.bin,scripts:r.scripts},misc:{hasBindingGyp:gA.hasBindingGyp(e)}}}async function _dt(t,e,r,s,{installChangedByUser:a}){let n="";n+=`# Warning: This file is automatically generated. Removing it is fine, but will +`,n+=`# cause your node_modules installation to become invalidated. +`,n+=` +`,n+=`__metadata: +`,n+=` version: ${HBe} +`,n+=` nmMode: ${s.value} +`;let c=Array.from(e.keys()).sort(),f=G.stringifyLocator(t.topLevelWorkspace.anchoredLocator);for(let E of c){let C=e.get(E);n+=` +`,n+=`${JSON.stringify(E)}: +`,n+=` locations: +`;for(let S of C.locations){let P=J.contains(t.cwd,S);if(P===null)throw new Error(`Assertion failed: Expected the path to be within the project (${S})`);n+=` - ${JSON.stringify(P)} +`}if(C.aliases.length>0){n+=` aliases: +`;for(let S of C.aliases)n+=` - ${JSON.stringify(S)} +`}if(E===f&&r.size>0){n+=` bin: +`;for(let[S,P]of r){let I=J.contains(t.cwd,S);if(I===null)throw new Error(`Assertion failed: Expected the path to be within the project (${S})`);n+=` ${JSON.stringify(I)}: +`;for(let[R,N]of P){let U=J.relative(J.join(S,Ti),N);n+=` ${JSON.stringify(R)}: ${JSON.stringify(U)} +`}}}}let p=t.cwd,h=J.join(p,Ti,jBe);a&&await ce.removePromise(h),await ce.changeFilePromise(h,n,{automaticNewlines:!0})}async function PY(t,{unrollAliases:e=!1}={}){let r=t.cwd,s=J.join(r,Ti,jBe),a;try{a=await ce.statPromise(s)}catch{}if(!a)return null;let n=ls(await ce.readFilePromise(s,"utf8"));if(n.__metadata.version>HBe)return null;let c=n.__metadata.nmMode||"classic",f=new Map,p=new Map;delete n.__metadata;for(let[h,E]of Object.entries(n)){let C=E.locations.map(P=>J.join(r,P)),S=E.bin;if(S)for(let[P,I]of Object.entries(S)){let R=J.join(r,fe.toPortablePath(P)),N=je.getMapWithDefault(p,R);for(let[U,W]of Object.entries(I))N.set(U,fe.toPortablePath([R,Ti,W].join(J.sep)))}if(f.set(h,{target:vt.dot,linkType:"HARD",locations:C,aliases:E.aliases||[]}),e&&E.aliases)for(let P of E.aliases){let{scope:I,name:R}=G.parseLocator(h),N=G.makeLocator(G.makeIdent(I,R),P),U=G.stringifyLocator(N);f.set(U,{target:vt.dot,linkType:"HARD",locations:C,aliases:[]})}}return{locatorMap:f,binSymlinks:p,locationTree:GBe(f,{skipPrefix:t.cwd}),nmMode:c,mtimeMs:a.mtimeMs}}var bw=async(t,e)=>{if(t.split(J.sep).indexOf(Ti)<0)throw new Error(`Assertion failed: trying to remove dir that doesn't contain node_modules: ${t}`);try{let r;if(!e.innerLoop&&(r=await ce.lstatPromise(t),!r.isDirectory()&&!r.isSymbolicLink()||r.isSymbolicLink()&&!e.isWorkspaceDir)){await ce.unlinkPromise(t);return}let s=await ce.readdirPromise(t,{withFileTypes:!0});for(let n of s){let c=J.join(t,n.name);n.isDirectory()?(n.name!==Ti||e&&e.innerLoop)&&await bw(c,{innerLoop:!0,contentsOnly:!1}):await ce.unlinkPromise(c)}let a=!e.innerLoop&&e.isWorkspaceDir&&r?.isSymbolicLink();!e.contentsOnly&&!a&&await ce.rmdirPromise(t)}catch(r){if(r.code!=="ENOENT"&&r.code!=="ENOTEMPTY")throw r}},LBe=4,lN=(t,{skipPrefix:e})=>{let r=J.contains(e,t);if(r===null)throw new Error(`Assertion failed: Writing attempt prevented to ${t} which is outside project root: ${e}`);let s=r.split(J.sep).filter(p=>p!==""),a=s.indexOf(Ti),n=s.slice(0,a).join(J.sep),c=J.join(e,n),f=s.slice(a);return{locationRoot:c,segments:f}},GBe=(t,{skipPrefix:e})=>{let r=new Map;if(t===null)return r;let s=()=>({children:new Map,linkType:"HARD"});for(let[a,n]of t.entries()){if(n.linkType==="SOFT"&&J.contains(e,n.target)!==null){let f=je.getFactoryWithDefault(r,n.target,s);f.locator=a,f.linkType=n.linkType}for(let c of n.locations){let{locationRoot:f,segments:p}=lN(c,{skipPrefix:e}),h=je.getFactoryWithDefault(r,f,s);for(let E=0;E{if(process.platform==="win32"&&r==="junctions"){let s;try{s=await ce.lstatPromise(t)}catch{}if(!s||s.isDirectory()){await ce.symlinkPromise(t,e,"junction");return}}await ce.symlinkPromise(J.relative(J.dirname(e),t),e)};async function qBe(t,e,r){let s=J.join(t,`${xY.default.randomBytes(16).toString("hex")}.tmp`);try{await ce.writeFilePromise(s,r);try{await ce.linkPromise(s,e)}catch{}}finally{await ce.unlinkPromise(s)}}async function Hdt({srcPath:t,dstPath:e,entry:r,globalHardlinksStore:s,baseFs:a,nmMode:n}){if(r.kind==="file"){if(n.value==="hardlinks-global"&&s&&r.digest){let f=J.join(s,r.digest.substring(0,2),`${r.digest.substring(2)}.dat`),p;try{let h=await ce.statPromise(f);if(h&&(!r.mtimeMs||h.mtimeMs>r.mtimeMs||h.mtimeMs{await ce.mkdirPromise(t,{recursive:!0});let f=async(E=vt.dot)=>{let C=J.join(e,E),S=await r.readdirPromise(C,{withFileTypes:!0}),P=new Map;for(let I of S){let R=J.join(E,I.name),N,U=J.join(C,I.name);if(I.isFile()){if(N={kind:"file",mode:(await r.lstatPromise(U)).mode},a.value==="hardlinks-global"){let W=await Nn.checksumFile(U,{baseFs:r,algorithm:"sha1"});N.digest=W}}else if(I.isDirectory())N={kind:"directory"};else if(I.isSymbolicLink())N={kind:"symlink",symlinkTo:await r.readlinkPromise(U)};else throw new Error(`Unsupported file type (file: ${U}, mode: 0o${await r.statSync(U).mode.toString(8).padStart(6,"0")})`);if(P.set(R,N),I.isDirectory()&&R!==Ti){let W=await f(R);for(let[ee,ie]of W)P.set(ee,ie)}}return P},p;if(a.value==="hardlinks-global"&&s&&c){let E=J.join(s,c.substring(0,2),`${c.substring(2)}.json`);try{p=new Map(Object.entries(JSON.parse(await ce.readFilePromise(E,"utf8"))))}catch{p=await f()}}else p=await f();let h=!1;for(let[E,C]of p){let S=J.join(e,E),P=J.join(t,E);if(C.kind==="directory")await ce.mkdirPromise(P,{recursive:!0});else if(C.kind==="file"){let I=C.mtimeMs;await Hdt({srcPath:S,dstPath:P,entry:C,nmMode:a,baseFs:r,globalHardlinksStore:s}),C.mtimeMs!==I&&(h=!0)}else C.kind==="symlink"&&await QY(J.resolve(J.dirname(P),C.symlinkTo),P,n)}if(a.value==="hardlinks-global"&&s&&h&&c){let E=J.join(s,c.substring(0,2),`${c.substring(2)}.json`);await ce.removePromise(E),await qBe(s,E,Buffer.from(JSON.stringify(Object.fromEntries(p))))}};function Gdt(t,e,r,s){let a=new Map,n=new Map,c=new Map,f=!1,p=(h,E,C,S,P)=>{let I=!0,R=J.join(h,E),N=new Set;if(E===Ti||E.startsWith("@")){let W;try{W=ce.statSync(R)}catch{}I=!!W,W?W.mtimeMs>r?(f=!0,N=new Set(ce.readdirSync(R))):N=new Set(C.children.get(E).children.keys()):f=!0;let ee=e.get(h);if(ee){let ie=J.join(h,Ti,aN),ue;try{ue=ce.statSync(ie)}catch{}if(!ue)f=!0;else if(ue.mtimeMs>r){f=!0;let le=new Set(ce.readdirSync(ie)),me=new Map;n.set(h,me);for(let[pe,Be]of ee)le.has(pe)&&me.set(pe,Be)}else n.set(h,ee)}}else I=P.has(E);let U=C.children.get(E);if(I){let{linkType:W,locator:ee}=U,ie={children:new Map,linkType:W,locator:ee};if(S.children.set(E,ie),ee){let ue=je.getSetWithDefault(c,ee);ue.add(R),c.set(ee,ue)}for(let ue of U.children.keys())p(R,ue,U,ie,N)}else U.locator&&s.storedBuildState.delete(G.parseLocator(U.locator).locatorHash)};for(let[h,E]of t){let{linkType:C,locator:S}=E,P={children:new Map,linkType:C,locator:S};if(a.set(h,P),S){let I=je.getSetWithDefault(c,E.locator);I.add(h),c.set(E.locator,I)}E.children.has(Ti)&&p(h,Ti,E,P,new Set)}return{locationTree:a,binSymlinks:n,locatorLocations:c,installChangedByUser:f}}function WBe(t){let e=G.parseDescriptor(t);return G.isVirtualDescriptor(e)&&(e=G.devirtualizeDescriptor(e)),e.range.startsWith("link:")}async function qdt(t,e,r,{loadManifest:s}){let a=new Map;for(let[f,{locations:p}]of t){let h=WBe(f)?null:await s(f,p[0]),E=new Map;if(h)for(let[C,S]of h.bin){let P=J.join(p[0],S);S!==""&&ce.existsSync(P)&&E.set(C,S)}a.set(f,E)}let n=new Map,c=(f,p,h)=>{let E=new Map,C=J.contains(r,f);if(h.locator&&C!==null){let S=a.get(h.locator);for(let[P,I]of S){let R=J.join(f,fe.toPortablePath(I));E.set(P,R)}for(let[P,I]of h.children){let R=J.join(f,P),N=c(R,R,I);N.size>0&&n.set(f,new Map([...n.get(f)||new Map,...N]))}}else for(let[S,P]of h.children){let I=c(J.join(f,S),p,P);for(let[R,N]of I)E.set(R,N)}return E};for(let[f,p]of e){let h=c(f,f,p);h.size>0&&n.set(f,new Map([...n.get(f)||new Map,...h]))}return n}var MBe=(t,e)=>{if(!t||!e)return t===e;let r=G.parseLocator(t);G.isVirtualLocator(r)&&(r=G.devirtualizeLocator(r));let s=G.parseLocator(e);return G.isVirtualLocator(s)&&(s=G.devirtualizeLocator(s)),G.areLocatorsEqual(r,s)};function TY(t){return J.join(t.get("globalFolder"),"store")}function Wdt(t,e){let r=s=>{let a=s.split(J.sep),n=a.lastIndexOf(Ti);if(n<0||n==a.length-1)throw new Error(`Assertion failed. Path is outside of any node_modules package ${s}`);return a.slice(0,n+(a[n+1].startsWith("@")?3:2)).join(J.sep)};for(let s of t.values())for(let[a,n]of s)e.has(r(n))&&s.delete(a)}async function Ydt(t,e,{baseFs:r,project:s,report:a,loadManifest:n,realLocatorChecksums:c}){let f=J.join(s.cwd,Ti),{locationTree:p,binSymlinks:h,locatorLocations:E,installChangedByUser:C}=Gdt(t.locationTree,t.binSymlinks,t.mtimeMs,s),S=GBe(e,{skipPrefix:s.cwd}),P=[],I=async({srcDir:Be,dstDir:Ce,linkType:g,globalHardlinksStore:we,nmMode:ye,windowsLinkType:Ae,packageChecksum:se})=>{let Z=(async()=>{try{g==="SOFT"?(await ce.mkdirPromise(J.dirname(Ce),{recursive:!0}),await QY(J.resolve(Be),Ce,Ae)):await jdt(Ce,Be,{baseFs:r,globalHardlinksStore:we,nmMode:ye,windowsLinkType:Ae,packageChecksum:se})}catch(De){throw De.message=`While persisting ${Be} -> ${Ce} ${De.message}`,De}finally{ie.tick()}})().then(()=>P.splice(P.indexOf(Z),1));P.push(Z),P.length>LBe&&await Promise.race(P)},R=async(Be,Ce,g)=>{let we=(async()=>{let ye=async(Ae,se,Z)=>{try{Z.innerLoop||await ce.mkdirPromise(se,{recursive:!0});let De=await ce.readdirPromise(Ae,{withFileTypes:!0});for(let Re of De){if(!Z.innerLoop&&Re.name===aN)continue;let mt=J.join(Ae,Re.name),j=J.join(se,Re.name);Re.isDirectory()?(Re.name!==Ti||Z&&Z.innerLoop)&&(await ce.mkdirPromise(j,{recursive:!0}),await ye(mt,j,{...Z,innerLoop:!0})):me.value==="hardlinks-local"||me.value==="hardlinks-global"?await ce.linkPromise(mt,j):await ce.copyFilePromise(mt,j,_Be.default.constants.COPYFILE_FICLONE)}}catch(De){throw Z.innerLoop||(De.message=`While cloning ${Ae} -> ${se} ${De.message}`),De}finally{Z.innerLoop||ie.tick()}};await ye(Be,Ce,g)})().then(()=>P.splice(P.indexOf(we),1));P.push(we),P.length>LBe&&await Promise.race(P)},N=async(Be,Ce,g)=>{if(g)for(let[we,ye]of Ce.children){let Ae=g.children.get(we);await N(J.join(Be,we),ye,Ae)}else{Ce.children.has(Ti)&&await bw(J.join(Be,Ti),{contentsOnly:!1});let we=J.basename(Be)===Ti&&p.has(J.join(J.dirname(Be)));await bw(Be,{contentsOnly:Be===f,isWorkspaceDir:we})}};for(let[Be,Ce]of p){let g=S.get(Be);for(let[we,ye]of Ce.children){if(we===".")continue;let Ae=g&&g.children.get(we),se=J.join(Be,we);await N(se,ye,Ae)}}let U=async(Be,Ce,g)=>{if(g){MBe(Ce.locator,g.locator)||await bw(Be,{contentsOnly:Ce.linkType==="HARD"});for(let[we,ye]of Ce.children){let Ae=g.children.get(we);await U(J.join(Be,we),ye,Ae)}}else{Ce.children.has(Ti)&&await bw(J.join(Be,Ti),{contentsOnly:!0});let we=J.basename(Be)===Ti&&S.has(J.join(J.dirname(Be)));await bw(Be,{contentsOnly:Ce.linkType==="HARD",isWorkspaceDir:we})}};for(let[Be,Ce]of S){let g=p.get(Be);for(let[we,ye]of Ce.children){if(we===".")continue;let Ae=g&&g.children.get(we);await U(J.join(Be,we),ye,Ae)}}let W=new Map,ee=[];for(let[Be,Ce]of E)for(let g of Ce){let{locationRoot:we,segments:ye}=lN(g,{skipPrefix:s.cwd}),Ae=S.get(we),se=we;if(Ae){for(let Z of ye)if(se=J.join(se,Z),Ae=Ae.children.get(Z),!Ae)break;if(Ae){let Z=MBe(Ae.locator,Be),De=e.get(Ae.locator),Re=De.target,mt=se,j=De.linkType;if(Z)W.has(Re)||W.set(Re,mt);else if(Re!==mt){let rt=G.parseLocator(Ae.locator);G.isVirtualLocator(rt)&&(rt=G.devirtualizeLocator(rt)),ee.push({srcDir:Re,dstDir:mt,linkType:j,realLocatorHash:rt.locatorHash})}}}}for(let[Be,{locations:Ce}]of e.entries())for(let g of Ce){let{locationRoot:we,segments:ye}=lN(g,{skipPrefix:s.cwd}),Ae=p.get(we),se=S.get(we),Z=we,De=e.get(Be),Re=G.parseLocator(Be);G.isVirtualLocator(Re)&&(Re=G.devirtualizeLocator(Re));let mt=Re.locatorHash,j=De.target,rt=g;if(j===rt)continue;let Fe=De.linkType;for(let Ne of ye)se=se.children.get(Ne);if(!Ae)ee.push({srcDir:j,dstDir:rt,linkType:Fe,realLocatorHash:mt});else for(let Ne of ye)if(Z=J.join(Z,Ne),Ae=Ae.children.get(Ne),!Ae){ee.push({srcDir:j,dstDir:rt,linkType:Fe,realLocatorHash:mt});break}}let ie=Ao.progressViaCounter(ee.length),ue=a.reportProgress(ie),le=s.configuration.get("nmMode"),me={value:le},pe=s.configuration.get("winLinkType");try{let Be=me.value==="hardlinks-global"?`${TY(s.configuration)}/v1`:null;if(Be&&!await ce.existsPromise(Be)){await ce.mkdirpPromise(Be);for(let g=0;g<256;g++)await ce.mkdirPromise(J.join(Be,g.toString(16).padStart(2,"0")))}for(let g of ee)(g.linkType==="SOFT"||!W.has(g.srcDir))&&(W.set(g.srcDir,g.dstDir),await I({...g,globalHardlinksStore:Be,nmMode:me,windowsLinkType:pe,packageChecksum:c.get(g.realLocatorHash)||null}));await Promise.all(P),P.length=0;for(let g of ee){let we=W.get(g.srcDir);g.linkType!=="SOFT"&&g.dstDir!==we&&await R(we,g.dstDir,{nmMode:me})}await Promise.all(P),await ce.mkdirPromise(f,{recursive:!0}),Wdt(h,new Set(ee.map(g=>g.dstDir)));let Ce=await qdt(e,S,s.cwd,{loadManifest:n});await Vdt(h,Ce,s.cwd,pe),await _dt(s,e,Ce,me,{installChangedByUser:C}),le=="hardlinks-global"&&me.value=="hardlinks-local"&&a.reportWarningOnce(74,"'nmMode' has been downgraded to 'hardlinks-local' due to global cache and install folder being on different devices")}finally{ue.stop()}}async function Vdt(t,e,r,s){for(let a of t.keys()){if(J.contains(r,a)===null)throw new Error(`Assertion failed. Excepted bin symlink location to be inside project dir, instead it was at ${a}`);if(!e.has(a)){let n=J.join(a,Ti,aN);await ce.removePromise(n)}}for(let[a,n]of e){if(J.contains(r,a)===null)throw new Error(`Assertion failed. Excepted bin symlink location to be inside project dir, instead it was at ${a}`);let c=J.join(a,Ti,aN),f=t.get(a)||new Map;await ce.mkdirPromise(c,{recursive:!0});for(let p of f.keys())n.has(p)||(await ce.removePromise(J.join(c,p)),process.platform==="win32"&&await ce.removePromise(J.join(c,`${p}.cmd`)));for(let[p,h]of n){let E=f.get(p),C=J.join(c,p);E!==h&&(process.platform==="win32"?await(0,UBe.default)(fe.fromPortablePath(h),fe.fromPortablePath(C),{createPwshFile:!1}):(await ce.removePromise(C),await QY(h,C,s),J.contains(r,await ce.realpathPromise(h))!==null&&await ce.chmodPromise(h,493)))}}}Ge();Dt();eA();var GD=class extends sg{constructor(){super(...arguments);this.mode="loose"}makeInstaller(r){return new RY(r)}},RY=class extends Gm{constructor(){super(...arguments);this.mode="loose"}async transformPnpSettings(r){let s=new uo({baseFs:new $f({maxOpenFiles:80,readOnlyArchives:!0,customZipImplementation:ST})}),a=SBe(r,this.opts.project.cwd,s),{tree:n,errors:c}=kD(a,{pnpifyFs:!1,project:this.opts.project});if(!n){for(let{messageName:C,text:S}of c)this.opts.report.reportError(C,S);return}let f=new Map;r.fallbackPool=f;let p=(C,S)=>{let P=G.parseLocator(S.locator),I=G.stringifyIdent(P);I===C?f.set(C,P.reference):f.set(C,[I,P.reference])},h=J.join(this.opts.project.cwd,Er.nodeModules),E=n.get(h);if(!(typeof E>"u")){if("target"in E)throw new Error("Assertion failed: Expected the root junction point to be a directory");for(let C of E.dirList){let S=J.join(h,C),P=n.get(S);if(typeof P>"u")throw new Error("Assertion failed: Expected the child to have been registered");if("target"in P)p(C,P);else for(let I of P.dirList){let R=J.join(S,I),N=n.get(R);if(typeof N>"u")throw new Error("Assertion failed: Expected the subchild to have been registered");if("target"in N)p(`${C}/${I}`,N);else throw new Error("Assertion failed: Expected the leaf junction to be a package")}}}}};var Jdt={hooks:{cleanGlobalArtifacts:async t=>{let e=TY(t);await ce.removePromise(e)}},configuration:{nmHoistingLimits:{description:"Prevents packages to be hoisted past specific levels",type:"STRING",values:["workspaces","dependencies","none"],default:"none"},nmMode:{description:"Defines in which measure Yarn must use hardlinks and symlinks when generated `node_modules` directories.",type:"STRING",values:["classic","hardlinks-local","hardlinks-global"],default:"classic"},nmSelfReferences:{description:"Defines whether the linker should generate self-referencing symlinks for workspaces.",type:"BOOLEAN",default:!0}},linkers:[jD,GD]},Kdt=Jdt;var FK={};Vt(FK,{NpmHttpFetcher:()=>VD,NpmRemapResolver:()=>JD,NpmSemverFetcher:()=>oh,NpmSemverResolver:()=>KD,NpmTagResolver:()=>zD,default:()=>ubt,npmConfigUtils:()=>hi,npmHttpUtils:()=>en,npmPublishUtils:()=>v1});Ge();var $Be=ut(Ai());var oi="npm:";var en={};Vt(en,{AuthType:()=>zBe,customPackageError:()=>qm,del:()=>Amt,get:()=>Wm,getIdentUrl:()=>WD,getPackageMetadata:()=>Qw,handleInvalidAuthenticationError:()=>ag,post:()=>umt,put:()=>fmt});Ge();Ge();Dt();var LY=ut(Vv());ql();var KBe=ut(Ai());var hi={};Vt(hi,{RegistryType:()=>VBe,getAuditRegistry:()=>zdt,getAuthConfiguration:()=>OY,getDefaultRegistry:()=>qD,getPublishRegistry:()=>Xdt,getRegistryConfiguration:()=>JBe,getScopeConfiguration:()=>NY,getScopeRegistry:()=>Pw,isPackageApproved:()=>xw,normalizeRegistry:()=>Jc});Ge();var YBe=ut(Go()),VBe=(s=>(s.AUDIT_REGISTRY="npmAuditRegistry",s.FETCH_REGISTRY="npmRegistryServer",s.PUBLISH_REGISTRY="npmPublishRegistry",s))(VBe||{});function Jc(t){return t.replace(/\/$/,"")}function zdt({configuration:t}){return qD({configuration:t,type:"npmAuditRegistry"})}function Xdt(t,{configuration:e}){return t.publishConfig?.registry?Jc(t.publishConfig.registry):t.name?Pw(t.name.scope,{configuration:e,type:"npmPublishRegistry"}):qD({configuration:e,type:"npmPublishRegistry"})}function Pw(t,{configuration:e,type:r="npmRegistryServer"}){let s=NY(t,{configuration:e});if(s===null)return qD({configuration:e,type:r});let a=s.get(r);return a===null?qD({configuration:e,type:r}):Jc(a)}function qD({configuration:t,type:e="npmRegistryServer"}){let r=t.get(e);return Jc(r!==null?r:t.get("npmRegistryServer"))}function JBe(t,{configuration:e}){let r=e.get("npmRegistries"),s=Jc(t),a=r.get(s);if(typeof a<"u")return a;let n=r.get(s.replace(/^[a-z]+:/,""));return typeof n<"u"?n:null}var Zdt=new Map([["npmRegistryServer","https://npm.jsr.io/"]]);function NY(t,{configuration:e}){if(t===null)return null;let s=e.get("npmScopes").get(t);return s||(t==="jsr"?Zdt:null)}function OY(t,{configuration:e,ident:r}){let s=r&&NY(r.scope,{configuration:e});return s?.get("npmAuthIdent")||s?.get("npmAuthToken")?s:JBe(t,{configuration:e})||e}function $dt({configuration:t,version:e,publishTimes:r}){let s=t.get("npmMinimalAgeGate");if(s){let a=r?.[e];if(typeof a>"u"||(new Date().getTime()-new Date(a).getTime())/60/1e3emt(e,r,s))}function xw(t){return!$dt(t)||tmt(t)}var zBe=(a=>(a[a.NO_AUTH=0]="NO_AUTH",a[a.BEST_EFFORT=1]="BEST_EFFORT",a[a.CONFIGURATION=2]="CONFIGURATION",a[a.ALWAYS_AUTH=3]="ALWAYS_AUTH",a))(zBe||{});async function ag(t,{attemptedAs:e,registry:r,headers:s,configuration:a}){if(uN(t))throw new jt(41,"Invalid OTP token");if(t.originalError?.name==="HTTPError"&&t.originalError?.response.statusCode===401)throw new jt(41,`Invalid authentication (${typeof e!="string"?`as ${await hmt(r,s,{configuration:a})}`:`attempted as ${e}`})`)}function qm(t,e){let r=t.response?.statusCode;return r?r===404?"Package not found":r>=500&&r<600?`The registry appears to be down (using a ${he.applyHyperlink(e,"local cache","https://yarnpkg.com/advanced/lexicon#local-cache")} might have protected you against such outages)`:null:null}function WD(t){return t.scope?`/@${t.scope}%2f${t.name}`:`/${t.name}`}var XBe=new Map,rmt=new Map;async function nmt(t){return await je.getFactoryWithDefault(XBe,t,async()=>{let e=null;try{e=await ce.readJsonPromise(t)}catch{}return e})}async function imt(t,e,{configuration:r,cached:s,registry:a,headers:n,version:c,...f}){return await je.getFactoryWithDefault(rmt,t,async()=>await Wm(WD(e),{...f,customErrorMessage:qm,configuration:r,registry:a,ident:e,headers:{...n,"If-None-Match":s?.etag,"If-Modified-Since":s?.lastModified},wrapNetworkRequest:async p=>async()=>{let h=await p();if(h.statusCode===304){if(s===null)throw new Error("Assertion failed: cachedMetadata should not be null");return{...h,body:s.metadata}}let E=omt(JSON.parse(h.body.toString())),C={metadata:E,etag:h.headers.etag,lastModified:h.headers["last-modified"]};return XBe.set(t,Promise.resolve(C)),Promise.resolve().then(async()=>{let S=`${t}-${process.pid}.tmp`;await ce.mkdirPromise(J.dirname(S),{recursive:!0}),await ce.writeJsonPromise(S,C,{compact:!0}),await ce.renamePromise(S,t)}).catch(()=>{}),{...h,body:E}}}))}function smt(t){return t.scope!==null?`@${t.scope}-${t.name}-${t.scope.length}`:t.name}async function Qw(t,{cache:e,project:r,registry:s,headers:a,version:n,...c}){let{configuration:f}=r;s=YD(f,{ident:t,registry:s});let p=lmt(f,s),h=J.join(p,`${smt(t)}.json`),E=null;if(!r.lockfileNeedsRefresh&&(E=await nmt(h),E)){if(typeof n<"u"&&typeof E.metadata.versions[n]<"u")return E.metadata;if(f.get("enableOfflineMode")){let C=structuredClone(E.metadata),S=new Set;if(e){for(let I of Object.keys(C.versions)){let R=G.makeLocator(t,`npm:${I}`),N=e.getLocatorMirrorPath(R);(!N||!ce.existsSync(N))&&(delete C.versions[I],S.add(I))}let P=C["dist-tags"].latest;if(S.has(P)){let I=Object.keys(E.metadata.versions).sort(KBe.default.compare),R=I.indexOf(P);for(;S.has(I[R])&&R>=0;)R-=1;R>=0?C["dist-tags"].latest=I[R]:delete C["dist-tags"].latest}}return C}}return await imt(h,t,{...c,configuration:f,cached:E,registry:s,headers:a,version:n})}var ZBe=["name","dist.tarball","bin","scripts","os","cpu","libc","dependencies","dependenciesMeta","optionalDependencies","peerDependencies","peerDependenciesMeta","deprecated"];function omt(t){return{"dist-tags":t["dist-tags"],versions:Object.fromEntries(Object.entries(t.versions).map(([e,r])=>[e,Kd(r,ZBe)])),time:t.time}}var amt=Nn.makeHash("time",...ZBe).slice(0,6);function lmt(t,e){let r=cmt(t),s=new URL(e);return J.join(r,amt,s.hostname)}function cmt(t){return J.join(t.get("globalFolder"),"metadata/npm")}async function Wm(t,{configuration:e,headers:r,ident:s,authType:a,allowOidc:n,registry:c,...f}){c=YD(e,{ident:s,registry:c}),s&&s.scope&&typeof a>"u"&&(a=1);let p=await cN(c,{authType:a,allowOidc:n,configuration:e,ident:s});p&&(r={...r,authorization:p});try{return await nn.get(t.charAt(0)==="/"?`${c}${t}`:t,{configuration:e,headers:r,...f})}catch(h){throw await ag(h,{registry:c,configuration:e,headers:r}),h}}async function umt(t,e,{attemptedAs:r,configuration:s,headers:a,ident:n,authType:c=3,allowOidc:f,registry:p,otp:h,...E}){p=YD(s,{ident:n,registry:p});let C=await cN(p,{authType:c,allowOidc:f,configuration:s,ident:n});C&&(a={...a,authorization:C}),h&&(a={...a,...kw(h)});try{return await nn.post(p+t,e,{configuration:s,headers:a,...E})}catch(S){if(!uN(S)||h)throw await ag(S,{attemptedAs:r,registry:p,configuration:s,headers:a}),S;h=await MY(S,{configuration:s});let P={...a,...kw(h)};try{return await nn.post(`${p}${t}`,e,{configuration:s,headers:P,...E})}catch(I){throw await ag(I,{attemptedAs:r,registry:p,configuration:s,headers:a}),I}}}async function fmt(t,e,{attemptedAs:r,configuration:s,headers:a,ident:n,authType:c=3,allowOidc:f,registry:p,otp:h,...E}){p=YD(s,{ident:n,registry:p});let C=await cN(p,{authType:c,allowOidc:f,configuration:s,ident:n});C&&(a={...a,authorization:C}),h&&(a={...a,...kw(h)});try{return await nn.put(p+t,e,{configuration:s,headers:a,...E})}catch(S){if(!uN(S))throw await ag(S,{attemptedAs:r,registry:p,configuration:s,headers:a}),S;h=await MY(S,{configuration:s});let P={...a,...kw(h)};try{return await nn.put(`${p}${t}`,e,{configuration:s,headers:P,...E})}catch(I){throw await ag(I,{attemptedAs:r,registry:p,configuration:s,headers:a}),I}}}async function Amt(t,{attemptedAs:e,configuration:r,headers:s,ident:a,authType:n=3,allowOidc:c,registry:f,otp:p,...h}){f=YD(r,{ident:a,registry:f});let E=await cN(f,{authType:n,allowOidc:c,configuration:r,ident:a});E&&(s={...s,authorization:E}),p&&(s={...s,...kw(p)});try{return await nn.del(f+t,{configuration:r,headers:s,...h})}catch(C){if(!uN(C)||p)throw await ag(C,{attemptedAs:e,registry:f,configuration:r,headers:s}),C;p=await MY(C,{configuration:r});let S={...s,...kw(p)};try{return await nn.del(`${f}${t}`,{configuration:r,headers:S,...h})}catch(P){throw await ag(P,{attemptedAs:e,registry:f,configuration:r,headers:s}),P}}}function YD(t,{ident:e,registry:r}){if(typeof r>"u"&&e)return Pw(e.scope,{configuration:t});if(typeof r!="string")throw new Error("Assertion failed: The registry should be a string");return Jc(r)}async function cN(t,{authType:e=2,allowOidc:r=!1,configuration:s,ident:a}){let n=OY(t,{configuration:s,ident:a}),c=pmt(n,e);if(!c)return null;let f=await s.reduceHook(p=>p.getNpmAuthenticationHeader,void 0,t,{configuration:s,ident:a});if(f)return f;if(n.get("npmAuthToken"))return`Bearer ${n.get("npmAuthToken")}`;if(n.get("npmAuthIdent")){let p=n.get("npmAuthIdent");return p.includes(":")?`Basic ${Buffer.from(p).toString("base64")}`:`Basic ${p}`}if(r&&a){let p=await gmt(t,{configuration:s,ident:a});if(p)return`Bearer ${p}`}if(c&&e!==1)throw new jt(33,"No authentication configured for request");return null}function pmt(t,e){switch(e){case 2:return t.get("npmAlwaysAuth");case 1:case 3:return!0;case 0:return!1;default:throw new Error("Unreachable")}}async function hmt(t,e,{configuration:r}){if(typeof e>"u"||typeof e.authorization>"u")return"an anonymous user";try{return(await nn.get(new URL(`${t}/-/whoami`).href,{configuration:r,headers:e,jsonResponse:!0})).username??"an unknown user"}catch{return"an unknown user"}}async function MY(t,{configuration:e}){let r=t.originalError?.response.headers["npm-notice"];if(r&&(await Ot.start({configuration:e,stdout:process.stdout,includeFooter:!1},async a=>{if(a.reportInfo(0,r.replace(/(https?:\/\/\S+)/g,he.pretty(e,"$1",he.Type.URL))),!process.env.YARN_IS_TEST_ENV){let n=r.match(/open (https?:\/\/\S+)/i);if(n&&Ui.openUrl){let{openNow:c}=await(0,LY.prompt)({type:"confirm",name:"openNow",message:"Do you want to try to open this url now?",required:!0,initial:!0,onCancel:()=>process.exit(130)});c&&(await Ui.openUrl(n[1])||(a.reportSeparator(),a.reportWarning(0,"We failed to automatically open the url; you'll have to open it yourself in your browser of choice.")))}}}),process.stdout.write(` +`)),process.env.YARN_IS_TEST_ENV)return process.env.YARN_INJECT_NPM_2FA_TOKEN||"";let{otp:s}=await(0,LY.prompt)({type:"password",name:"otp",message:"One-time password:",required:!0,onCancel:()=>process.exit(130)});return process.stdout.write(` +`),s}function uN(t){if(t.originalError?.name!=="HTTPError")return!1;try{return(t.originalError?.response.headers["www-authenticate"].split(/,\s*/).map(r=>r.toLowerCase())).includes("otp")}catch{return!1}}function kw(t){return{"npm-otp":t}}async function gmt(t,{configuration:e,ident:r}){let s=null;if(process.env.GITLAB_CI)s=process.env.NPM_ID_TOKEN||null;else if(process.env.GITHUB_ACTIONS){if(!(process.env.ACTIONS_ID_TOKEN_REQUEST_URL&&process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN))return null;let a=`npm:${new URL(t).host.replace("registry.yarnpkg.com","registry.npmjs.org").replace("yarn.npmjs.org","registry.npmjs.org")}`,n=new URL(process.env.ACTIONS_ID_TOKEN_REQUEST_URL);n.searchParams.append("audience",a),s=(await nn.get(n.href,{configuration:e,jsonResponse:!0,headers:{Authorization:`Bearer ${process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN}`}})).value}if(!s)return null;try{return(await nn.post(`${t}/-/npm/v1/oidc/token/exchange/package${WD(r)}`,null,{configuration:e,jsonResponse:!0,headers:{Authorization:`Bearer ${s}`}})).token||null}catch{}return null}var VD=class{supports(e,r){if(!e.reference.startsWith(oi))return!1;let{selector:s,params:a}=G.parseRange(e.reference);return!(!$Be.default.valid(s)||a===null||typeof a.__archiveUrl!="string")}getLocalPath(e,r){return null}async fetch(e,r){let s=r.checksums.get(e.locatorHash)||null,[a,n,c]=await r.cache.fetchPackageFromCache(e,s,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${G.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the remote server`),loader:()=>this.fetchFromNetwork(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:G.getIdentVendorPath(e),checksum:c}}async fetchFromNetwork(e,r){let{params:s}=G.parseRange(e.reference);if(s===null||typeof s.__archiveUrl!="string")throw new Error("Assertion failed: The archiveUrl querystring parameter should have been available");let a=await Wm(s.__archiveUrl,{customErrorMessage:qm,configuration:r.project.configuration,ident:e});return await ps.convertToZip(a,{configuration:r.project.configuration,prefixPath:G.getIdentVendorPath(e),stripComponents:1})}};Ge();var JD=class{supportsDescriptor(e,r){return!(!e.range.startsWith(oi)||!G.tryParseDescriptor(e.range.slice(oi.length),!0))}supportsLocator(e,r){return!1}shouldPersistResolution(e,r){throw new Error("Unreachable")}bindDescriptor(e,r,s){return e}getResolutionDependencies(e,r){let s=r.project.configuration.normalizeDependency(G.parseDescriptor(e.range.slice(oi.length),!0));return r.resolver.getResolutionDependencies(s,r)}async getCandidates(e,r,s){let a=s.project.configuration.normalizeDependency(G.parseDescriptor(e.range.slice(oi.length),!0));return await s.resolver.getCandidates(a,r,s)}async getSatisfying(e,r,s,a){let n=a.project.configuration.normalizeDependency(G.parseDescriptor(e.range.slice(oi.length),!0));return a.resolver.getSatisfying(n,r,s,a)}resolve(e,r){throw new Error("Unreachable")}};Ge();Ge();var eve=ut(Ai());var oh=class t{supports(e,r){if(!e.reference.startsWith(oi))return!1;let s=new URL(e.reference);return!(!eve.default.valid(s.pathname)||s.searchParams.has("__archiveUrl"))}getLocalPath(e,r){return null}async fetch(e,r){let s=r.checksums.get(e.locatorHash)||null,[a,n,c]=await r.cache.fetchPackageFromCache(e,s,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${G.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the remote registry`),loader:()=>this.fetchFromNetwork(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:G.getIdentVendorPath(e),checksum:c}}async fetchFromNetwork(e,r){let s;try{s=await Wm(t.getLocatorUrl(e),{customErrorMessage:qm,configuration:r.project.configuration,ident:e})}catch{s=await Wm(t.getLocatorUrl(e).replace(/%2f/g,"/"),{customErrorMessage:qm,configuration:r.project.configuration,ident:e})}return await ps.convertToZip(s,{configuration:r.project.configuration,prefixPath:G.getIdentVendorPath(e),stripComponents:1})}static isConventionalTarballUrl(e,r,{configuration:s}){let a=Pw(e.scope,{configuration:s}),n=t.getLocatorUrl(e);return r=r.replace(/^https?:(\/\/(?:[^/]+\.)?npmjs.org(?:$|\/))/,"https:$1"),a=a.replace(/^https:\/\/registry\.npmjs\.org($|\/)/,"https://registry.yarnpkg.com$1"),r=r.replace(/^https:\/\/registry\.npmjs\.org($|\/)/,"https://registry.yarnpkg.com$1"),r===a+n||r===a+n.replace(/%2f/g,"/")}static getLocatorUrl(e){let r=Fr.clean(e.reference.slice(oi.length));if(r===null)throw new jt(10,"The npm semver resolver got selected, but the version isn't semver");return`${WD(e)}/-/${e.name}-${r}.tgz`}};Ge();Ge();Ge();var UY=ut(Ai());var fN=G.makeIdent(null,"node-gyp"),dmt=/\b(node-gyp|prebuild-install)\b/,KD=class{supportsDescriptor(e,r){return e.range.startsWith(oi)?!!Fr.validRange(e.range.slice(oi.length)):!1}supportsLocator(e,r){if(!e.reference.startsWith(oi))return!1;let{selector:s}=G.parseRange(e.reference);return!!UY.default.valid(s)}shouldPersistResolution(e,r){return!0}bindDescriptor(e,r,s){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,s){let a=Fr.validRange(e.range.slice(oi.length));if(a===null)throw new Error(`Expected a valid range, got ${e.range.slice(oi.length)}`);let n=await Qw(e,{cache:s.fetchOptions?.cache,project:s.project,version:UY.default.valid(a.raw)?a.raw:void 0}),c=je.mapAndFilter(Object.keys(n.versions),h=>{try{let E=new Fr.SemVer(h);if(a.test(E))return xw({configuration:s.project.configuration,ident:e,version:h,publishTimes:n.time})?E:je.mapAndFilter.skip}catch{}return je.mapAndFilter.skip}),f=c.filter(h=>!n.versions[h.raw].deprecated),p=f.length>0?f:c;return p.sort((h,E)=>-h.compare(E)),p.map(h=>{let E=G.makeLocator(e,`${oi}${h.raw}`),C=n.versions[h.raw].dist.tarball;return oh.isConventionalTarballUrl(E,C,{configuration:s.project.configuration})?E:G.bindLocator(E,{__archiveUrl:C})})}async getSatisfying(e,r,s,a){let n=Fr.validRange(e.range.slice(oi.length));if(n===null)throw new Error(`Expected a valid range, got ${e.range.slice(oi.length)}`);return{locators:je.mapAndFilter(s,p=>{if(p.identHash!==e.identHash)return je.mapAndFilter.skip;let h=G.tryParseRange(p.reference,{requireProtocol:oi});if(!h)return je.mapAndFilter.skip;let E=new Fr.SemVer(h.selector);return n.test(E)?{locator:p,version:E}:je.mapAndFilter.skip}).sort((p,h)=>-p.version.compare(h.version)).map(({locator:p})=>p),sorted:!0}}async resolve(e,r){let{selector:s}=G.parseRange(e.reference),a=Fr.clean(s);if(a===null)throw new jt(10,"The npm semver resolver got selected, but the version isn't semver");let n=await Qw(e,{cache:r.fetchOptions?.cache,project:r.project,version:a});if(!Object.hasOwn(n,"versions"))throw new jt(15,'Registry returned invalid data for - missing "versions" field');if(!Object.hasOwn(n.versions,a))throw new jt(16,`Registry failed to return reference "${a}"`);let c=new Ut;if(c.load(n.versions[a]),!c.dependencies.has(fN.identHash)&&!c.peerDependencies.has(fN.identHash)){for(let f of c.scripts.values())if(f.match(dmt)){c.dependencies.set(fN.identHash,G.makeDescriptor(fN,"latest"));break}}return{...e,version:a,languageName:"node",linkType:"HARD",conditions:c.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(c.dependencies),peerDependencies:c.peerDependencies,dependenciesMeta:c.dependenciesMeta,peerDependenciesMeta:c.peerDependenciesMeta,bin:c.bin}}};Ge();Ge();var AN=ut(Ai());var zD=class{supportsDescriptor(e,r){return!(!e.range.startsWith(oi)||!Mp.test(e.range.slice(oi.length)))}supportsLocator(e,r){return!1}shouldPersistResolution(e,r){throw new Error("Unreachable")}bindDescriptor(e,r,s){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,s){let a=e.range.slice(oi.length),n=await Qw(e,{cache:s.fetchOptions?.cache,project:s.project});if(!Object.hasOwn(n,"dist-tags"))throw new jt(15,'Registry returned invalid data - missing "dist-tags" field');let c=n["dist-tags"];if(!Object.hasOwn(c,a))throw new jt(16,`Registry failed to return tag "${a}"`);let f=Object.keys(n.versions),p=n.time,h=c[a];if(a==="latest"&&!xw({configuration:s.project.configuration,ident:e,version:h,publishTimes:p})){let S=h.includes("-"),P=AN.default.rsort(f).find(I=>AN.default.lt(I,h)&&(S||!I.includes("-"))&&xw({configuration:s.project.configuration,ident:e,version:I,publishTimes:p}));if(!P)throw new jt(16,`The version for tag "${a}" is quarantined, and no lower version is available`);h=P}let E=G.makeLocator(e,`${oi}${h}`),C=n.versions[h].dist.tarball;return oh.isConventionalTarballUrl(E,C,{configuration:s.project.configuration})?[E]:[G.bindLocator(E,{__archiveUrl:C})]}async getSatisfying(e,r,s,a){let n=[];for(let c of s){if(c.identHash!==e.identHash)continue;let f=G.tryParseRange(c.reference,{requireProtocol:oi});if(!(!f||!AN.default.valid(f.selector))){if(f.params?.__archiveUrl){let p=G.makeRange({protocol:oi,selector:f.selector,source:null,params:null}),[h]=await a.resolver.getCandidates(G.makeDescriptor(e,p),r,a);if(c.reference!==h.reference)continue}n.push(c)}}return{locators:n,sorted:!1}}async resolve(e,r){throw new Error("Unreachable")}};var v1={};Vt(v1,{getGitHead:()=>abt,getPublishAccess:()=>qxe,getReadmeContent:()=>Wxe,makePublishBody:()=>obt});Ge();Ge();Dt();var bV={};Vt(bV,{PackCommand:()=>jw,default:()=>KEt,packUtils:()=>yA});Ge();Ge();Ge();Dt();Yt();var yA={};Vt(yA,{genPackList:()=>NN,genPackStream:()=>DV,genPackageManifest:()=>QSe,hasPackScripts:()=>vV,prepareForPack:()=>SV});Ge();Dt();var BV=ut(Go()),xSe=ut(SSe()),kSe=Ie("zlib"),MEt=["/package.json","/readme","/readme.*","/license","/license.*","/licence","/licence.*","/changelog","/changelog.*"],UEt=["/package.tgz",".github",".git",".hg","node_modules",".npmignore",".gitignore",".#*",".DS_Store"];async function vV(t){return!!(In.hasWorkspaceScript(t,"prepack")||In.hasWorkspaceScript(t,"postpack"))}async function SV(t,{report:e},r){await In.maybeExecuteWorkspaceLifecycleScript(t,"prepack",{report:e});try{let s=J.join(t.cwd,Ut.fileName);await ce.existsPromise(s)&&await t.manifest.loadFile(s,{baseFs:ce}),await r()}finally{await In.maybeExecuteWorkspaceLifecycleScript(t,"postpack",{report:e})}}async function DV(t,e){typeof e>"u"&&(e=await NN(t));let r=new Set;for(let n of t.manifest.publishConfig?.executableFiles??new Set)r.add(J.normalize(n));for(let n of t.manifest.bin.values())r.add(J.normalize(n));let s=xSe.default.pack();process.nextTick(async()=>{for(let n of e){let c=J.normalize(n),f=J.resolve(t.cwd,c),p=J.join("package",c),h=await ce.lstatPromise(f),E={name:p,mtime:new Date(fi.SAFE_TIME*1e3)},C=r.has(c)?493:420,S,P,I=new Promise((N,U)=>{S=N,P=U}),R=N=>{N?P(N):S()};if(h.isFile()){let N;c==="package.json"?N=Buffer.from(JSON.stringify(await QSe(t),null,2)):N=await ce.readFilePromise(f),s.entry({...E,mode:C,type:"file"},N,R)}else h.isSymbolicLink()?s.entry({...E,mode:C,type:"symlink",linkname:await ce.readlinkPromise(f)},R):R(new Error(`Unsupported file type ${h.mode} for ${fe.fromPortablePath(c)}`));await I}s.finalize()});let a=(0,kSe.createGzip)();return s.pipe(a),a}async function QSe(t){let e=JSON.parse(JSON.stringify(t.manifest.raw));return await t.project.configuration.triggerHook(r=>r.beforeWorkspacePacking,t,e),e}async function NN(t){let e=t.project,r=e.configuration,s={accept:[],reject:[]};for(let C of UEt)s.reject.push(C);for(let C of MEt)s.accept.push(C);s.reject.push(r.get("rcFilename"));let a=C=>{if(C===null||!C.startsWith(`${t.cwd}/`))return;let S=J.relative(t.cwd,C),P=J.resolve(vt.root,S);s.reject.push(P)};a(J.resolve(e.cwd,Er.lockfile)),a(r.get("cacheFolder")),a(r.get("globalFolder")),a(r.get("installStatePath")),a(r.get("virtualFolder")),a(r.get("yarnPath")),await r.triggerHook(C=>C.populateYarnPaths,e,C=>{a(C)});for(let C of e.workspaces){let S=J.relative(t.cwd,C.cwd);S!==""&&!S.match(/^(\.\.)?\//)&&s.reject.push(`/${S}`)}let n={accept:[],reject:[]},c=t.manifest.publishConfig?.main??t.manifest.main,f=t.manifest.publishConfig?.module??t.manifest.module,p=t.manifest.publishConfig?.browser??t.manifest.browser,h=t.manifest.publishConfig?.bin??t.manifest.bin;c!=null&&n.accept.push(J.resolve(vt.root,c)),f!=null&&n.accept.push(J.resolve(vt.root,f)),typeof p=="string"&&n.accept.push(J.resolve(vt.root,p));for(let C of h.values())n.accept.push(J.resolve(vt.root,C));if(p instanceof Map)for(let[C,S]of p.entries())n.accept.push(J.resolve(vt.root,C)),typeof S=="string"&&n.accept.push(J.resolve(vt.root,S));let E=t.manifest.files!==null;if(E){n.reject.push("/*");for(let C of t.manifest.files)TSe(n.accept,C,{cwd:vt.root})}return await _Et(t.cwd,{hasExplicitFileList:E,globalList:s,ignoreList:n})}async function _Et(t,{hasExplicitFileList:e,globalList:r,ignoreList:s}){let a=[],n=new Hf(t),c=[[vt.root,[s]]];for(;c.length>0;){let[f,p]=c.pop(),h=await n.lstatPromise(f);if(!bSe(f,{globalList:r,ignoreLists:h.isDirectory()?null:p}))if(h.isDirectory()){let E=await n.readdirPromise(f),C=!1,S=!1;if(!e||f!==vt.root)for(let R of E)C=C||R===".gitignore",S=S||R===".npmignore";let P=S?await DSe(n,f,".npmignore"):C?await DSe(n,f,".gitignore"):null,I=P!==null?[P].concat(p):p;bSe(f,{globalList:r,ignoreLists:p})&&(I=[...p,{accept:[],reject:["**/*"]}]);for(let R of E)c.push([J.resolve(f,R),I])}else(h.isFile()||h.isSymbolicLink())&&a.push(J.relative(vt.root,f))}return a.sort()}async function DSe(t,e,r){let s={accept:[],reject:[]},a=await t.readFilePromise(J.join(e,r),"utf8");for(let n of a.split(/\n/g))TSe(s.reject,n,{cwd:e});return s}function HEt(t,{cwd:e}){let r=t[0]==="!";return r&&(t=t.slice(1)),t.match(/\.{0,1}\//)&&(t=J.resolve(e,t)),r&&(t=`!${t}`),t}function TSe(t,e,{cwd:r}){let s=e.trim();s===""||s[0]==="#"||t.push(HEt(s,{cwd:r}))}function bSe(t,{globalList:e,ignoreLists:r}){let s=FN(t,e.accept);if(s!==0)return s===2;let a=FN(t,e.reject);if(a!==0)return a===1;if(r!==null)for(let n of r){let c=FN(t,n.accept);if(c!==0)return c===2;let f=FN(t,n.reject);if(f!==0)return f===1}return!1}function FN(t,e){let r=e,s=[];for(let a=0;a{await SV(a,{report:p},async()=>{p.reportJson({base:fe.fromPortablePath(a.cwd)});let h=await NN(a);for(let E of h)p.reportInfo(null,fe.fromPortablePath(E)),p.reportJson({location:fe.fromPortablePath(E)});if(!this.dryRun){let E=await DV(a,h);await ce.mkdirPromise(J.dirname(c),{recursive:!0});let C=ce.createWriteStream(c);E.pipe(C),await new Promise(S=>{C.on("finish",S)})}}),this.dryRun||(p.reportInfo(0,`Package archive generated in ${he.pretty(r,c,he.Type.PATH)}`),p.reportJson({output:fe.fromPortablePath(c)}))})).exitCode()}};function jEt(t,{workspace:e}){let r=t.replace("%s",GEt(e)).replace("%v",qEt(e));return fe.toPortablePath(r)}function GEt(t){return t.manifest.name!==null?G.slugifyIdent(t.manifest.name):"package"}function qEt(t){return t.manifest.version!==null?t.manifest.version:"unknown"}var WEt=["dependencies","devDependencies","peerDependencies"],YEt="workspace:",VEt=(t,e)=>{e.publishConfig&&(e.publishConfig.type&&(e.type=e.publishConfig.type),e.publishConfig.main&&(e.main=e.publishConfig.main),e.publishConfig.browser&&(e.browser=e.publishConfig.browser),e.publishConfig.module&&(e.module=e.publishConfig.module),e.publishConfig.exports&&(e.exports=e.publishConfig.exports),e.publishConfig.imports&&(e.imports=e.publishConfig.imports),e.publishConfig.bin&&(e.bin=e.publishConfig.bin));let r=t.project;for(let s of WEt)for(let a of t.manifest.getForScope(s).values()){let n=r.tryWorkspaceByDescriptor(a),c=G.parseRange(a.range);if(c.protocol===YEt)if(n===null){if(r.tryWorkspaceByIdent(a)===null)throw new jt(21,`${G.prettyDescriptor(r.configuration,a)}: No local workspace found for this range`)}else{let f;G.areDescriptorsEqual(a,n.anchoredDescriptor)||c.selector==="*"?f=n.manifest.version??"0.0.0":c.selector==="~"||c.selector==="^"?f=`${c.selector}${n.manifest.version??"0.0.0"}`:f=c.selector;let p=s==="dependencies"?G.makeDescriptor(a,"unknown"):null,h=p!==null&&t.manifest.ensureDependencyMeta(p).optional?"optionalDependencies":s;e[h][G.stringifyIdent(a)]=f}}},JEt={hooks:{beforeWorkspacePacking:VEt},commands:[jw]},KEt=JEt;var Gxe=ut(HSe());Ge();var Hxe=ut(_xe()),{env:Bt}=process,XDt="application/vnd.in-toto+json",ZDt="https://in-toto.io/Statement/v0.1",$Dt="https://in-toto.io/Statement/v1",ebt="https://slsa.dev/provenance/v0.2",tbt="https://slsa.dev/provenance/v1",rbt="https://github.com/actions/runner",nbt="https://slsa-framework.github.io/github-actions-buildtypes/workflow/v1",ibt="https://github.com/npm/cli/gitlab",sbt="v0alpha1",jxe=async(t,e)=>{let r;if(Bt.GITHUB_ACTIONS){if(!Bt.ACTIONS_ID_TOKEN_REQUEST_URL)throw new jt(91,'Provenance generation in GitHub Actions requires "write" access to the "id-token" permission');let s=(Bt.GITHUB_WORKFLOW_REF||"").replace(`${Bt.GITHUB_REPOSITORY}/`,""),a=s.indexOf("@"),n=s.slice(0,a),c=s.slice(a+1);r={_type:$Dt,subject:t,predicateType:tbt,predicate:{buildDefinition:{buildType:nbt,externalParameters:{workflow:{ref:c,repository:`${Bt.GITHUB_SERVER_URL}/${Bt.GITHUB_REPOSITORY}`,path:n}},internalParameters:{github:{event_name:Bt.GITHUB_EVENT_NAME,repository_id:Bt.GITHUB_REPOSITORY_ID,repository_owner_id:Bt.GITHUB_REPOSITORY_OWNER_ID}},resolvedDependencies:[{uri:`git+${Bt.GITHUB_SERVER_URL}/${Bt.GITHUB_REPOSITORY}@${Bt.GITHUB_REF}`,digest:{gitCommit:Bt.GITHUB_SHA}}]},runDetails:{builder:{id:`${rbt}/${Bt.RUNNER_ENVIRONMENT}`},metadata:{invocationId:`${Bt.GITHUB_SERVER_URL}/${Bt.GITHUB_REPOSITORY}/actions/runs/${Bt.GITHUB_RUN_ID}/attempts/${Bt.GITHUB_RUN_ATTEMPT}`}}}}}else if(Bt.GITLAB_CI){if(!Bt.SIGSTORE_ID_TOKEN)throw new jt(91,`Provenance generation in GitLab CI requires "SIGSTORE_ID_TOKEN" with "sigstore" audience to be present in "id_tokens". For more info see: +https://docs.gitlab.com/ee/ci/secrets/id_token_authentication.html`);r={_type:ZDt,subject:t,predicateType:ebt,predicate:{buildType:`${ibt}/${sbt}`,builder:{id:`${Bt.CI_PROJECT_URL}/-/runners/${Bt.CI_RUNNER_ID}`},invocation:{configSource:{uri:`git+${Bt.CI_PROJECT_URL}`,digest:{sha1:Bt.CI_COMMIT_SHA},entryPoint:Bt.CI_JOB_NAME},parameters:{CI:Bt.CI,CI_API_GRAPHQL_URL:Bt.CI_API_GRAPHQL_URL,CI_API_V4_URL:Bt.CI_API_V4_URL,CI_BUILD_BEFORE_SHA:Bt.CI_BUILD_BEFORE_SHA,CI_BUILD_ID:Bt.CI_BUILD_ID,CI_BUILD_NAME:Bt.CI_BUILD_NAME,CI_BUILD_REF:Bt.CI_BUILD_REF,CI_BUILD_REF_NAME:Bt.CI_BUILD_REF_NAME,CI_BUILD_REF_SLUG:Bt.CI_BUILD_REF_SLUG,CI_BUILD_STAGE:Bt.CI_BUILD_STAGE,CI_COMMIT_BEFORE_SHA:Bt.CI_COMMIT_BEFORE_SHA,CI_COMMIT_BRANCH:Bt.CI_COMMIT_BRANCH,CI_COMMIT_REF_NAME:Bt.CI_COMMIT_REF_NAME,CI_COMMIT_REF_PROTECTED:Bt.CI_COMMIT_REF_PROTECTED,CI_COMMIT_REF_SLUG:Bt.CI_COMMIT_REF_SLUG,CI_COMMIT_SHA:Bt.CI_COMMIT_SHA,CI_COMMIT_SHORT_SHA:Bt.CI_COMMIT_SHORT_SHA,CI_COMMIT_TIMESTAMP:Bt.CI_COMMIT_TIMESTAMP,CI_COMMIT_TITLE:Bt.CI_COMMIT_TITLE,CI_CONFIG_PATH:Bt.CI_CONFIG_PATH,CI_DEFAULT_BRANCH:Bt.CI_DEFAULT_BRANCH,CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX:Bt.CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX,CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX:Bt.CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX,CI_DEPENDENCY_PROXY_SERVER:Bt.CI_DEPENDENCY_PROXY_SERVER,CI_DEPENDENCY_PROXY_USER:Bt.CI_DEPENDENCY_PROXY_USER,CI_JOB_ID:Bt.CI_JOB_ID,CI_JOB_NAME:Bt.CI_JOB_NAME,CI_JOB_NAME_SLUG:Bt.CI_JOB_NAME_SLUG,CI_JOB_STAGE:Bt.CI_JOB_STAGE,CI_JOB_STARTED_AT:Bt.CI_JOB_STARTED_AT,CI_JOB_URL:Bt.CI_JOB_URL,CI_NODE_TOTAL:Bt.CI_NODE_TOTAL,CI_PAGES_DOMAIN:Bt.CI_PAGES_DOMAIN,CI_PAGES_URL:Bt.CI_PAGES_URL,CI_PIPELINE_CREATED_AT:Bt.CI_PIPELINE_CREATED_AT,CI_PIPELINE_ID:Bt.CI_PIPELINE_ID,CI_PIPELINE_IID:Bt.CI_PIPELINE_IID,CI_PIPELINE_SOURCE:Bt.CI_PIPELINE_SOURCE,CI_PIPELINE_URL:Bt.CI_PIPELINE_URL,CI_PROJECT_CLASSIFICATION_LABEL:Bt.CI_PROJECT_CLASSIFICATION_LABEL,CI_PROJECT_DESCRIPTION:Bt.CI_PROJECT_DESCRIPTION,CI_PROJECT_ID:Bt.CI_PROJECT_ID,CI_PROJECT_NAME:Bt.CI_PROJECT_NAME,CI_PROJECT_NAMESPACE:Bt.CI_PROJECT_NAMESPACE,CI_PROJECT_NAMESPACE_ID:Bt.CI_PROJECT_NAMESPACE_ID,CI_PROJECT_PATH:Bt.CI_PROJECT_PATH,CI_PROJECT_PATH_SLUG:Bt.CI_PROJECT_PATH_SLUG,CI_PROJECT_REPOSITORY_LANGUAGES:Bt.CI_PROJECT_REPOSITORY_LANGUAGES,CI_PROJECT_ROOT_NAMESPACE:Bt.CI_PROJECT_ROOT_NAMESPACE,CI_PROJECT_TITLE:Bt.CI_PROJECT_TITLE,CI_PROJECT_URL:Bt.CI_PROJECT_URL,CI_PROJECT_VISIBILITY:Bt.CI_PROJECT_VISIBILITY,CI_REGISTRY:Bt.CI_REGISTRY,CI_REGISTRY_IMAGE:Bt.CI_REGISTRY_IMAGE,CI_REGISTRY_USER:Bt.CI_REGISTRY_USER,CI_RUNNER_DESCRIPTION:Bt.CI_RUNNER_DESCRIPTION,CI_RUNNER_ID:Bt.CI_RUNNER_ID,CI_RUNNER_TAGS:Bt.CI_RUNNER_TAGS,CI_SERVER_HOST:Bt.CI_SERVER_HOST,CI_SERVER_NAME:Bt.CI_SERVER_NAME,CI_SERVER_PORT:Bt.CI_SERVER_PORT,CI_SERVER_PROTOCOL:Bt.CI_SERVER_PROTOCOL,CI_SERVER_REVISION:Bt.CI_SERVER_REVISION,CI_SERVER_SHELL_SSH_HOST:Bt.CI_SERVER_SHELL_SSH_HOST,CI_SERVER_SHELL_SSH_PORT:Bt.CI_SERVER_SHELL_SSH_PORT,CI_SERVER_URL:Bt.CI_SERVER_URL,CI_SERVER_VERSION:Bt.CI_SERVER_VERSION,CI_SERVER_VERSION_MAJOR:Bt.CI_SERVER_VERSION_MAJOR,CI_SERVER_VERSION_MINOR:Bt.CI_SERVER_VERSION_MINOR,CI_SERVER_VERSION_PATCH:Bt.CI_SERVER_VERSION_PATCH,CI_TEMPLATE_REGISTRY_HOST:Bt.CI_TEMPLATE_REGISTRY_HOST,GITLAB_CI:Bt.GITLAB_CI,GITLAB_FEATURES:Bt.GITLAB_FEATURES,GITLAB_USER_ID:Bt.GITLAB_USER_ID,GITLAB_USER_LOGIN:Bt.GITLAB_USER_LOGIN,RUNNER_GENERATE_ARTIFACTS_METADATA:Bt.RUNNER_GENERATE_ARTIFACTS_METADATA},environment:{name:Bt.CI_RUNNER_DESCRIPTION,architecture:Bt.CI_RUNNER_EXECUTABLE_ARCH,server:Bt.CI_SERVER_URL,project:Bt.CI_PROJECT_PATH,job:{id:Bt.CI_JOB_ID},pipeline:{id:Bt.CI_PIPELINE_ID,ref:Bt.CI_CONFIG_PATH}}},metadata:{buildInvocationId:`${Bt.CI_JOB_URL}`,completeness:{parameters:!0,environment:!0,materials:!1},reproducible:!1},materials:[{uri:`git+${Bt.CI_PROJECT_URL}`,digest:{sha1:Bt.CI_COMMIT_SHA}}]}}}else throw new jt(91,"Provenance generation is only supported in GitHub Actions and GitLab CI");return Hxe.attest(Buffer.from(JSON.stringify(r)),XDt,e)};async function obt(t,e,{access:r,tag:s,registry:a,gitHead:n,provenance:c}){let f=t.manifest.name,p=t.manifest.version,h=G.stringifyIdent(f),E=Gxe.default.fromData(e,{algorithms:["sha1","sha512"]}),C=r??qxe(t,f),S=await Wxe(t),P=await yA.genPackageManifest(t),I=`${h}-${p}.tgz`,R=new URL(`${Jc(a)}/${h}/-/${I}`),N={[I]:{content_type:"application/octet-stream",data:e.toString("base64"),length:e.length}};if(c){let U={name:`pkg:npm/${h.replace(/^@/,"%40")}@${p}`,digest:{sha512:E.sha512[0].hexDigest()}},W=await jxe([U]),ee=JSON.stringify(W);N[`${h}-${p}.sigstore`]={content_type:W.mediaType,data:ee,length:ee.length}}return{_id:h,_attachments:N,name:h,access:C,"dist-tags":{[s]:p},versions:{[p]:{...P,_id:`${h}@${p}`,name:h,version:p,gitHead:n,dist:{shasum:E.sha1[0].hexDigest(),integrity:E.sha512[0].toString(),tarball:R.toString()}}},readme:S}}async function abt(t){try{let{stdout:e}=await qr.execvp("git",["rev-parse","--revs-only","HEAD"],{cwd:t});return e.trim()===""?void 0:e.trim()}catch{return}}function qxe(t,e){let r=t.project.configuration;return t.manifest.publishConfig&&typeof t.manifest.publishConfig.access=="string"?t.manifest.publishConfig.access:r.get("npmPublishAccess")!==null?r.get("npmPublishAccess"):e.scope?"restricted":"public"}async function Wxe(t){let e=fe.toPortablePath(`${t.cwd}/README.md`),r=t.manifest.name,a=`# ${G.stringifyIdent(r)} +`;try{a=await ce.readFilePromise(e,"utf8")}catch(n){if(n.code==="ENOENT")return a;throw n}return a}var RK={npmAlwaysAuth:{description:"URL of the selected npm registry (note: npm enterprise isn't supported)",type:"BOOLEAN",default:!1},npmAuthIdent:{description:"Authentication identity for the npm registry (_auth in npm and yarn v1)",type:"SECRET",default:null},npmAuthToken:{description:"Authentication token for the npm registry (_authToken in npm and yarn v1)",type:"SECRET",default:null}},Yxe={npmAuditRegistry:{description:"Registry to query for audit reports",type:"STRING",default:null},npmPublishRegistry:{description:"Registry to push packages to",type:"STRING",default:null},npmRegistryServer:{description:"URL of the selected npm registry (note: npm enterprise isn't supported)",type:"STRING",default:"https://registry.yarnpkg.com"}},lbt={npmMinimalAgeGate:{description:"Minimum age of a package version according to the publish date on the npm registry to be considered for installation",type:"DURATION",unit:"m",default:"0m"},npmPreapprovedPackages:{description:"Array of package descriptors or package name glob patterns to exclude from the minimum release age check",type:"STRING",isArray:!0,default:[]}},cbt={configuration:{...RK,...Yxe,...lbt,npmScopes:{description:"Settings per package scope",type:"MAP",valueDefinition:{description:"",type:"SHAPE",properties:{...RK,...Yxe}}},npmRegistries:{description:"Settings per registry",type:"MAP",normalizeKeys:Jc,valueDefinition:{description:"",type:"SHAPE",properties:{...RK}}}},fetchers:[VD,oh],resolvers:[JD,KD,zD]},ubt=cbt;var qK={};Vt(qK,{NpmAuditCommand:()=>D1,NpmInfoCommand:()=>b1,NpmLoginCommand:()=>P1,NpmLogoutCommand:()=>k1,NpmPublishCommand:()=>Q1,NpmTagAddCommand:()=>R1,NpmTagListCommand:()=>T1,NpmTagRemoveCommand:()=>F1,NpmWhoamiCommand:()=>N1,default:()=>wbt,npmAuditTypes:()=>zb,npmAuditUtils:()=>kL});Ge();Ge();Yt();var UK=ut(Go());Ul();var zb={};Vt(zb,{Environment:()=>Jb,Severity:()=>Kb});var Jb=(s=>(s.All="all",s.Production="production",s.Development="development",s))(Jb||{}),Kb=(n=>(n.Info="info",n.Low="low",n.Moderate="moderate",n.High="high",n.Critical="critical",n))(Kb||{});var kL={};Vt(kL,{allSeverities:()=>S1,getPackages:()=>MK,getReportTree:()=>OK,getSeverityInclusions:()=>NK,getTopLevelDependencies:()=>LK});Ge();var Vxe=ut(Ai());var S1=["info","low","moderate","high","critical"];function NK(t){if(typeof t>"u")return new Set(S1);let e=S1.indexOf(t),r=S1.slice(e);return new Set(r)}function OK(t){let e={},r={children:e};for(let[s,a]of je.sortMap(Object.entries(t),n=>n[0]))for(let n of je.sortMap(a,c=>`${c.id}`))e[`${s}/${n.id}`]={value:he.tuple(he.Type.IDENT,G.parseIdent(s)),children:{ID:typeof n.id<"u"&&{label:"ID",value:he.tuple(he.Type.ID,n.id)},Issue:{label:"Issue",value:he.tuple(he.Type.NO_HINT,n.title)},URL:typeof n.url<"u"&&{label:"URL",value:he.tuple(he.Type.URL,n.url)},Severity:{label:"Severity",value:he.tuple(he.Type.NO_HINT,n.severity)},"Vulnerable Versions":{label:"Vulnerable Versions",value:he.tuple(he.Type.RANGE,n.vulnerable_versions)},"Tree Versions":{label:"Tree Versions",children:[...n.versions].sort(Vxe.default.compare).map(c=>({value:he.tuple(he.Type.REFERENCE,c)}))},Dependents:{label:"Dependents",children:je.sortMap(n.dependents,c=>G.stringifyLocator(c)).map(c=>({value:he.tuple(he.Type.LOCATOR,c)}))}}};return r}function LK(t,e,{all:r,environment:s}){let a=[],n=r?t.workspaces:[e],c=["all","production"].includes(s),f=["all","development"].includes(s);for(let p of n)for(let h of p.anchoredPackage.dependencies.values())(p.manifest.devDependencies.has(h.identHash)?!f:!c)||a.push({workspace:p,dependency:h});return a}function MK(t,e,{recursive:r}){let s=new Map,a=new Set,n=[],c=(f,p)=>{let h=t.storedResolutions.get(p.descriptorHash);if(typeof h>"u")throw new Error("Assertion failed: The resolution should have been registered");if(!a.has(h))a.add(h);else return;let E=t.storedPackages.get(h);if(typeof E>"u")throw new Error("Assertion failed: The package should have been registered");if(G.ensureDevirtualizedLocator(E).reference.startsWith("npm:")&&E.version!==null){let S=G.stringifyIdent(E),P=je.getMapWithDefault(s,S);je.getArrayWithDefault(P,E.version).push(f)}if(r)for(let S of E.dependencies.values())n.push([E,S])};for(let{workspace:f,dependency:p}of e)n.push([f.anchoredLocator,p]);for(;n.length>0;){let[f,p]=n.shift();c(f,p)}return s}var D1=class extends ft{constructor(){super(...arguments);this.all=ge.Boolean("-A,--all",!1,{description:"Audit dependencies from all workspaces"});this.recursive=ge.Boolean("-R,--recursive",!1,{description:"Audit transitive dependencies as well"});this.environment=ge.String("--environment","all",{description:"Which environments to cover",validator:fo(Jb)});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.noDeprecations=ge.Boolean("--no-deprecations",!1,{description:"Don't warn about deprecated packages"});this.severity=ge.String("--severity","info",{description:"Minimal severity requested for packages to be displayed",validator:fo(Kb)});this.excludes=ge.Array("--exclude",[],{description:"Array of glob patterns of packages to exclude from audit"});this.ignores=ge.Array("--ignore",[],{description:"Array of glob patterns of advisory ID's to ignore in the audit report"})}static{this.paths=[["npm","audit"]]}static{this.usage=ot.Usage({description:"perform a vulnerability audit against the installed packages",details:` + This command checks for known security reports on the packages you use. The reports are by default extracted from the npm registry, and may or may not be relevant to your actual program (not all vulnerabilities affect all code paths). + + For consistency with our other commands the default is to only check the direct dependencies for the active workspace. To extend this search to all workspaces, use \`-A,--all\`. To extend this search to both direct and transitive dependencies, use \`-R,--recursive\`. + + Applying the \`--severity\` flag will limit the audit table to vulnerabilities of the corresponding severity and above. Valid values are ${S1.map(r=>`\`${r}\``).join(", ")}. + + If the \`--json\` flag is set, Yarn will print the output exactly as received from the registry. Regardless of this flag, the process will exit with a non-zero exit code if a report is found for the selected packages. + + If certain packages produce false positives for a particular environment, the \`--exclude\` flag can be used to exclude any number of packages from the audit. This can also be set in the configuration file with the \`npmAuditExcludePackages\` option. + + If particular advisories are needed to be ignored, the \`--ignore\` flag can be used with Advisory ID's to ignore any number of advisories in the audit report. This can also be set in the configuration file with the \`npmAuditIgnoreAdvisories\` option. + + To understand the dependency tree requiring vulnerable packages, check the raw report with the \`--json\` flag or use \`yarn why package\` to get more information as to who depends on them. + `,examples:[["Checks for known security issues with the installed packages. The output is a list of known issues.","yarn npm audit"],["Audit dependencies in all workspaces","yarn npm audit --all"],["Limit auditing to `dependencies` (excludes `devDependencies`)","yarn npm audit --environment production"],["Show audit report as valid JSON","yarn npm audit --json"],["Audit all direct and transitive dependencies","yarn npm audit --recursive"],["Output moderate (or more severe) vulnerabilities","yarn npm audit --severity moderate"],["Exclude certain packages","yarn npm audit --exclude package1 --exclude package2"],["Ignore specific advisories","yarn npm audit --ignore 1234567 --ignore 7654321"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Tt.find(r,this.context.cwd);if(!a)throw new ar(s.cwd,this.context.cwd);await s.restoreInstallState();let n=LK(s,a,{all:this.all,environment:this.environment}),c=MK(s,n,{recursive:this.recursive}),f=Array.from(new Set([...r.get("npmAuditExcludePackages"),...this.excludes])),p=Object.create(null);for(let[N,U]of c)f.some(W=>UK.default.isMatch(N,W))||(p[N]=[...U.keys()]);let h=hi.getAuditRegistry({configuration:r}),E,C=await lA.start({configuration:r,stdout:this.context.stdout},async()=>{let N=en.post("/-/npm/v1/security/advisories/bulk",p,{authType:en.AuthType.BEST_EFFORT,configuration:r,jsonResponse:!0,registry:h}),U=this.noDeprecations?[]:await Promise.all(Array.from(Object.entries(p),async([ee,ie])=>{let ue=await en.getPackageMetadata(G.parseIdent(ee),{project:s});return je.mapAndFilter(ie,le=>{let{deprecated:me}=ue.versions[le];return me?[ee,le,me]:je.mapAndFilter.skip})})),W=await N;for(let[ee,ie,ue]of U.flat(1))Object.hasOwn(W,ee)&&W[ee].some(le=>Fr.satisfiesWithPrereleases(ie,le.vulnerable_versions))||(W[ee]??=[],W[ee].push({id:`${ee} (deprecation)`,title:(typeof ue=="string"?ue:"").trim()||"This package has been deprecated.",severity:"moderate",vulnerable_versions:ie}));E=W});if(C.hasErrors())return C.exitCode();let S=NK(this.severity),P=Array.from(new Set([...r.get("npmAuditIgnoreAdvisories"),...this.ignores])),I=Object.create(null);for(let[N,U]of Object.entries(E)){let W=U.filter(ee=>!UK.default.isMatch(`${ee.id}`,P)&&S.has(ee.severity));W.length>0&&(I[N]=W.map(ee=>{let ie=c.get(N);if(typeof ie>"u")throw new Error("Assertion failed: Expected the registry to only return packages that were requested");let ue=[...ie.keys()].filter(me=>Fr.satisfiesWithPrereleases(me,ee.vulnerable_versions)),le=new Map;for(let me of ue)for(let pe of ie.get(me))le.set(pe.locatorHash,pe);return{...ee,versions:ue,dependents:[...le.values()]}}))}let R=Object.keys(I).length>0;return R?(xs.emitTree(OK(I),{configuration:r,json:this.json,stdout:this.context.stdout,separators:2}),1):(await Ot.start({configuration:r,includeFooter:!1,json:this.json,stdout:this.context.stdout},async N=>{N.reportInfo(1,"No audit suggestions")}),R?1:0)}};Ge();Ge();Dt();Yt();var _K=ut(Ai()),HK=Ie("util"),b1=class extends ft{constructor(){super(...arguments);this.fields=ge.String("-f,--fields",{description:"A comma-separated list of manifest fields that should be displayed"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.packages=ge.Rest()}static{this.paths=[["npm","info"]]}static{this.usage=ot.Usage({category:"Npm-related commands",description:"show information about a package",details:"\n This command fetches information about a package from the npm registry and prints it in a tree format.\n\n The package does not have to be installed locally, but needs to have been published (in particular, local changes will be ignored even for workspaces).\n\n Append `@` to the package argument to provide information specific to the latest version that satisfies the range or to the corresponding tagged version. If the range is invalid or if there is no version satisfying the range, the command will print a warning and fall back to the latest version.\n\n If the `-f,--fields` option is set, it's a comma-separated list of fields which will be used to only display part of the package information.\n\n By default, this command won't return the `dist`, `readme`, and `users` fields, since they are often very long. To explicitly request those fields, explicitly list them with the `--fields` flag or request the output in JSON mode.\n ",examples:[["Show all available information about react (except the `dist`, `readme`, and `users` fields)","yarn npm info react"],["Show all available information about react as valid JSON (including the `dist`, `readme`, and `users` fields)","yarn npm info react --json"],["Show all available information about react@16.12.0","yarn npm info react@16.12.0"],["Show all available information about react@next","yarn npm info react@next"],["Show the description of react","yarn npm info react --fields description"],["Show all available versions of react","yarn npm info react --fields versions"],["Show the readme of react","yarn npm info react --fields readme"],["Show a few fields of react","yarn npm info react --fields homepage,repository"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s}=await Tt.find(r,this.context.cwd),a=typeof this.fields<"u"?new Set(["name",...this.fields.split(/\s*,\s*/)]):null,n=[],c=!1,f=await Ot.start({configuration:r,includeFooter:!1,json:this.json,stdout:this.context.stdout},async p=>{for(let h of this.packages){let E;if(h==="."){let ie=s.topLevelWorkspace;if(!ie.manifest.name)throw new nt(`Missing ${he.pretty(r,"name",he.Type.CODE)} field in ${fe.fromPortablePath(J.join(ie.cwd,Er.manifest))}`);E=G.makeDescriptor(ie.manifest.name,"unknown")}else E=G.parseDescriptor(h);let C=en.getIdentUrl(E),S=jK(await en.get(C,{configuration:r,ident:E,jsonResponse:!0,customErrorMessage:en.customPackageError})),P=Object.keys(S.versions).sort(_K.default.compareLoose),R=S["dist-tags"].latest||P[P.length-1],N=Fr.validRange(E.range);if(N){let ie=_K.default.maxSatisfying(P,N);ie!==null?R=ie:(p.reportWarning(0,`Unmet range ${G.prettyRange(r,E.range)}; falling back to the latest version`),c=!0)}else Object.hasOwn(S["dist-tags"],E.range)?R=S["dist-tags"][E.range]:E.range!=="unknown"&&(p.reportWarning(0,`Unknown tag ${G.prettyRange(r,E.range)}; falling back to the latest version`),c=!0);let U=S.versions[R],W={...S,...U,version:R,versions:P},ee;if(a!==null){ee={};for(let ie of a){let ue=W[ie];if(typeof ue<"u")ee[ie]=ue;else{p.reportWarning(1,`The ${he.pretty(r,ie,he.Type.CODE)} field doesn't exist inside ${G.prettyIdent(r,E)}'s information`),c=!0;continue}}}else this.json||(delete W.dist,delete W.readme,delete W.users),ee=W;p.reportJson(ee),this.json||n.push(ee)}});HK.inspect.styles.name="cyan";for(let p of n)(p!==n[0]||c)&&this.context.stdout.write(` +`),this.context.stdout.write(`${(0,HK.inspect)(p,{depth:1/0,colors:!0,compact:!1})} +`);return f.exitCode()}};function jK(t){if(Array.isArray(t)){let e=[];for(let r of t)r=jK(r),r&&e.push(r);return e}else if(typeof t=="object"&&t!==null){let e={};for(let r of Object.keys(t)){if(r.startsWith("_"))continue;let s=jK(t[r]);s&&(e[r]=s)}return e}else return t||null}Ge();Ge();Yt();var GK=ut(Vv()),P1=class extends ft{constructor(){super(...arguments);this.scope=ge.String("-s,--scope",{description:"Login to the registry configured for a given scope"});this.publish=ge.Boolean("--publish",!1,{description:"Login to the publish registry"});this.alwaysAuth=ge.Boolean("--always-auth",{description:"Set the npmAlwaysAuth configuration"});this.webLogin=ge.Boolean("--web-login",{description:"Enable web login"})}static{this.paths=[["npm","login"]]}static{this.usage=ot.Usage({category:"Npm-related commands",description:"store new login info to access the npm registry",details:"\n This command will ask you for your username, password, and 2FA One-Time-Password (when it applies). It will then modify your local configuration (in your home folder, never in the project itself) to reference the new tokens thus generated.\n\n Adding the `-s,--scope` flag will cause the authentication to be done against whatever registry is configured for the associated scope (see also `npmScopes`).\n\n Adding the `--publish` flag will cause the authentication to be done against the registry used when publishing the package (see also `publishConfig.registry` and `npmPublishRegistry`).\n ",examples:[["Login to the default registry","yarn npm login"],["Login to the registry linked to the @my-scope registry","yarn npm login --scope my-scope"],["Login to the publish registry for the current package","yarn npm login --publish"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),s=await QL({configuration:r,cwd:this.context.cwd,publish:this.publish,scope:this.scope});return(await Ot.start({configuration:r,stdout:this.context.stdout,includeFooter:!1},async n=>{let c=await gbt({registry:s,configuration:r,report:n,webLogin:this.webLogin,stdin:this.context.stdin,stdout:this.context.stdout});return await mbt(s,c,{alwaysAuth:this.alwaysAuth,scope:this.scope}),n.reportInfo(0,"Successfully logged in")})).exitCode()}};async function QL({scope:t,publish:e,configuration:r,cwd:s}){return t&&e?hi.getScopeRegistry(t,{configuration:r,type:hi.RegistryType.PUBLISH_REGISTRY}):t?hi.getScopeRegistry(t,{configuration:r}):e?hi.getPublishRegistry((await eC(r,s)).manifest,{configuration:r}):hi.getDefaultRegistry({configuration:r})}async function fbt(t,e){let r;try{r=await en.post("/-/v1/login",null,{configuration:e,registry:t,authType:en.AuthType.NO_AUTH,jsonResponse:!0,headers:{"npm-auth-type":"web"}})}catch{return null}return r}async function Abt(t,e){let r=await nn.request(t,null,{configuration:e,jsonResponse:!0});if(r.statusCode===202){let s=r.headers["retry-after"]??"1";return{type:"waiting",sleep:parseInt(s,10)}}return r.statusCode===200?{type:"success",token:r.body.token}:null}async function pbt({registry:t,configuration:e,report:r}){let s=await fbt(t,e);if(!s)return null;if(Ui.openUrl){r.reportInfo(0,"Starting the web login process..."),r.reportSeparator();let{openNow:a}=await(0,GK.prompt)({type:"confirm",name:"openNow",message:"Do you want to try to open your browser now?",required:!0,initial:!0,onCancel:()=>process.exit(130)});r.reportSeparator(),(!a||!await Ui.openUrl(s.loginUrl))&&(r.reportWarning(0,"We failed to automatically open the url; you'll have to open it yourself in your browser of choice:"),r.reportWarning(0,he.pretty(e,s.loginUrl,he.Type.URL)),r.reportSeparator())}for(;;){let a=await Abt(s.doneUrl,e);if(a===null)return null;if(a.type==="waiting")await new Promise(n=>setTimeout(n,a.sleep*1e3));else return a.token}}var hbt=["https://registry.yarnpkg.com","https://registry.npmjs.org"];async function gbt(t){if(t.webLogin??hbt.includes(t.registry)){let e=await pbt(t);if(e!==null)return e}return await dbt(t)}async function dbt({registry:t,configuration:e,report:r,stdin:s,stdout:a}){let n=await ybt({configuration:e,registry:t,report:r,stdin:s,stdout:a}),c=`/-/user/org.couchdb.user:${encodeURIComponent(n.name)}`,f={_id:`org.couchdb.user:${n.name}`,name:n.name,password:n.password,type:"user",roles:[],date:new Date().toISOString()},p={attemptedAs:n.name,configuration:e,registry:t,jsonResponse:!0,authType:en.AuthType.NO_AUTH};try{return(await en.put(c,f,p)).token}catch(P){if(!(P.originalError?.name==="HTTPError"&&P.originalError?.response.statusCode===409))throw P}let h={...p,authType:en.AuthType.NO_AUTH,headers:{authorization:`Basic ${Buffer.from(`${n.name}:${n.password}`).toString("base64")}`}},E=await en.get(c,h);for(let[P,I]of Object.entries(E))(!f[P]||P==="roles")&&(f[P]=I);let C=`${c}/-rev/${f._rev}`;return(await en.put(C,f,h)).token}async function mbt(t,e,{alwaysAuth:r,scope:s}){let a=c=>f=>{let p=je.isIndexableObject(f)?f:{},h=p[c],E=je.isIndexableObject(h)?h:{};return{...p,[c]:{...E,...r!==void 0?{npmAlwaysAuth:r}:{},npmAuthToken:e}}},n=s?{npmScopes:a(s)}:{npmRegistries:a(t)};return await ze.updateHomeConfiguration(n)}async function ybt({configuration:t,registry:e,report:r,stdin:s,stdout:a}){r.reportInfo(0,`Logging in to ${he.pretty(t,e,he.Type.URL)}`);let n=!1;if(e.match(/^https:\/\/npm\.pkg\.github\.com(\/|$)/)&&(r.reportInfo(0,"You seem to be using the GitHub Package Registry. Tokens must be generated with the 'repo', 'write:packages', and 'read:packages' permissions."),n=!0),r.reportSeparator(),t.env.YARN_IS_TEST_ENV)return{name:t.env.YARN_INJECT_NPM_USER||"",password:t.env.YARN_INJECT_NPM_PASSWORD||""};let c=await(0,GK.prompt)([{type:"input",name:"name",message:"Username:",required:!0,onCancel:()=>process.exit(130),stdin:s,stdout:a},{type:"password",name:"password",message:n?"Token:":"Password:",required:!0,onCancel:()=>process.exit(130),stdin:s,stdout:a}]);return r.reportSeparator(),c}Ge();Ge();Yt();var x1=new Set(["npmAuthIdent","npmAuthToken"]),k1=class extends ft{constructor(){super(...arguments);this.scope=ge.String("-s,--scope",{description:"Logout of the registry configured for a given scope"});this.publish=ge.Boolean("--publish",!1,{description:"Logout of the publish registry"});this.all=ge.Boolean("-A,--all",!1,{description:"Logout of all registries"})}static{this.paths=[["npm","logout"]]}static{this.usage=ot.Usage({category:"Npm-related commands",description:"logout of the npm registry",details:"\n This command will log you out by modifying your local configuration (in your home folder, never in the project itself) to delete all credentials linked to a registry.\n\n Adding the `-s,--scope` flag will cause the deletion to be done against whatever registry is configured for the associated scope (see also `npmScopes`).\n\n Adding the `--publish` flag will cause the deletion to be done against the registry used when publishing the package (see also `publishConfig.registry` and `npmPublishRegistry`).\n\n Adding the `-A,--all` flag will cause the deletion to be done against all registries and scopes.\n ",examples:[["Logout of the default registry","yarn npm logout"],["Logout of the @my-scope scope","yarn npm logout --scope my-scope"],["Logout of the publish registry for the current package","yarn npm logout --publish"],["Logout of all registries","yarn npm logout --all"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),s=async()=>{let n=await QL({configuration:r,cwd:this.context.cwd,publish:this.publish,scope:this.scope}),c=await ze.find(this.context.cwd,this.context.plugins),f=G.makeIdent(this.scope??null,"pkg");return!hi.getAuthConfiguration(n,{configuration:c,ident:f}).get("npmAuthToken")};return(await Ot.start({configuration:r,stdout:this.context.stdout},async n=>{if(this.all&&(await Ibt(),n.reportInfo(0,"Successfully logged out from everything")),this.scope){await Jxe("npmScopes",this.scope),await s()?n.reportInfo(0,`Successfully logged out from ${this.scope}`):n.reportWarning(0,"Scope authentication settings removed, but some other ones settings still apply to it");return}let c=await QL({configuration:r,cwd:this.context.cwd,publish:this.publish});await Jxe("npmRegistries",c),await s()?n.reportInfo(0,`Successfully logged out from ${c}`):n.reportWarning(0,"Registry authentication settings removed, but some other ones settings still apply to it")})).exitCode()}};function Ebt(t,e){let r=t[e];if(!je.isIndexableObject(r))return!1;let s=new Set(Object.keys(r));if([...x1].every(n=>!s.has(n)))return!1;for(let n of x1)s.delete(n);if(s.size===0)return t[e]=void 0,!0;let a={...r};for(let n of x1)delete a[n];return t[e]=a,!0}async function Ibt(){let t=e=>{let r=!1,s=je.isIndexableObject(e)?{...e}:{};s.npmAuthToken&&(delete s.npmAuthToken,r=!0);for(let a of Object.keys(s))Ebt(s,a)&&(r=!0);if(Object.keys(s).length!==0)return r?s:e};return await ze.updateHomeConfiguration({npmRegistries:t,npmScopes:t})}async function Jxe(t,e){return await ze.updateHomeConfiguration({[t]:r=>{let s=je.isIndexableObject(r)?r:{};if(!Object.hasOwn(s,e))return r;let a=s[e],n=je.isIndexableObject(a)?a:{},c=new Set(Object.keys(n));if([...x1].every(p=>!c.has(p)))return r;for(let p of x1)c.delete(p);if(c.size===0)return Object.keys(s).length===1?void 0:{...s,[e]:void 0};let f={};for(let p of x1)f[p]=void 0;return{...s,[e]:{...n,...f}}}})}Ge();Dt();Yt();var Q1=class extends ft{constructor(){super(...arguments);this.access=ge.String("--access",{description:"The access for the published package (public or restricted)"});this.tag=ge.String("--tag","latest",{description:"The tag on the registry that the package should be attached to"});this.tolerateRepublish=ge.Boolean("--tolerate-republish",!1,{description:"Warn and exit when republishing an already existing version of a package"});this.otp=ge.String("--otp",{description:"The OTP token to use with the command"});this.provenance=ge.Boolean("--provenance",!1,{description:"Generate provenance for the package. Only available in GitHub Actions and GitLab CI. Can be set globally through the `npmPublishProvenance` setting or the `YARN_NPM_CONFIG_PROVENANCE` environment variable, or per-package through the `publishConfig.provenance` field in package.json."});this.dryRun=ge.Boolean("-n,--dry-run",!1,{description:"Show what would be published without actually publishing"});this.json=ge.Boolean("--json",!1,{description:"Output the result in JSON format"})}static{this.paths=[["npm","publish"]]}static{this.usage=ot.Usage({category:"Npm-related commands",description:"publish the active workspace to the npm registry",details:'\n This command will pack the active workspace into a fresh archive and upload it to the npm registry.\n\n The package will by default be attached to the `latest` tag on the registry, but this behavior can be overridden by using the `--tag` option.\n\n Note that for legacy reasons scoped packages are by default published with an access set to `restricted` (aka "private packages"). This requires you to register for a paid npm plan. In case you simply wish to publish a public scoped package to the registry (for free), just add the `--access public` flag. This behavior can be enabled by default through the `npmPublishAccess` settings.\n ',examples:[["Publish the active workspace","yarn npm publish"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Tt.find(r,this.context.cwd);if(!a)throw new ar(s.cwd,this.context.cwd);if(a.manifest.private)throw new nt("Private workspaces cannot be published");if(a.manifest.name===null||a.manifest.version===null)throw new nt("Workspaces must have valid names and versions to be published on an external registry");await s.restoreInstallState();let n=a.manifest.name,c=a.manifest.version,f=hi.getPublishRegistry(a.manifest,{configuration:r});return(await Ot.start({configuration:r,stdout:this.context.stdout,json:this.json},async h=>{if(this.tolerateRepublish)try{let E=await en.get(en.getIdentUrl(n),{configuration:r,registry:f,ident:n,jsonResponse:!0});if(!Object.hasOwn(E,"versions"))throw new jt(15,'Registry returned invalid data for - missing "versions" field');if(Object.hasOwn(E.versions,c)){let C=`Registry already knows about version ${c}; skipping.`;h.reportWarning(0,C),h.reportJson({name:G.stringifyIdent(n),version:c,registry:f,warning:C,skipped:!0});return}}catch(E){if(E.originalError?.response?.statusCode!==404)throw E}await In.maybeExecuteWorkspaceLifecycleScript(a,"prepublish",{report:h}),await yA.prepareForPack(a,{report:h},async()=>{let E=await yA.genPackList(a);for(let W of E)h.reportInfo(null,fe.fromPortablePath(W)),h.reportJson({file:fe.fromPortablePath(W)});let C=await yA.genPackStream(a,E),S=await je.bufferStream(C),P=await v1.getGitHead(a.cwd),I=!1,R="";a.manifest.publishConfig&&"provenance"in a.manifest.publishConfig?(I=!!a.manifest.publishConfig.provenance,R=I?"Generating provenance statement because `publishConfig.provenance` field is set.":"Skipping provenance statement because `publishConfig.provenance` field is set to false."):this.provenance?(I=!0,R="Generating provenance statement because `--provenance` flag is set."):r.get("npmPublishProvenance")&&(I=!0,R="Generating provenance statement because `npmPublishProvenance` setting is set."),R&&(h.reportInfo(null,R),h.reportJson({type:"provenance",enabled:I,provenanceMessage:R}));let N=await v1.makePublishBody(a,S,{access:this.access,tag:this.tag,registry:f,gitHead:P,provenance:I});this.dryRun||await en.put(en.getIdentUrl(n),N,{configuration:r,registry:f,ident:n,otp:this.otp,jsonResponse:!0,allowOidc:!!(process.env.CI&&(process.env.GITHUB_ACTIONS||process.env.GITLAB_CI))});let U=this.dryRun?`[DRY RUN] Package would be published to ${f} with tag ${this.tag}`:"Package archive published";h.reportInfo(0,U),h.reportJson({name:G.stringifyIdent(n),version:c,registry:f,tag:this.tag||"latest",files:E.map(W=>fe.fromPortablePath(W)),access:this.access||null,dryRun:this.dryRun,published:!this.dryRun,message:U,provenance:!!I})})})).exitCode()}};Ge();Yt();var Kxe=ut(Ai());Ge();Dt();Yt();var T1=class extends ft{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.package=ge.String({required:!1})}static{this.paths=[["npm","tag","list"]]}static{this.usage=ot.Usage({category:"Npm-related commands",description:"list all dist-tags of a package",details:` + This command will list all tags of a package from the npm registry. + + If the package is not specified, Yarn will default to the current workspace. + `,examples:[["List all tags of package `my-pkg`","yarn npm tag list my-pkg"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Tt.find(r,this.context.cwd),n;if(typeof this.package<"u")n=G.parseIdent(this.package);else{if(!a)throw new ar(s.cwd,this.context.cwd);if(!a.manifest.name)throw new nt(`Missing 'name' field in ${fe.fromPortablePath(J.join(a.cwd,Er.manifest))}`);n=a.manifest.name}let c=await Xb(n,r),p={children:je.sortMap(Object.entries(c),([h])=>h).map(([h,E])=>({value:he.tuple(he.Type.RESOLUTION,{descriptor:G.makeDescriptor(n,h),locator:G.makeLocator(n,E)})}))};return xs.emitTree(p,{configuration:r,json:this.json,stdout:this.context.stdout})}};async function Xb(t,e){let r=`/-/package${en.getIdentUrl(t)}/dist-tags`;return en.get(r,{configuration:e,ident:t,jsonResponse:!0,customErrorMessage:en.customPackageError})}var R1=class extends ft{constructor(){super(...arguments);this.package=ge.String();this.tag=ge.String()}static{this.paths=[["npm","tag","add"]]}static{this.usage=ot.Usage({category:"Npm-related commands",description:"add a tag for a specific version of a package",details:` + This command will add a tag to the npm registry for a specific version of a package. If the tag already exists, it will be overwritten. + `,examples:[["Add a `beta` tag for version `2.3.4-beta.4` of package `my-pkg`","yarn npm tag add my-pkg@2.3.4-beta.4 beta"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Tt.find(r,this.context.cwd);if(!a)throw new ar(s.cwd,this.context.cwd);let n=G.parseDescriptor(this.package,!0),c=n.range;if(!Kxe.default.valid(c))throw new nt(`The range ${he.pretty(r,n.range,he.Type.RANGE)} must be a valid semver version`);let f=hi.getPublishRegistry(a.manifest,{configuration:r}),p=he.pretty(r,n,he.Type.IDENT),h=he.pretty(r,c,he.Type.RANGE),E=he.pretty(r,this.tag,he.Type.CODE);return(await Ot.start({configuration:r,stdout:this.context.stdout},async S=>{let P=await Xb(n,r);Object.hasOwn(P,this.tag)&&P[this.tag]===c&&S.reportWarning(0,`Tag ${E} is already set to version ${h}`);let I=`/-/package${en.getIdentUrl(n)}/dist-tags/${encodeURIComponent(this.tag)}`;await en.put(I,c,{configuration:r,registry:f,ident:n,jsonRequest:!0,jsonResponse:!0}),S.reportInfo(0,`Tag ${E} added to version ${h} of package ${p}`)})).exitCode()}};Ge();Yt();var F1=class extends ft{constructor(){super(...arguments);this.package=ge.String();this.tag=ge.String()}static{this.paths=[["npm","tag","remove"]]}static{this.usage=ot.Usage({category:"Npm-related commands",description:"remove a tag from a package",details:` + This command will remove a tag from a package from the npm registry. + `,examples:[["Remove the `beta` tag from package `my-pkg`","yarn npm tag remove my-pkg beta"]]})}async execute(){if(this.tag==="latest")throw new nt("The 'latest' tag cannot be removed.");let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Tt.find(r,this.context.cwd);if(!a)throw new ar(s.cwd,this.context.cwd);let n=G.parseIdent(this.package),c=hi.getPublishRegistry(a.manifest,{configuration:r}),f=he.pretty(r,this.tag,he.Type.CODE),p=he.pretty(r,n,he.Type.IDENT),h=await Xb(n,r);if(!Object.hasOwn(h,this.tag))throw new nt(`${f} is not a tag of package ${p}`);return(await Ot.start({configuration:r,stdout:this.context.stdout},async C=>{let S=`/-/package${en.getIdentUrl(n)}/dist-tags/${encodeURIComponent(this.tag)}`;await en.del(S,{configuration:r,registry:c,ident:n,jsonResponse:!0}),C.reportInfo(0,`Tag ${f} removed from package ${p}`)})).exitCode()}};Ge();Ge();Yt();var N1=class extends ft{constructor(){super(...arguments);this.scope=ge.String("-s,--scope",{description:"Print username for the registry configured for a given scope"});this.publish=ge.Boolean("--publish",!1,{description:"Print username for the publish registry"})}static{this.paths=[["npm","whoami"]]}static{this.usage=ot.Usage({category:"Npm-related commands",description:"display the name of the authenticated user",details:"\n Print the username associated with the current authentication settings to the standard output.\n\n When using `-s,--scope`, the username printed will be the one that matches the authentication settings of the registry associated with the given scope (those settings can be overriden using the `npmRegistries` map, and the registry associated with the scope is configured via the `npmScopes` map).\n\n When using `--publish`, the registry we'll select will by default be the one used when publishing packages (`publishConfig.registry` or `npmPublishRegistry` if available, otherwise we'll fallback to the regular `npmRegistryServer`).\n ",examples:[["Print username for the default registry","yarn npm whoami"],["Print username for the registry on a given scope","yarn npm whoami --scope company"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),s;return this.scope&&this.publish?s=hi.getScopeRegistry(this.scope,{configuration:r,type:hi.RegistryType.PUBLISH_REGISTRY}):this.scope?s=hi.getScopeRegistry(this.scope,{configuration:r}):this.publish?s=hi.getPublishRegistry((await eC(r,this.context.cwd)).manifest,{configuration:r}):s=hi.getDefaultRegistry({configuration:r}),(await Ot.start({configuration:r,stdout:this.context.stdout},async n=>{let c;try{c=await en.get("/-/whoami",{configuration:r,registry:s,authType:en.AuthType.ALWAYS_AUTH,jsonResponse:!0,ident:this.scope?G.makeIdent(this.scope,""):void 0})}catch(f){if(f.response?.statusCode===401||f.response?.statusCode===403){n.reportError(41,"Authentication failed - your credentials may have expired");return}else throw f}n.reportInfo(0,c.username)})).exitCode()}};var Cbt={configuration:{npmPublishAccess:{description:"Default access of the published packages",type:"STRING",default:null},npmPublishProvenance:{description:"Whether to generate provenance for the published packages",type:"BOOLEAN",default:!1},npmAuditExcludePackages:{description:"Array of glob patterns of packages to exclude from npm audit",type:"STRING",default:[],isArray:!0},npmAuditIgnoreAdvisories:{description:"Array of glob patterns of advisory IDs to exclude from npm audit",type:"STRING",default:[],isArray:!0}},commands:[D1,b1,P1,k1,Q1,R1,T1,F1,N1]},wbt=Cbt;var XK={};Vt(XK,{PatchCommand:()=>H1,PatchCommitCommand:()=>_1,PatchFetcher:()=>rP,PatchResolver:()=>nP,default:()=>_bt,patchUtils:()=>gy});Ge();Ge();Dt();eA();var gy={};Vt(gy,{applyPatchFile:()=>RL,diffFolders:()=>KK,ensureUnpatchedDescriptor:()=>WK,ensureUnpatchedLocator:()=>NL,extractPackageToDisk:()=>JK,extractPatchFlags:()=>rke,isParentRequired:()=>VK,isPatchDescriptor:()=>FL,isPatchLocator:()=>Rg,loadPatchFiles:()=>tP,makeDescriptor:()=>OL,makeLocator:()=>YK,makePatchHash:()=>zK,parseDescriptor:()=>$b,parseLocator:()=>eP,parsePatchFile:()=>Zb,unpatchDescriptor:()=>Lbt,unpatchLocator:()=>Mbt});Ge();Dt();Ge();Dt();var Bbt=/^@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@.*/;function O1(t){return J.relative(vt.root,J.resolve(vt.root,fe.toPortablePath(t)))}function vbt(t){let e=t.trim().match(Bbt);if(!e)throw new Error(`Bad header line: '${t}'`);return{original:{start:Math.max(Number(e[1]),1),length:Number(e[3]||1)},patched:{start:Math.max(Number(e[4]),1),length:Number(e[6]||1)}}}var Sbt=420,Dbt=493;var zxe=()=>({semverExclusivity:null,diffLineFromPath:null,diffLineToPath:null,oldMode:null,newMode:null,deletedFileMode:null,newFileMode:null,renameFrom:null,renameTo:null,beforeHash:null,afterHash:null,fromPath:null,toPath:null,hunks:null}),bbt=t=>({header:vbt(t),parts:[]}),Pbt={"@":"header","-":"deletion","+":"insertion"," ":"context","\\":"pragma",undefined:"context"};function xbt(t){let e=[],r=zxe(),s="parsing header",a=null,n=null;function c(){a&&(n&&(a.parts.push(n),n=null),r.hunks.push(a),a=null)}function f(){c(),e.push(r),r=zxe()}for(let p=0;p0?"patch":"mode change",W=null;switch(U){case"rename":{if(!E||!C)throw new Error("Bad parser state: rename from & to not given");e.push({type:"rename",semverExclusivity:s,fromPath:O1(E),toPath:O1(C)}),W=C}break;case"file deletion":{let ee=a||I;if(!ee)throw new Error("Bad parse state: no path given for file deletion");e.push({type:"file deletion",semverExclusivity:s,hunk:N&&N[0]||null,path:O1(ee),mode:TL(p),hash:S})}break;case"file creation":{let ee=n||R;if(!ee)throw new Error("Bad parse state: no path given for file creation");e.push({type:"file creation",semverExclusivity:s,hunk:N&&N[0]||null,path:O1(ee),mode:TL(h),hash:P})}break;case"patch":case"mode change":W=R||n;break;default:je.assertNever(U);break}W&&c&&f&&c!==f&&e.push({type:"mode change",semverExclusivity:s,path:O1(W),oldMode:TL(c),newMode:TL(f)}),W&&N&&N.length&&e.push({type:"patch",semverExclusivity:s,path:O1(W),hunks:N,beforeHash:S,afterHash:P})}if(e.length===0)throw new Error("Unable to parse patch file: No changes found. Make sure the patch is a valid UTF8 encoded string");return e}function TL(t){let e=parseInt(t,8)&511;if(e!==Sbt&&e!==Dbt)throw new Error(`Unexpected file mode string: ${t}`);return e}function Zb(t){let e=t.split(/\n/g);return e[e.length-1]===""&&e.pop(),kbt(xbt(e))}function Qbt(t){let e=0,r=0;for(let{type:s,lines:a}of t.parts)switch(s){case"context":r+=a.length,e+=a.length;break;case"deletion":e+=a.length;break;case"insertion":r+=a.length;break;default:je.assertNever(s);break}if(e!==t.header.original.length||r!==t.header.patched.length){let s=a=>a<0?a:`+${a}`;throw new Error(`hunk header integrity check failed (expected @@ ${s(t.header.original.length)} ${s(t.header.patched.length)} @@, got @@ ${s(e)} ${s(r)} @@)`)}}Ge();Dt();var L1=class extends Error{constructor(r,s){super(`Cannot apply hunk #${r+1}`);this.hunk=s}};async function M1(t,e,r){let s=await t.lstatPromise(e),a=await r();typeof a<"u"&&(e=a),await t.lutimesPromise(e,s.atime,s.mtime)}async function RL(t,{baseFs:e=new Yn,dryRun:r=!1,version:s=null}={}){for(let a of t)if(!(a.semverExclusivity!==null&&s!==null&&!Fr.satisfiesWithPrereleases(s,a.semverExclusivity)))switch(a.type){case"file deletion":if(r){if(!e.existsSync(a.path))throw new Error(`Trying to delete a file that doesn't exist: ${a.path}`)}else await M1(e,J.dirname(a.path),async()=>{await e.unlinkPromise(a.path)});break;case"rename":if(r){if(!e.existsSync(a.fromPath))throw new Error(`Trying to move a file that doesn't exist: ${a.fromPath}`)}else await M1(e,J.dirname(a.fromPath),async()=>{await M1(e,J.dirname(a.toPath),async()=>{await M1(e,a.fromPath,async()=>(await e.movePromise(a.fromPath,a.toPath),a.toPath))})});break;case"file creation":if(r){if(e.existsSync(a.path))throw new Error(`Trying to create a file that already exists: ${a.path}`)}else{let n=a.hunk?a.hunk.parts[0].lines.join(` +`)+(a.hunk.parts[0].noNewlineAtEndOfFile?"":` +`):"";await e.mkdirpPromise(J.dirname(a.path),{chmod:493,utimes:[fi.SAFE_TIME,fi.SAFE_TIME]}),await e.writeFilePromise(a.path,n,{mode:a.mode}),await e.utimesPromise(a.path,fi.SAFE_TIME,fi.SAFE_TIME)}break;case"patch":await M1(e,a.path,async()=>{await Fbt(a,{baseFs:e,dryRun:r})});break;case"mode change":{let c=(await e.statPromise(a.path)).mode;if(Xxe(a.newMode)!==Xxe(c))continue;await M1(e,a.path,async()=>{await e.chmodPromise(a.path,a.newMode)})}break;default:je.assertNever(a);break}}function Xxe(t){return(t&64)>0}function Zxe(t){return t.replace(/\s+$/,"")}function Rbt(t,e){return Zxe(t)===Zxe(e)}async function Fbt({hunks:t,path:e},{baseFs:r,dryRun:s=!1}){let a=await r.statSync(e).mode,c=(await r.readFileSync(e,"utf8")).split(/\n/),f=[],p=0,h=0;for(let C of t){let S=Math.max(h,C.header.patched.start+p),P=Math.max(0,S-h),I=Math.max(0,c.length-S-C.header.original.length),R=Math.max(P,I),N=0,U=0,W=null;for(;N<=R;){if(N<=P&&(U=S-N,W=$xe(C,c,U),W!==null)){N=-N;break}if(N<=I&&(U=S+N,W=$xe(C,c,U),W!==null))break;N+=1}if(W===null)throw new L1(t.indexOf(C),C);f.push(W),p+=N,h=U+C.header.original.length}if(s)return;let E=0;for(let C of f)for(let S of C)switch(S.type){case"splice":{let P=S.index+E;c.splice(P,S.numToDelete,...S.linesToInsert),E+=S.linesToInsert.length-S.numToDelete}break;case"pop":c.pop();break;case"push":c.push(S.line);break;default:je.assertNever(S);break}await r.writeFilePromise(e,c.join(` +`),{mode:a})}function $xe(t,e,r){let s=[];for(let a of t.parts)switch(a.type){case"context":case"deletion":{for(let n of a.lines){let c=e[r];if(c==null||!Rbt(c,n))return null;r+=1}a.type==="deletion"&&(s.push({type:"splice",index:r-a.lines.length,numToDelete:a.lines.length,linesToInsert:[]}),a.noNewlineAtEndOfFile&&s.push({type:"push",line:""}))}break;case"insertion":s.push({type:"splice",index:r,numToDelete:0,linesToInsert:a.lines}),a.noNewlineAtEndOfFile&&s.push({type:"pop"});break;default:je.assertNever(a.type);break}return s}var Obt=/^builtin<([^>]+)>$/;function U1(t,e){let{protocol:r,source:s,selector:a,params:n}=G.parseRange(t);if(r!=="patch:")throw new Error("Invalid patch range");if(s===null)throw new Error("Patch locators must explicitly define their source");let c=a?a.split(/&/).map(E=>fe.toPortablePath(E)):[],f=n&&typeof n.locator=="string"?G.parseLocator(n.locator):null,p=n&&typeof n.version=="string"?n.version:null,h=e(s);return{parentLocator:f,sourceItem:h,patchPaths:c,sourceVersion:p}}function FL(t){return t.range.startsWith("patch:")}function Rg(t){return t.reference.startsWith("patch:")}function $b(t){let{sourceItem:e,...r}=U1(t.range,G.parseDescriptor);return{...r,sourceDescriptor:e}}function eP(t){let{sourceItem:e,...r}=U1(t.reference,G.parseLocator);return{...r,sourceLocator:e}}function Lbt(t){let{sourceItem:e}=U1(t.range,G.parseDescriptor);return e}function Mbt(t){let{sourceItem:e}=U1(t.reference,G.parseLocator);return e}function WK(t){if(!FL(t))return t;let{sourceItem:e}=U1(t.range,G.parseDescriptor);return e}function NL(t){if(!Rg(t))return t;let{sourceItem:e}=U1(t.reference,G.parseLocator);return e}function eke({parentLocator:t,sourceItem:e,patchPaths:r,sourceVersion:s,patchHash:a},n){let c=t!==null?{locator:G.stringifyLocator(t)}:{},f=typeof s<"u"?{version:s}:{},p=typeof a<"u"?{hash:a}:{};return G.makeRange({protocol:"patch:",source:n(e),selector:r.join("&"),params:{...f,...p,...c}})}function OL(t,{parentLocator:e,sourceDescriptor:r,patchPaths:s}){return G.makeDescriptor(t,eke({parentLocator:e,sourceItem:r,patchPaths:s},G.stringifyDescriptor))}function YK(t,{parentLocator:e,sourcePackage:r,patchPaths:s,patchHash:a}){return G.makeLocator(t,eke({parentLocator:e,sourceItem:r,sourceVersion:r.version,patchPaths:s,patchHash:a},G.stringifyLocator))}function tke({onAbsolute:t,onRelative:e,onProject:r,onBuiltin:s},a){let n=a.lastIndexOf("!");n!==-1&&(a=a.slice(n+1));let c=a.match(Obt);return c!==null?s(c[1]):a.startsWith("~/")?r(a.slice(2)):J.isAbsolute(a)?t(a):e(a)}function rke(t){let e=t.lastIndexOf("!");return{optional:(e!==-1?new Set(t.slice(0,e).split(/!/)):new Set).has("optional")}}function VK(t){return tke({onAbsolute:()=>!1,onRelative:()=>!0,onProject:()=>!1,onBuiltin:()=>!1},t)}async function tP(t,e,r){let s=t!==null?await r.fetcher.fetch(t,r):null,a=s&&s.localPath?{packageFs:new Sn(vt.root),prefixPath:J.relative(vt.root,s.localPath)}:s;s&&s!==a&&s.releaseFs&&s.releaseFs();let n=await je.releaseAfterUseAsync(async()=>await Promise.all(e.map(async c=>{let f=rke(c),p=await tke({onAbsolute:async h=>await ce.readFilePromise(h,"utf8"),onRelative:async h=>{if(a===null)throw new Error("Assertion failed: The parent locator should have been fetched");return await a.packageFs.readFilePromise(J.join(a.prefixPath,h),"utf8")},onProject:async h=>await ce.readFilePromise(J.join(r.project.cwd,h),"utf8"),onBuiltin:async h=>await r.project.configuration.firstHook(E=>E.getBuiltinPatch,r.project,h)},c);return{...f,source:p}})));for(let c of n)typeof c.source=="string"&&(c.source=c.source.replace(/\r\n?/g,` +`));return n}async function JK(t,{cache:e,project:r}){let s=r.storedPackages.get(t.locatorHash);if(typeof s>"u")throw new Error("Assertion failed: Expected the package to be registered");let a=NL(t),n=r.storedChecksums,c=new ki,f=await ce.mktempPromise(),p=J.join(f,"source"),h=J.join(f,"user"),E=J.join(f,".yarn-patch.json"),C=r.configuration.makeFetcher(),S=[];try{let P,I;if(t.locatorHash===a.locatorHash){let R=await C.fetch(t,{cache:e,project:r,fetcher:C,checksums:n,report:c});S.push(()=>R.releaseFs?.()),P=R,I=R}else P=await C.fetch(t,{cache:e,project:r,fetcher:C,checksums:n,report:c}),S.push(()=>P.releaseFs?.()),I=await C.fetch(t,{cache:e,project:r,fetcher:C,checksums:n,report:c}),S.push(()=>I.releaseFs?.());await Promise.all([ce.copyPromise(p,P.prefixPath,{baseFs:P.packageFs}),ce.copyPromise(h,I.prefixPath,{baseFs:I.packageFs}),ce.writeJsonPromise(E,{locator:G.stringifyLocator(t),version:s.version})])}finally{for(let P of S)P()}return ce.detachTemp(f),h}async function KK(t,e){let r=fe.fromPortablePath(t).replace(/\\/g,"/"),s=fe.fromPortablePath(e).replace(/\\/g,"/"),{stdout:a,stderr:n}=await qr.execvp("git",["-c","core.safecrlf=false","diff","--src-prefix=a/","--dst-prefix=b/","--ignore-cr-at-eol","--full-index","--no-index","--no-renames","--text",r,s],{cwd:fe.toPortablePath(process.cwd()),env:{...process.env,GIT_CONFIG_NOSYSTEM:"1",HOME:"",XDG_CONFIG_HOME:"",USERPROFILE:""}});if(n.length>0)throw new Error(`Unable to diff directories. Make sure you have a recent version of 'git' available in PATH. +The following error was reported by 'git': +${n}`);let c=r.startsWith("/")?f=>f.slice(1):f=>f;return a.replace(new RegExp(`(a|b)(${je.escapeRegExp(`/${c(r)}/`)})`,"g"),"$1/").replace(new RegExp(`(a|b)${je.escapeRegExp(`/${c(s)}/`)}`,"g"),"$1/").replace(new RegExp(je.escapeRegExp(`${r}/`),"g"),"").replace(new RegExp(je.escapeRegExp(`${s}/`),"g"),"")}function zK(t,e){let r=[];for(let{source:s}of t){if(s===null)continue;let a=Zb(s);for(let n of a){let{semverExclusivity:c,...f}=n;c!==null&&e!==null&&!Fr.satisfiesWithPrereleases(e,c)||r.push(JSON.stringify(f))}}return Nn.makeHash(`${3}`,...r).slice(0,6)}Ge();function nke(t,{configuration:e,report:r}){for(let s of t.parts)for(let a of s.lines)switch(s.type){case"context":r.reportInfo(null,` ${he.pretty(e,a,"grey")}`);break;case"deletion":r.reportError(28,`- ${he.pretty(e,a,he.Type.REMOVED)}`);break;case"insertion":r.reportError(28,`+ ${he.pretty(e,a,he.Type.ADDED)}`);break;default:je.assertNever(s.type)}}var rP=class{supports(e,r){return!!Rg(e)}getLocalPath(e,r){return null}async fetch(e,r){let s=r.checksums.get(e.locatorHash)||null,[a,n,c]=await r.cache.fetchPackageFromCache(e,s,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${G.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the disk`),loader:()=>this.patchPackage(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:G.getIdentVendorPath(e),localPath:this.getLocalPath(e,r),checksum:c}}async patchPackage(e,r){let{parentLocator:s,sourceLocator:a,sourceVersion:n,patchPaths:c}=eP(e),f=await tP(s,c,r),p=await ce.mktempPromise(),h=J.join(p,"current.zip"),E=await r.fetcher.fetch(a,r),C=G.getIdentVendorPath(e),S=new As(h,{create:!0,level:r.project.configuration.get("compressionLevel")});await je.releaseAfterUseAsync(async()=>{await S.copyPromise(C,E.prefixPath,{baseFs:E.packageFs,stableSort:!0})},E.releaseFs),S.saveAndClose();for(let{source:P,optional:I}of f){if(P===null)continue;let R=new As(h,{level:r.project.configuration.get("compressionLevel")}),N=new Sn(J.resolve(vt.root,C),{baseFs:R});try{await RL(Zb(P),{baseFs:N,version:n})}catch(U){if(!(U instanceof L1))throw U;let W=r.project.configuration.get("enableInlineHunks"),ee=!W&&!I?" (set enableInlineHunks for details)":"",ie=`${G.prettyLocator(r.project.configuration,e)}: ${U.message}${ee}`,ue=le=>{W&&nke(U.hunk,{configuration:r.project.configuration,report:le})};if(R.discardAndClose(),I){r.report.reportWarningOnce(66,ie,{reportExtra:ue});continue}else throw new jt(66,ie,ue)}R.saveAndClose()}return new As(h,{level:r.project.configuration.get("compressionLevel")})}};Ge();var nP=class{supportsDescriptor(e,r){return!!FL(e)}supportsLocator(e,r){return!!Rg(e)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,s){let{patchPaths:a}=$b(e);return a.every(n=>!VK(n))?e:G.bindDescriptor(e,{locator:G.stringifyLocator(r)})}getResolutionDependencies(e,r){let{sourceDescriptor:s}=$b(e);return{sourceDescriptor:r.project.configuration.normalizeDependency(s)}}async getCandidates(e,r,s){if(!s.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let{parentLocator:a,patchPaths:n}=$b(e),c=await tP(a,n,s.fetchOptions),f=r.sourceDescriptor;if(typeof f>"u")throw new Error("Assertion failed: The dependency should have been resolved");let p=zK(c,f.version);return[YK(e,{parentLocator:a,sourcePackage:f,patchPaths:n,patchHash:p})]}async getSatisfying(e,r,s,a){let[n]=await this.getCandidates(e,r,a);return{locators:s.filter(c=>c.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){let{sourceLocator:s}=eP(e);return{...await r.resolver.resolve(s,r),...e}}};Ge();Dt();Yt();var _1=class extends ft{constructor(){super(...arguments);this.save=ge.Boolean("-s,--save",!1,{description:"Add the patch to your resolution entries"});this.patchFolder=ge.String()}static{this.paths=[["patch-commit"]]}static{this.usage=ot.Usage({description:"generate a patch out of a directory",details:"\n By default, this will print a patchfile on stdout based on the diff between the folder passed in and the original version of the package. Such file is suitable for consumption with the `patch:` protocol.\n\n With the `-s,--save` option set, the patchfile won't be printed on stdout anymore and will instead be stored within a local file (by default kept within `.yarn/patches`, but configurable via the `patchFolder` setting). A `resolutions` entry will also be added to your top-level manifest, referencing the patched package via the `patch:` protocol.\n\n Note that only folders generated by `yarn patch` are accepted as valid input for `yarn patch-commit`.\n "})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Tt.find(r,this.context.cwd);if(!a)throw new ar(s.cwd,this.context.cwd);await s.restoreInstallState();let n=J.resolve(this.context.cwd,fe.toPortablePath(this.patchFolder)),c=J.join(n,"../source"),f=J.join(n,"../.yarn-patch.json");if(!ce.existsSync(c))throw new nt("The argument folder didn't get created by 'yarn patch'");let p=await KK(c,n),h=await ce.readJsonPromise(f),E=G.parseLocator(h.locator,!0);if(!s.storedPackages.has(E.locatorHash))throw new nt("No package found in the project for the given locator");if(!this.save){this.context.stdout.write(p);return}let C=r.get("patchFolder"),S=J.join(C,`${G.slugifyLocator(E)}.patch`);await ce.mkdirPromise(C,{recursive:!0}),await ce.writeFilePromise(S,p);let P=[],I=new Map;for(let R of s.storedPackages.values()){if(G.isVirtualLocator(R))continue;let N=R.dependencies.get(E.identHash);if(!N)continue;let U=G.ensureDevirtualizedDescriptor(N),W=WK(U),ee=s.storedResolutions.get(W.descriptorHash);if(!ee)throw new Error("Assertion failed: Expected the resolution to have been registered");if(!s.storedPackages.get(ee))throw new Error("Assertion failed: Expected the package to have been registered");let ue=s.tryWorkspaceByLocator(R);if(ue)P.push(ue);else{let le=s.originalPackages.get(R.locatorHash);if(!le)throw new Error("Assertion failed: Expected the original package to have been registered");let me=le.dependencies.get(N.identHash);if(!me)throw new Error("Assertion failed: Expected the original dependency to have been registered");I.set(me.descriptorHash,me)}}for(let R of P)for(let N of Ut.hardDependencies){let U=R.manifest[N].get(E.identHash);if(!U)continue;let W=OL(U,{parentLocator:null,sourceDescriptor:G.convertLocatorToDescriptor(E),patchPaths:[J.join(Er.home,J.relative(s.cwd,S))]});R.manifest[N].set(U.identHash,W)}for(let R of I.values()){let N=OL(R,{parentLocator:null,sourceDescriptor:G.convertLocatorToDescriptor(E),patchPaths:[J.join(Er.home,J.relative(s.cwd,S))]});s.topLevelWorkspace.manifest.resolutions.push({pattern:{descriptor:{fullName:G.stringifyIdent(N),description:R.range}},reference:N.range})}await s.persist()}};Ge();Dt();Yt();var H1=class extends ft{constructor(){super(...arguments);this.update=ge.Boolean("-u,--update",!1,{description:"Reapply local patches that already apply to this packages"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.package=ge.String()}static{this.paths=[["patch"]]}static{this.usage=ot.Usage({description:"prepare a package for patching",details:"\n This command will cause a package to be extracted in a temporary directory intended to be editable at will.\n\n Once you're done with your changes, run `yarn patch-commit -s path` (with `path` being the temporary directory you received) to generate a patchfile and register it into your top-level manifest via the `patch:` protocol. Run `yarn patch-commit -h` for more details.\n\n Calling the command when you already have a patch won't import it by default (in other words, the default behavior is to reset existing patches). However, adding the `-u,--update` flag will import any current patch.\n "})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Tt.find(r,this.context.cwd),n=await Kr.find(r);if(!a)throw new ar(s.cwd,this.context.cwd);await s.restoreInstallState();let c=G.parseLocator(this.package);if(c.reference==="unknown"){let f=je.mapAndFilter([...s.storedPackages.values()],p=>p.identHash!==c.identHash?je.mapAndFilter.skip:G.isVirtualLocator(p)?je.mapAndFilter.skip:Rg(p)!==this.update?je.mapAndFilter.skip:p);if(f.length===0)throw new nt("No package found in the project for the given locator");if(f.length>1)throw new nt(`Multiple candidate packages found; explicitly choose one of them (use \`yarn why \` to get more information as to who depends on them): +${f.map(p=>` +- ${G.prettyLocator(r,p)}`).join("")}`);c=f[0]}if(!s.storedPackages.has(c.locatorHash))throw new nt("No package found in the project for the given locator");await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout},async f=>{let p=NL(c),h=await JK(c,{cache:n,project:s});f.reportJson({locator:G.stringifyLocator(p),path:fe.fromPortablePath(h)});let E=this.update?" along with its current modifications":"";f.reportInfo(0,`Package ${G.prettyLocator(r,p)} got extracted with success${E}!`),f.reportInfo(0,`You can now edit the following folder: ${he.pretty(r,fe.fromPortablePath(h),"magenta")}`),f.reportInfo(0,`Once you are done run ${he.pretty(r,`yarn patch-commit -s ${process.platform==="win32"?'"':""}${fe.fromPortablePath(h)}${process.platform==="win32"?'"':""}`,"cyan")} and Yarn will store a patchfile based on your changes.`)})}};var Ubt={configuration:{enableInlineHunks:{description:"If true, the installs will print unmatched patch hunks",type:"BOOLEAN",default:!1},patchFolder:{description:"Folder where the patch files must be written",type:"ABSOLUTE_PATH",default:"./.yarn/patches"}},commands:[_1,H1],fetchers:[rP],resolvers:[nP]},_bt=Ubt;var ez={};Vt(ez,{PnpmLinker:()=>iP,default:()=>Ybt});Ge();Dt();Yt();var iP=class{getCustomDataKey(){return JSON.stringify({name:"PnpmLinker",version:3})}supportsPackage(e,r){return this.isEnabled(r)}async findPackageLocation(e,r){if(!this.isEnabled(r))throw new Error("Assertion failed: Expected the pnpm linker to be enabled");let s=this.getCustomDataKey(),a=r.project.linkersCustomData.get(s);if(!a)throw new nt(`The project in ${he.pretty(r.project.configuration,`${r.project.cwd}/package.json`,he.Type.PATH)} doesn't seem to have been installed - running an install there might help`);let n=a.pathsByLocator.get(e.locatorHash);if(typeof n>"u")throw new nt(`Couldn't find ${G.prettyLocator(r.project.configuration,e)} in the currently installed pnpm map - running an install might help`);return n.packageLocation}async findPackageLocator(e,r){if(!this.isEnabled(r))return null;let s=this.getCustomDataKey(),a=r.project.linkersCustomData.get(s);if(!a)throw new nt(`The project in ${he.pretty(r.project.configuration,`${r.project.cwd}/package.json`,he.Type.PATH)} doesn't seem to have been installed - running an install there might help`);let n=e.match(/(^.*\/node_modules\/(@[^/]*\/)?[^/]+)(\/.*$)/);if(n){let p=a.locatorByPath.get(n[1]);if(p)return p}let c=e,f=e;do{f=c,c=J.dirname(f);let p=a.locatorByPath.get(f);if(p)return p}while(c!==f);return null}makeInstaller(e){return new ZK(e)}isEnabled(e){return e.project.configuration.get("nodeLinker")==="pnpm"}},ZK=class{constructor(e){this.opts=e;this.asyncActions=new je.AsyncActions(10);this.customData={pathsByLocator:new Map,locatorByPath:new Map};this.indexFolderPromise=$P(ce,{indexPath:J.join(e.project.configuration.get("globalFolder"),"index")})}attachCustomData(e){}async installPackage(e,r,s){switch(e.linkType){case"SOFT":return this.installPackageSoft(e,r,s);case"HARD":return this.installPackageHard(e,r,s)}throw new Error("Assertion failed: Unsupported package link type")}async installPackageSoft(e,r,s){let a=J.resolve(r.packageFs.getRealPath(),r.prefixPath),n=this.opts.project.tryWorkspaceByLocator(e)?J.join(a,Er.nodeModules):null;return this.customData.pathsByLocator.set(e.locatorHash,{packageLocation:a,dependenciesLocation:n}),{packageLocation:a,buildRequest:null}}async installPackageHard(e,r,s){let a=jbt(e,{project:this.opts.project}),n=a.packageLocation;this.customData.locatorByPath.set(n,G.stringifyLocator(e)),this.customData.pathsByLocator.set(e.locatorHash,a),s.holdFetchResult(this.asyncActions.set(e.locatorHash,async()=>{await ce.mkdirPromise(n,{recursive:!0}),await ce.copyPromise(n,r.prefixPath,{baseFs:r.packageFs,overwrite:!1,linkStrategy:{type:"HardlinkFromIndex",indexPath:await this.indexFolderPromise,autoRepair:!0}})}));let f=G.isVirtualLocator(e)?G.devirtualizeLocator(e):e,p={manifest:await Ut.tryFind(r.prefixPath,{baseFs:r.packageFs})??new Ut,misc:{hasBindingGyp:gA.hasBindingGyp(r)}},h=this.opts.project.getDependencyMeta(f,e.version),E=gA.extractBuildRequest(e,p,h,{configuration:this.opts.project.configuration});return{packageLocation:n,buildRequest:E}}async attachInternalDependencies(e,r){if(this.opts.project.configuration.get("nodeLinker")!=="pnpm"||!ike(e,{project:this.opts.project}))return;let s=this.customData.pathsByLocator.get(e.locatorHash);if(typeof s>"u")throw new Error(`Assertion failed: Expected the package to have been registered (${G.stringifyLocator(e)})`);let{dependenciesLocation:a}=s;a&&this.asyncActions.reduce(e.locatorHash,async n=>{await ce.mkdirPromise(a,{recursive:!0});let c=await Gbt(a),f=new Map(c),p=[n],h=(C,S)=>{let P=S;ike(S,{project:this.opts.project})||(this.opts.report.reportWarningOnce(0,"The pnpm linker doesn't support providing different versions to workspaces' peer dependencies"),P=G.devirtualizeLocator(S));let I=this.customData.pathsByLocator.get(P.locatorHash);if(typeof I>"u")throw new Error(`Assertion failed: Expected the package to have been registered (${G.stringifyLocator(S)})`);let R=G.stringifyIdent(C),N=J.join(a,R),U=J.relative(J.dirname(N),I.packageLocation),W=f.get(R);f.delete(R),p.push(Promise.resolve().then(async()=>{if(W){if(W.isSymbolicLink()&&await ce.readlinkPromise(N)===U)return;await ce.removePromise(N)}await ce.mkdirpPromise(J.dirname(N)),process.platform=="win32"&&this.opts.project.configuration.get("winLinkType")==="junctions"?await ce.symlinkPromise(I.packageLocation,N,"junction"):await ce.symlinkPromise(U,N)}))},E=!1;for(let[C,S]of r)C.identHash===e.identHash&&(E=!0),h(C,S);!E&&!this.opts.project.tryWorkspaceByLocator(e)&&h(G.convertLocatorToDescriptor(e),e),p.push(qbt(a,f)),await Promise.all(p)})}async attachExternalDependents(e,r){throw new Error("External dependencies haven't been implemented for the pnpm linker")}async finalizeInstall(){let e=ske(this.opts.project);if(this.opts.project.configuration.get("nodeLinker")!=="pnpm")await ce.removePromise(e);else{let r;try{r=new Set(await ce.readdirPromise(e))}catch{r=new Set}for(let{dependenciesLocation:s}of this.customData.pathsByLocator.values()){if(!s)continue;let a=J.contains(e,s);if(a===null)continue;let[n]=a.split(J.sep);r.delete(n)}await Promise.all([...r].map(async s=>{await ce.removePromise(J.join(e,s))}))}return await this.asyncActions.wait(),await $K(e),this.opts.project.configuration.get("nodeLinker")!=="node-modules"&&await $K(Hbt(this.opts.project)),{customData:this.customData}}};function Hbt(t){return J.join(t.cwd,Er.nodeModules)}function ske(t){return t.configuration.get("pnpmStoreFolder")}function jbt(t,{project:e}){let r=G.slugifyLocator(t),s=ske(e),a=J.join(s,r,"package"),n=J.join(s,r,Er.nodeModules);return{packageLocation:a,dependenciesLocation:n}}function ike(t,{project:e}){return!G.isVirtualLocator(t)||!e.tryWorkspaceByLocator(t)}async function Gbt(t){let e=new Map,r=[];try{r=await ce.readdirPromise(t,{withFileTypes:!0})}catch(s){if(s.code!=="ENOENT")throw s}try{for(let s of r)if(!s.name.startsWith("."))if(s.name.startsWith("@")){let a=await ce.readdirPromise(J.join(t,s.name),{withFileTypes:!0});if(a.length===0)e.set(s.name,s);else for(let n of a)e.set(`${s.name}/${n.name}`,n)}else e.set(s.name,s)}catch(s){if(s.code!=="ENOENT")throw s}return e}async function qbt(t,e){let r=[],s=new Set;for(let a of e.keys()){r.push(ce.removePromise(J.join(t,a)));let n=G.tryParseIdent(a)?.scope;n&&s.add(`@${n}`)}return Promise.all(r).then(()=>Promise.all([...s].map(a=>$K(J.join(t,a)))))}async function $K(t){try{await ce.rmdirPromise(t)}catch(e){if(e.code!=="ENOENT"&&e.code!=="ENOTEMPTY"&&e.code!=="EBUSY")throw e}}var Wbt={configuration:{pnpmStoreFolder:{description:"By default, the store is stored in the 'node_modules/.store' of the project. Sometimes in CI scenario's it is convenient to store this in a different location so it can be cached and reused.",type:"ABSOLUTE_PATH",default:"./node_modules/.store"}},linkers:[iP]},Ybt=Wbt;var az={};Vt(az,{StageCommand:()=>j1,default:()=>nPt,stageUtils:()=>ML});Ge();Dt();Yt();Ge();Dt();var ML={};Vt(ML,{ActionType:()=>tz,checkConsensus:()=>LL,expandDirectory:()=>iz,findConsensus:()=>sz,findVcsRoot:()=>rz,genCommitMessage:()=>oz,getCommitPrefix:()=>oke,isYarnFile:()=>nz});Dt();var tz=(n=>(n[n.CREATE=0]="CREATE",n[n.DELETE=1]="DELETE",n[n.ADD=2]="ADD",n[n.REMOVE=3]="REMOVE",n[n.MODIFY=4]="MODIFY",n))(tz||{});async function rz(t,{marker:e}){do if(!ce.existsSync(J.join(t,e)))t=J.dirname(t);else return t;while(t!=="/");return null}function nz(t,{roots:e,names:r}){if(r.has(J.basename(t)))return!0;do if(!e.has(t))t=J.dirname(t);else return!0;while(t!=="/");return!1}function iz(t){let e=[],r=[t];for(;r.length>0;){let s=r.pop(),a=ce.readdirSync(s);for(let n of a){let c=J.resolve(s,n);ce.lstatSync(c).isDirectory()?r.push(c):e.push(c)}}return e}function LL(t,e){let r=0,s=0;for(let a of t)a!=="wip"&&(e.test(a)?r+=1:s+=1);return r>=s}function sz(t){let e=LL(t,/^(\w\(\w+\):\s*)?\w+s/),r=LL(t,/^(\w\(\w+\):\s*)?[A-Z]/),s=LL(t,/^\w\(\w+\):/);return{useThirdPerson:e,useUpperCase:r,useComponent:s}}function oke(t){return t.useComponent?"chore(yarn): ":""}var Vbt=new Map([[0,"create"],[1,"delete"],[2,"add"],[3,"remove"],[4,"update"]]);function oz(t,e){let r=oke(t),s=[],a=e.slice().sort((n,c)=>n[0]-c[0]);for(;a.length>0;){let[n,c]=a.shift(),f=Vbt.get(n);t.useUpperCase&&s.length===0&&(f=`${f[0].toUpperCase()}${f.slice(1)}`),t.useThirdPerson&&(f+="s");let p=[c];for(;a.length>0&&a[0][0]===n;){let[,E]=a.shift();p.push(E)}p.sort();let h=p.shift();p.length===1?h+=" (and one other)":p.length>1&&(h+=` (and ${p.length} others)`),s.push(`${f} ${h}`)}return`${r}${s.join(", ")}`}var Jbt="Commit generated via `yarn stage`",Kbt=11;async function ake(t){let{code:e,stdout:r}=await qr.execvp("git",["log","-1","--pretty=format:%H"],{cwd:t});return e===0?r.trim():null}async function zbt(t,e){let r=[],s=e.filter(h=>J.basename(h.path)==="package.json");for(let{action:h,path:E}of s){let C=J.relative(t,E);if(h===4){let S=await ake(t),{stdout:P}=await qr.execvp("git",["show",`${S}:${C}`],{cwd:t,strict:!0}),I=await Ut.fromText(P),R=await Ut.fromFile(E),N=new Map([...R.dependencies,...R.devDependencies]),U=new Map([...I.dependencies,...I.devDependencies]);for(let[W,ee]of U){let ie=G.stringifyIdent(ee),ue=N.get(W);ue?ue.range!==ee.range&&r.push([4,`${ie} to ${ue.range}`]):r.push([3,ie])}for(let[W,ee]of N)U.has(W)||r.push([2,G.stringifyIdent(ee)])}else if(h===0){let S=await Ut.fromFile(E);S.name?r.push([0,G.stringifyIdent(S.name)]):r.push([0,"a package"])}else if(h===1){let S=await ake(t),{stdout:P}=await qr.execvp("git",["show",`${S}:${C}`],{cwd:t,strict:!0}),I=await Ut.fromText(P);I.name?r.push([1,G.stringifyIdent(I.name)]):r.push([1,"a package"])}else throw new Error("Assertion failed: Unsupported action type")}let{code:a,stdout:n}=await qr.execvp("git",["log",`-${Kbt}`,"--pretty=format:%s"],{cwd:t}),c=a===0?n.split(/\n/g).filter(h=>h!==""):[],f=sz(c);return oz(f,r)}var Xbt={0:[" A ","?? "],4:[" M "],1:[" D "]},Zbt={0:["A "],4:["M "],1:["D "]},lke={async findRoot(t){return await rz(t,{marker:".git"})},async filterChanges(t,e,r,s){let{stdout:a}=await qr.execvp("git",["status","-s"],{cwd:t,strict:!0}),n=a.toString().split(/\n/g),c=s?.staged?Zbt:Xbt;return[].concat(...n.map(p=>{if(p==="")return[];let h=p.slice(0,3),E=J.resolve(t,p.slice(3));if(!s?.staged&&h==="?? "&&p.endsWith("/"))return iz(E).map(C=>({action:0,path:C}));{let S=[0,4,1].find(P=>c[P].includes(h));return S!==void 0?[{action:S,path:E}]:[]}})).filter(p=>nz(p.path,{roots:e,names:r}))},async genCommitMessage(t,e){return await zbt(t,e)},async makeStage(t,e){let r=e.map(s=>fe.fromPortablePath(s.path));await qr.execvp("git",["add","--",...r],{cwd:t,strict:!0})},async makeCommit(t,e,r){let s=e.map(a=>fe.fromPortablePath(a.path));await qr.execvp("git",["add","-N","--",...s],{cwd:t,strict:!0}),await qr.execvp("git",["commit","-m",`${r} + +${Jbt} +`,"--",...s],{cwd:t,strict:!0})},async makeReset(t,e){let r=e.map(s=>fe.fromPortablePath(s.path));await qr.execvp("git",["reset","HEAD","--",...r],{cwd:t,strict:!0})}};var $bt=[lke],j1=class extends ft{constructor(){super(...arguments);this.commit=ge.Boolean("-c,--commit",!1,{description:"Commit the staged files"});this.reset=ge.Boolean("-r,--reset",!1,{description:"Remove all files from the staging area"});this.dryRun=ge.Boolean("-n,--dry-run",!1,{description:"Print the commit message and the list of modified files without staging / committing"});this.update=ge.Boolean("-u,--update",!1,{hidden:!0})}static{this.paths=[["stage"]]}static{this.usage=ot.Usage({description:"add all yarn files to your vcs",details:"\n This command will add to your staging area the files belonging to Yarn (typically any modified `package.json` and `.yarnrc.yml` files, but also linker-generated files, cache data, etc). It will take your ignore list into account, so the cache files won't be added if the cache is ignored in a `.gitignore` file (assuming you use Git).\n\n Running `--reset` will instead remove them from the staging area (the changes will still be there, but won't be committed until you stage them back).\n\n Since the staging area is a non-existent concept in Mercurial, Yarn will always create a new commit when running this command on Mercurial repositories. You can get this behavior when using Git by using the `--commit` flag which will directly create a commit.\n ",examples:[["Adds all modified project files to the staging area","yarn stage"],["Creates a new commit containing all modified project files","yarn stage --commit"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s}=await Tt.find(r,this.context.cwd),{driver:a,root:n}=await ePt(s.cwd),c=[r.get("cacheFolder"),r.get("globalFolder"),r.get("virtualFolder"),r.get("yarnPath")];await r.triggerHook(C=>C.populateYarnPaths,s,C=>{c.push(C)});let f=new Set;for(let C of c)for(let S of tPt(n,C))f.add(S);let p=new Set([r.get("rcFilename"),Er.lockfile,Er.manifest]),h=await a.filterChanges(n,f,p),E=await a.genCommitMessage(n,h);if(this.dryRun)if(this.commit)this.context.stdout.write(`${E} +`);else for(let C of h)this.context.stdout.write(`${fe.fromPortablePath(C.path)} +`);else if(this.reset){let C=await a.filterChanges(n,f,p,{staged:!0});C.length===0?this.context.stdout.write("No staged changes found!"):await a.makeReset(n,C)}else h.length===0?this.context.stdout.write("No changes found!"):this.commit?await a.makeCommit(n,h,E):(await a.makeStage(n,h),this.context.stdout.write(E))}};async function ePt(t){let e=null,r=null;for(let s of $bt)if((r=await s.findRoot(t))!==null){e=s;break}if(e===null||r===null)throw new nt("No stage driver has been found for your current project");return{driver:e,root:r}}function tPt(t,e){let r=[];if(e===null)return r;for(;;){(e===t||e.startsWith(`${t}/`))&&r.push(e);let s;try{s=ce.statSync(e)}catch{break}if(s.isSymbolicLink())e=J.resolve(J.dirname(e),ce.readlinkSync(e));else break}return r}var rPt={commands:[j1]},nPt=rPt;var lz={};Vt(lz,{default:()=>fPt});Ge();Ge();Dt();var fke=ut(Ai());Ge();var cke=ut(g9()),iPt="e8e1bd300d860104bb8c58453ffa1eb4",sPt="OFCNCOG2CU",uke=async(t,e)=>{let r=G.stringifyIdent(t),a=oPt(e).initIndex("npm-search");try{return(await a.getObject(r,{attributesToRetrieve:["types"]})).types?.ts==="definitely-typed"}catch{return!1}},oPt=t=>(0,cke.default)(sPt,iPt,{requester:{async send(r){try{let s=await nn.request(r.url,r.data||null,{configuration:t,headers:r.headers});return{content:s.body,isTimedOut:!1,status:s.statusCode}}catch(s){return{content:s.response.body,isTimedOut:!1,status:s.response.statusCode}}}}});var Ake=t=>t.scope?`${t.scope}__${t.name}`:`${t.name}`,aPt=async(t,e,r,s)=>{if(r.scope==="types")return;let{project:a}=t,{configuration:n}=a;if(!(n.get("tsEnableAutoTypes")??(ce.existsSync(J.join(t.cwd,"tsconfig.json"))||ce.existsSync(J.join(a.cwd,"tsconfig.json")))))return;let f=n.makeResolver(),p={project:a,resolver:f,report:new ki};if(!await uke(r,n))return;let E=Ake(r),C=G.parseRange(r.range).selector;if(!Fr.validRange(C)){let N=n.normalizeDependency(r),U=await f.getCandidates(N,{},p);C=G.parseRange(U[0].reference).selector}let S=fke.default.coerce(C);if(S===null)return;let P=`${Xu.Modifier.CARET}${S.major}`,I=G.makeDescriptor(G.makeIdent("types",E),P),R=je.mapAndFind(a.workspaces,N=>{let U=N.manifest.dependencies.get(r.identHash)?.descriptorHash,W=N.manifest.devDependencies.get(r.identHash)?.descriptorHash;if(U!==r.descriptorHash&&W!==r.descriptorHash)return je.mapAndFind.skip;let ee=[];for(let ie of Ut.allDependencies){let ue=N.manifest[ie].get(I.identHash);typeof ue>"u"||ee.push([ie,ue])}return ee.length===0?je.mapAndFind.skip:ee});if(typeof R<"u")for(let[N,U]of R)t.manifest[N].set(U.identHash,U);else{try{let N=n.normalizeDependency(I);if((await f.getCandidates(N,{},p)).length===0)return}catch{return}t.manifest[Xu.Target.DEVELOPMENT].set(I.identHash,I)}},lPt=async(t,e,r)=>{if(r.scope==="types")return;let{project:s}=t,{configuration:a}=s;if(!(a.get("tsEnableAutoTypes")??(ce.existsSync(J.join(t.cwd,"tsconfig.json"))||ce.existsSync(J.join(s.cwd,"tsconfig.json")))))return;let c=Ake(r),f=G.makeIdent("types",c);for(let p of Ut.allDependencies)typeof t.manifest[p].get(f.identHash)>"u"||t.manifest[p].delete(f.identHash)},cPt=(t,e)=>{e.publishConfig&&e.publishConfig.typings&&(e.typings=e.publishConfig.typings),e.publishConfig&&e.publishConfig.types&&(e.types=e.publishConfig.types)},uPt={configuration:{tsEnableAutoTypes:{description:"Whether Yarn should auto-install @types/ dependencies on 'yarn add'",type:"BOOLEAN",isNullable:!0,default:null}},hooks:{afterWorkspaceDependencyAddition:aPt,afterWorkspaceDependencyRemoval:lPt,beforeWorkspacePacking:cPt}},fPt=uPt;var pz={};Vt(pz,{VersionApplyCommand:()=>Y1,VersionCheckCommand:()=>V1,VersionCommand:()=>J1,default:()=>dPt,versionUtils:()=>W1});Ge();Ge();Yt();var W1={};Vt(W1,{Decision:()=>G1,applyPrerelease:()=>pke,applyReleases:()=>Az,applyStrategy:()=>sP,clearVersionFiles:()=>cz,getUndecidedDependentWorkspaces:()=>aP,getUndecidedWorkspaces:()=>UL,openVersionFile:()=>q1,requireMoreDecisions:()=>pPt,resolveVersionFiles:()=>oP,suggestStrategy:()=>fz,updateVersionFiles:()=>uz,validateReleaseDecision:()=>dy});Ge();Dt();wc();Yt();ql();var kA=ut(Ai()),APt=/^(>=|[~^]|)(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(-(0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(\.(0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?(\+[0-9a-zA-Z-]+(\.[0-9a-zA-Z-]+)*)?$/,G1=(h=>(h.UNDECIDED="undecided",h.DECLINE="decline",h.MAJOR="major",h.MINOR="minor",h.PATCH="patch",h.PREMAJOR="premajor",h.PREMINOR="preminor",h.PREPATCH="prepatch",h.PRERELEASE="prerelease",h))(G1||{});function dy(t){let e=kA.default.valid(t);return e||je.validateEnum(O4(G1,"UNDECIDED"),t)}async function oP(t,{prerelease:e=null}={}){let r=new Map,s=t.configuration.get("deferredVersionFolder");if(!ce.existsSync(s))return r;let a=await ce.readdirPromise(s);for(let n of a){if(!n.endsWith(".yml"))continue;let c=J.join(s,n),f=await ce.readFilePromise(c,"utf8"),p=ls(f);for(let[h,E]of Object.entries(p.releases||{})){if(E==="decline")continue;let C=G.parseIdent(h),S=t.tryWorkspaceByIdent(C);if(S===null)throw new Error(`Assertion failed: Expected a release definition file to only reference existing workspaces (${J.basename(c)} references ${h})`);if(S.manifest.version===null)throw new Error(`Assertion failed: Expected the workspace to have a version (${G.prettyLocator(t.configuration,S.anchoredLocator)})`);let P=S.manifest.raw.stableVersion??S.manifest.version,I=r.get(S),R=sP(E==="prerelease"?S.manifest.version:P,dy(E));if(R===null)throw new Error(`Assertion failed: Expected ${P} to support being bumped via strategy ${E}`);let N=typeof I<"u"?kA.default.gt(R,I)?R:I:R;r.set(S,N)}}return e&&(r=new Map([...r].map(([n,c])=>[n,pke(c,{current:n.manifest.version,prerelease:e})]))),r}async function cz(t){let e=t.configuration.get("deferredVersionFolder");ce.existsSync(e)&&await ce.removePromise(e)}async function uz(t,e){let r=new Set(e),s=t.configuration.get("deferredVersionFolder");if(!ce.existsSync(s))return;let a=await ce.readdirPromise(s);for(let n of a){if(!n.endsWith(".yml"))continue;let c=J.join(s,n),f=await ce.readFilePromise(c,"utf8"),p=ls(f),h=p?.releases;if(h){for(let E of Object.keys(h)){let C=G.parseIdent(E),S=t.tryWorkspaceByIdent(C);(S===null||r.has(S))&&delete p.releases[E]}Object.keys(p.releases).length>0?await ce.changeFilePromise(c,nl(new nl.PreserveOrdering(p))):await ce.unlinkPromise(c)}}}async function q1(t,{allowEmpty:e=!1}={}){let r=t.configuration;if(r.projectCwd===null)throw new nt("This command can only be run from within a Yarn project");let s=await ka.fetchRoot(r.projectCwd),a=s!==null?await ka.fetchBase(s,{baseRefs:r.get("changesetBaseRefs")}):null,n=s!==null?await ka.fetchChangedFiles(s,{base:a.hash,project:t}):[],c=r.get("deferredVersionFolder"),f=n.filter(P=>J.contains(c,P)!==null);if(f.length>1)throw new nt(`Your current branch contains multiple versioning files; this isn't supported: +- ${f.map(P=>fe.fromPortablePath(P)).join(` +- `)}`);let p=new Set(je.mapAndFilter(n,P=>{let I=t.tryWorkspaceByFilePath(P);return I===null?je.mapAndFilter.skip:I}));if(f.length===0&&p.size===0&&!e)return null;let h=f.length===1?f[0]:J.join(c,`${Nn.makeHash(Math.random().toString()).slice(0,8)}.yml`),E=ce.existsSync(h)?await ce.readFilePromise(h,"utf8"):"{}",C=ls(E),S=new Map;for(let P of C.declined||[]){let I=G.parseIdent(P),R=t.getWorkspaceByIdent(I);S.set(R,"decline")}for(let[P,I]of Object.entries(C.releases||{})){let R=G.parseIdent(P),N=t.getWorkspaceByIdent(R);S.set(N,dy(I))}return{project:t,root:s,baseHash:a!==null?a.hash:null,baseTitle:a!==null?a.title:null,changedFiles:new Set(n),changedWorkspaces:p,releaseRoots:new Set([...p].filter(P=>P.manifest.version!==null)),releases:S,async saveAll(){let P={},I=[],R=[];for(let N of t.workspaces){if(N.manifest.version===null)continue;let U=G.stringifyIdent(N.anchoredLocator),W=S.get(N);W==="decline"?I.push(U):typeof W<"u"?P[U]=dy(W):p.has(N)&&R.push(U)}await ce.mkdirPromise(J.dirname(h),{recursive:!0}),await ce.changeFilePromise(h,nl(new nl.PreserveOrdering({releases:Object.keys(P).length>0?P:void 0,declined:I.length>0?I:void 0,undecided:R.length>0?R:void 0})))}}}function pPt(t){return UL(t).size>0||aP(t).length>0}function UL(t){let e=new Set;for(let r of t.changedWorkspaces)r.manifest.version!==null&&(t.releases.has(r)||e.add(r));return e}function aP(t,{include:e=new Set}={}){let r=[],s=new Map(je.mapAndFilter([...t.releases],([n,c])=>c==="decline"?je.mapAndFilter.skip:[n.anchoredLocator.locatorHash,n])),a=new Map(je.mapAndFilter([...t.releases],([n,c])=>c!=="decline"?je.mapAndFilter.skip:[n.anchoredLocator.locatorHash,n]));for(let n of t.project.workspaces)if(!(!e.has(n)&&(a.has(n.anchoredLocator.locatorHash)||s.has(n.anchoredLocator.locatorHash)))&&n.manifest.version!==null)for(let c of Ut.hardDependencies)for(let f of n.manifest.getForScope(c).values()){let p=t.project.tryWorkspaceByDescriptor(f);p!==null&&s.has(p.anchoredLocator.locatorHash)&&r.push([n,p])}return r}function fz(t,e){let r=kA.default.clean(e);for(let s of Object.values(G1))if(s!=="undecided"&&s!=="decline"&&kA.default.inc(t,s)===r)return s;return null}function sP(t,e){if(kA.default.valid(e))return e;if(t===null)throw new nt(`Cannot apply the release strategy "${e}" unless the workspace already has a valid version`);if(!kA.default.valid(t))throw new nt(`Cannot apply the release strategy "${e}" on a non-semver version (${t})`);let r=kA.default.inc(t,e);if(r===null)throw new nt(`Cannot apply the release strategy "${e}" on the specified version (${t})`);return r}function Az(t,e,{report:r,exact:s}){let a=new Map;for(let n of t.workspaces)for(let c of Ut.allDependencies)for(let f of n.manifest[c].values()){let p=t.tryWorkspaceByDescriptor(f);if(p===null||!e.has(p))continue;je.getArrayWithDefault(a,p).push([n,c,f.identHash])}for(let[n,c]of e){let f=n.manifest.version;n.manifest.version=c,kA.default.prerelease(c)===null?delete n.manifest.raw.stableVersion:n.manifest.raw.stableVersion||(n.manifest.raw.stableVersion=f);let p=n.manifest.name!==null?G.stringifyIdent(n.manifest.name):null;r.reportInfo(0,`${G.prettyLocator(t.configuration,n.anchoredLocator)}: Bumped to ${c}`),r.reportJson({cwd:fe.fromPortablePath(n.cwd),ident:p,oldVersion:f,newVersion:c});let h=a.get(n);if(!(typeof h>"u"))for(let[E,C,S]of h){let P=E.manifest[C].get(S);if(typeof P>"u")throw new Error("Assertion failed: The dependency should have existed");let I=P.range,R=!1;if(I.startsWith(Ei.protocol)&&(I=I.slice(Ei.protocol.length),R=!0,I===n.relativeCwd))continue;let N=I.match(APt);if(!N){r.reportWarning(0,`Couldn't auto-upgrade range ${I} (in ${G.prettyLocator(t.configuration,E.anchoredLocator)})`);continue}let U=s?`${c}`:`${N[1]}${c}`;R&&(U=`${Ei.protocol}${U}`);let W=G.makeDescriptor(P,U);E.manifest[C].set(S,W)}}}var hPt=new Map([["%n",{extract:t=>t.length>=1?[t[0],t.slice(1)]:null,generate:(t=0)=>`${t+1}`}]]);function pke(t,{current:e,prerelease:r}){let s=new kA.default.SemVer(e),a=s.prerelease.slice(),n=[];s.prerelease=[],s.format()!==t&&(a.length=0);let c=!0,f=r.split(/\./g);for(let p of f){let h=hPt.get(p);if(typeof h>"u")n.push(p),a[0]===p?a.shift():c=!1;else{let E=c?h.extract(a):null;E!==null&&typeof E[0]=="number"?(n.push(h.generate(E[0])),a=E[1]):(n.push(h.generate()),c=!1)}}return s.prerelease&&(s.prerelease=[]),`${t}-${n.join(".")}`}var Y1=class extends ft{constructor(){super(...arguments);this.all=ge.Boolean("--all",!1,{description:"Apply the deferred version changes on all workspaces"});this.dryRun=ge.Boolean("--dry-run",!1,{description:"Print the versions without actually generating the package archive"});this.prerelease=ge.String("--prerelease",{description:"Add a prerelease identifier to new versions",tolerateBoolean:!0});this.exact=ge.Boolean("--exact",!1,{description:"Use the exact version of each package, removes any range. Useful for nightly releases where the range might match another version."});this.recursive=ge.Boolean("-R,--recursive",{description:"Release the transitive workspaces as well"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"})}static{this.paths=[["version","apply"]]}static{this.usage=ot.Usage({category:"Release-related commands",description:"apply all the deferred version bumps at once",details:` + This command will apply the deferred version changes and remove their definitions from the repository. + + Note that if \`--prerelease\` is set, the given prerelease identifier (by default \`rc.%n\`) will be used on all new versions and the version definitions will be kept as-is. + + By default only the current workspace will be bumped, but you can configure this behavior by using one of: + + - \`--recursive\` to also apply the version bump on its dependencies + - \`--all\` to apply the version bump on all packages in the repository + + Note that this command will also update the \`workspace:\` references across all your local workspaces, thus ensuring that they keep referring to the same workspaces even after the version bump. + `,examples:[["Apply the version change to the local workspace","yarn version apply"],["Apply the version change to all the workspaces in the local workspace","yarn version apply --all"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Tt.find(r,this.context.cwd),n=await Kr.find(r);if(!a)throw new ar(s.cwd,this.context.cwd);await s.restoreInstallState({restoreResolutions:!1});let c=await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout},async f=>{let p=this.prerelease?typeof this.prerelease!="boolean"?this.prerelease:"rc.%n":null,h=await oP(s,{prerelease:p}),E=new Map;if(this.all)E=h;else{let C=this.recursive?a.getRecursiveWorkspaceDependencies():[a];for(let S of C){let P=h.get(S);typeof P<"u"&&E.set(S,P)}}if(E.size===0){let C=h.size>0?" Did you want to add --all?":"";f.reportWarning(0,`The current workspace doesn't seem to require a version bump.${C}`);return}Az(s,E,{report:f,exact:this.exact}),this.dryRun||(p||(this.all?await cz(s):await uz(s,[...E.keys()])),f.reportSeparator())});return this.dryRun||c.hasErrors()?c.exitCode():await s.installWithNewReport({json:this.json,stdout:this.context.stdout},{cache:n})}};Ge();Dt();Yt();var _L=ut(Ai());var V1=class extends ft{constructor(){super(...arguments);this.interactive=ge.Boolean("-i,--interactive",{description:"Open an interactive interface used to set version bumps"})}static{this.paths=[["version","check"]]}static{this.usage=ot.Usage({category:"Release-related commands",description:"check that all the relevant packages have been bumped",details:"\n **Warning:** This command currently requires Git.\n\n This command will check that all the packages covered by the files listed in argument have been properly bumped or declined to bump.\n\n In the case of a bump, the check will also cover transitive packages - meaning that should `Foo` be bumped, a package `Bar` depending on `Foo` will require a decision as to whether `Bar` will need to be bumped. This check doesn't cross packages that have declined to bump.\n\n In case no arguments are passed to the function, the list of modified files will be generated by comparing the HEAD against `master`.\n ",examples:[["Check whether the modified packages need a bump","yarn version check"]]})}async execute(){return this.interactive?await this.executeInteractive():await this.executeStandard()}async executeInteractive(){iw(this.context);let{Gem:r}=await Promise.resolve().then(()=>(WF(),LW)),{ScrollableItems:s}=await Promise.resolve().then(()=>(KF(),JF)),{FocusRequest:a}=await Promise.resolve().then(()=>(UW(),v2e)),{useListInput:n}=await Promise.resolve().then(()=>(VF(),S2e)),{renderForm:c}=await Promise.resolve().then(()=>($F(),ZF)),{Box:f,Text:p}=await Promise.resolve().then(()=>ut(Wc())),{default:h,useCallback:E,useState:C}=await Promise.resolve().then(()=>ut(hn())),S=await ze.find(this.context.cwd,this.context.plugins),{project:P,workspace:I}=await Tt.find(S,this.context.cwd);if(!I)throw new ar(P.cwd,this.context.cwd);await P.restoreInstallState();let R=await q1(P);if(R===null||R.releaseRoots.size===0)return 0;if(R.root===null)throw new nt("This command can only be run on Git repositories");let N=()=>h.createElement(f,{flexDirection:"row",paddingBottom:1},h.createElement(f,{flexDirection:"column",width:60},h.createElement(f,null,h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},""),"/",h.createElement(p,{bold:!0,color:"cyanBright"},"")," to select workspaces.")),h.createElement(f,null,h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},""),"/",h.createElement(p,{bold:!0,color:"cyanBright"},"")," to select release strategies."))),h.createElement(f,{flexDirection:"column"},h.createElement(f,{marginLeft:1},h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"")," to save.")),h.createElement(f,{marginLeft:1},h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"")," to abort.")))),U=({workspace:me,active:pe,decision:Be,setDecision:Ce})=>{let g=me.manifest.raw.stableVersion??me.manifest.version;if(g===null)throw new Error(`Assertion failed: The version should have been set (${G.prettyLocator(S,me.anchoredLocator)})`);if(_L.default.prerelease(g)!==null)throw new Error(`Assertion failed: Prerelease identifiers shouldn't be found (${g})`);let we=["undecided","decline","patch","minor","major"];n(Be,we,{active:pe,minus:"left",plus:"right",set:Ce});let ye=Be==="undecided"?h.createElement(p,{color:"yellow"},g):Be==="decline"?h.createElement(p,{color:"green"},g):h.createElement(p,null,h.createElement(p,{color:"magenta"},g)," \u2192 ",h.createElement(p,{color:"green"},_L.default.valid(Be)?Be:_L.default.inc(g,Be)));return h.createElement(f,{flexDirection:"column"},h.createElement(f,null,h.createElement(p,null,G.prettyLocator(S,me.anchoredLocator)," - ",ye)),h.createElement(f,null,we.map(Ae=>h.createElement(f,{key:Ae,paddingLeft:2},h.createElement(p,null,h.createElement(r,{active:Ae===Be})," ",Ae)))))},W=me=>{let pe=new Set(R.releaseRoots),Be=new Map([...me].filter(([Ce])=>pe.has(Ce)));for(;;){let Ce=aP({project:R.project,releases:Be}),g=!1;if(Ce.length>0){for(let[we]of Ce)if(!pe.has(we)){pe.add(we),g=!0;let ye=me.get(we);typeof ye<"u"&&Be.set(we,ye)}}if(!g)break}return{relevantWorkspaces:pe,relevantReleases:Be}},ee=()=>{let[me,pe]=C(()=>new Map(R.releases)),Be=E((Ce,g)=>{let we=new Map(me);g!=="undecided"?we.set(Ce,g):we.delete(Ce);let{relevantReleases:ye}=W(we);pe(ye)},[me,pe]);return[me,Be]},ie=({workspaces:me,releases:pe})=>{let Be=[];Be.push(`${me.size} total`);let Ce=0,g=0;for(let we of me){let ye=pe.get(we);typeof ye>"u"?g+=1:ye!=="decline"&&(Ce+=1)}return Be.push(`${Ce} release${Ce===1?"":"s"}`),Be.push(`${g} remaining`),h.createElement(p,{color:"yellow"},Be.join(", "))},le=await c(({useSubmit:me})=>{let[pe,Be]=ee();me(pe);let{relevantWorkspaces:Ce}=W(pe),g=new Set([...Ce].filter(se=>!R.releaseRoots.has(se))),[we,ye]=C(0),Ae=E(se=>{switch(se){case a.BEFORE:ye(we-1);break;case a.AFTER:ye(we+1);break}},[we,ye]);return h.createElement(f,{flexDirection:"column"},h.createElement(N,null),h.createElement(f,null,h.createElement(p,{wrap:"wrap"},"The following files have been modified in your local checkout.")),h.createElement(f,{flexDirection:"column",marginTop:1,paddingLeft:2},[...R.changedFiles].map(se=>h.createElement(f,{key:se},h.createElement(p,null,h.createElement(p,{color:"grey"},fe.fromPortablePath(R.root)),fe.sep,fe.relative(fe.fromPortablePath(R.root),fe.fromPortablePath(se)))))),R.releaseRoots.size>0&&h.createElement(h.Fragment,null,h.createElement(f,{marginTop:1},h.createElement(p,{wrap:"wrap"},"Because of those files having been modified, the following workspaces may need to be released again (note that private workspaces are also shown here, because even though they won't be published, releasing them will allow us to flag their dependents for potential re-release):")),g.size>3?h.createElement(f,{marginTop:1},h.createElement(ie,{workspaces:R.releaseRoots,releases:pe})):null,h.createElement(f,{marginTop:1,flexDirection:"column"},h.createElement(s,{active:we%2===0,radius:1,size:2,onFocusRequest:Ae},[...R.releaseRoots].map(se=>h.createElement(U,{key:se.cwd,workspace:se,decision:pe.get(se)||"undecided",setDecision:Z=>Be(se,Z)}))))),g.size>0?h.createElement(h.Fragment,null,h.createElement(f,{marginTop:1},h.createElement(p,{wrap:"wrap"},"The following workspaces depend on other workspaces that have been marked for release, and thus may need to be released as well:")),h.createElement(f,null,h.createElement(p,null,"(Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"")," to move the focus between the workspace groups.)")),g.size>5?h.createElement(f,{marginTop:1},h.createElement(ie,{workspaces:g,releases:pe})):null,h.createElement(f,{marginTop:1,flexDirection:"column"},h.createElement(s,{active:we%2===1,radius:2,size:2,onFocusRequest:Ae},[...g].map(se=>h.createElement(U,{key:se.cwd,workspace:se,decision:pe.get(se)||"undecided",setDecision:Z=>Be(se,Z)}))))):null)},{versionFile:R},{stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr});if(typeof le>"u")return 1;R.releases.clear();for(let[me,pe]of le)R.releases.set(me,pe);await R.saveAll()}async executeStandard(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Tt.find(r,this.context.cwd);if(!a)throw new ar(s.cwd,this.context.cwd);return await s.restoreInstallState(),(await Ot.start({configuration:r,stdout:this.context.stdout},async c=>{let f=await q1(s);if(f===null||f.releaseRoots.size===0)return;if(f.root===null)throw new nt("This command can only be run on Git repositories");if(c.reportInfo(0,`Your PR was started right after ${he.pretty(r,f.baseHash.slice(0,7),"yellow")} ${he.pretty(r,f.baseTitle,"magenta")}`),f.changedFiles.size>0){c.reportInfo(0,"You have changed the following files since then:"),c.reportSeparator();for(let S of f.changedFiles)c.reportInfo(null,`${he.pretty(r,fe.fromPortablePath(f.root),"gray")}${fe.sep}${fe.relative(fe.fromPortablePath(f.root),fe.fromPortablePath(S))}`)}let p=!1,h=!1,E=UL(f);if(E.size>0){p||c.reportSeparator();for(let S of E)c.reportError(0,`${G.prettyLocator(r,S.anchoredLocator)} has been modified but doesn't have a release strategy attached`);p=!0}let C=aP(f);for(let[S,P]of C)h||c.reportSeparator(),c.reportError(0,`${G.prettyLocator(r,S.anchoredLocator)} doesn't have a release strategy attached, but depends on ${G.prettyWorkspace(r,P)} which is planned for release.`),h=!0;(p||h)&&(c.reportSeparator(),c.reportInfo(0,"This command detected that at least some workspaces have received modifications without explicit instructions as to how they had to be released (if needed)."),c.reportInfo(0,"To correct these errors, run `yarn version check --interactive` then follow the instructions."))})).exitCode()}};Ge();Yt();var HL=ut(Ai());var J1=class extends ft{constructor(){super(...arguments);this.deferred=ge.Boolean("-d,--deferred",{description:"Prepare the version to be bumped during the next release cycle"});this.immediate=ge.Boolean("-i,--immediate",{description:"Bump the version immediately"});this.strategy=ge.String()}static{this.paths=[["version"]]}static{this.usage=ot.Usage({category:"Release-related commands",description:"apply a new version to the current package",details:"\n This command will bump the version number for the given package, following the specified strategy:\n\n - If `major`, the first number from the semver range will be increased (`X.0.0`).\n - If `minor`, the second number from the semver range will be increased (`0.X.0`).\n - If `patch`, the third number from the semver range will be increased (`0.0.X`).\n - If prefixed by `pre` (`premajor`, ...), a `-0` suffix will be set (`0.0.0-0`).\n - If `prerelease`, the suffix will be increased (`0.0.0-X`); the third number from the semver range will also be increased if there was no suffix in the previous version.\n - If `decline`, the nonce will be increased for `yarn version check` to pass without version bump.\n - If a valid semver range, it will be used as new version.\n - If unspecified, Yarn will ask you for guidance.\n\n For more information about the `--deferred` flag, consult our documentation (https://yarnpkg.com/features/release-workflow#deferred-versioning).\n ",examples:[["Immediately bump the version to the next major","yarn version major"],["Prepare the version to be bumped to the next major","yarn version major --deferred"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Tt.find(r,this.context.cwd);if(!a)throw new ar(s.cwd,this.context.cwd);let n=r.get("preferDeferredVersions");this.deferred&&(n=!0),this.immediate&&(n=!1);let c=HL.default.valid(this.strategy),f=this.strategy==="decline",p;if(c)if(a.manifest.version!==null){let E=fz(a.manifest.version,this.strategy);E!==null?p=E:p=this.strategy}else p=this.strategy;else{let E=a.manifest.version;if(!f){if(E===null)throw new nt("Can't bump the version if there wasn't a version to begin with - use 0.0.0 as initial version then run the command again.");if(typeof E!="string"||!HL.default.valid(E))throw new nt(`Can't bump the version (${E}) if it's not valid semver`)}p=dy(this.strategy)}if(!n){let C=(await oP(s)).get(a);if(typeof C<"u"&&p!=="decline"){let S=sP(a.manifest.version,p);if(HL.default.lt(S,C))throw new nt(`Can't bump the version to one that would be lower than the current deferred one (${C})`)}}let h=await q1(s,{allowEmpty:!0});return h.releases.set(a,p),await h.saveAll(),n?0:await this.cli.run(["version","apply"])}};var gPt={configuration:{deferredVersionFolder:{description:"Folder where are stored the versioning files",type:"ABSOLUTE_PATH",default:"./.yarn/versions"},preferDeferredVersions:{description:"If true, running `yarn version` will assume the `--deferred` flag unless `--immediate` is set",type:"BOOLEAN",default:!1}},commands:[Y1,V1,J1]},dPt=gPt;var hz={};Vt(hz,{WorkspacesFocusCommand:()=>K1,WorkspacesForeachCommand:()=>X1,default:()=>EPt});Ge();Ge();Yt();var K1=class extends ft{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.production=ge.Boolean("--production",!1,{description:"Only install regular dependencies by omitting dev dependencies"});this.all=ge.Boolean("-A,--all",!1,{description:"Install the entire project"});this.workspaces=ge.Rest()}static{this.paths=[["workspaces","focus"]]}static{this.usage=ot.Usage({category:"Workspace-related commands",description:"install a single workspace and its dependencies",details:"\n This command will run an install as if the specified workspaces (and all other workspaces they depend on) were the only ones in the project. If no workspaces are explicitly listed, the active one will be assumed.\n\n Note that this command is only very moderately useful when using zero-installs, since the cache will contain all the packages anyway - meaning that the only difference between a full install and a focused install would just be a few extra lines in the `.pnp.cjs` file, at the cost of introducing an extra complexity.\n\n If the `-A,--all` flag is set, the entire project will be installed. Combine with `--production` to replicate the old `yarn install --production`.\n "})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Tt.find(r,this.context.cwd),n=await Kr.find(r);await s.restoreInstallState({restoreResolutions:!1});let c;if(this.all)c=new Set(s.workspaces);else if(this.workspaces.length===0){if(!a)throw new ar(s.cwd,this.context.cwd);c=new Set([a])}else c=new Set(this.workspaces.map(f=>s.getWorkspaceByIdent(G.parseIdent(f))));for(let f of c)for(let p of this.production?["dependencies"]:Ut.hardDependencies)for(let h of f.manifest.getForScope(p).values()){let E=s.tryWorkspaceByDescriptor(h);E!==null&&c.add(E)}for(let f of s.workspaces)c.has(f)?this.production&&f.manifest.devDependencies.clear():(f.manifest.installConfig=f.manifest.installConfig||{},f.manifest.installConfig.selfReferences=!1,f.manifest.dependencies.clear(),f.manifest.devDependencies.clear(),f.manifest.peerDependencies.clear(),f.manifest.scripts.clear());return await s.installWithNewReport({json:this.json,stdout:this.context.stdout},{cache:n,persistProject:!1})}};Ge();Ge();Ge();Yt();var z1=ut(Go()),gke=ut(Ld());Ul();var X1=class extends ft{constructor(){super(...arguments);this.from=ge.Array("--from",{description:"An array of glob pattern idents or paths from which to base any recursion"});this.all=ge.Boolean("-A,--all",{description:"Run the command on all workspaces of a project"});this.recursive=ge.Boolean("-R,--recursive",{description:"Run the command on the current workspace and all of its recursive dependencies"});this.worktree=ge.Boolean("-W,--worktree",{description:"Run the command on all workspaces of the current worktree"});this.verbose=ge.Counter("-v,--verbose",{description:"Increase level of logging verbosity up to 2 times"});this.parallel=ge.Boolean("-p,--parallel",!1,{description:"Run the commands in parallel"});this.interlaced=ge.Boolean("-i,--interlaced",!1,{description:"Print the output of commands in real-time instead of buffering it"});this.jobs=ge.String("-j,--jobs",{description:"The maximum number of parallel tasks that the execution will be limited to; or `unlimited`",validator:g_([fo(["unlimited"]),$2(h_(),[m_(),d_(1)])])});this.topological=ge.Boolean("-t,--topological",!1,{description:"Run the command after all workspaces it depends on (regular) have finished"});this.topologicalDev=ge.Boolean("--topological-dev",!1,{description:"Run the command after all workspaces it depends on (regular + dev) have finished"});this.include=ge.Array("--include",[],{description:"An array of glob pattern idents or paths; only matching workspaces will be traversed"});this.exclude=ge.Array("--exclude",[],{description:"An array of glob pattern idents or paths; matching workspaces won't be traversed"});this.publicOnly=ge.Boolean("--no-private",{description:"Avoid running the command on private workspaces"});this.since=ge.String("--since",{description:"Only include workspaces that have been changed since the specified ref.",tolerateBoolean:!0});this.dryRun=ge.Boolean("-n,--dry-run",{description:"Print the commands that would be run, without actually running them"});this.commandName=ge.String();this.args=ge.Proxy()}static{this.paths=[["workspaces","foreach"]]}static{this.usage=ot.Usage({category:"Workspace-related commands",description:"run a command on all workspaces",details:"\n This command will run a given sub-command on current and all its descendant workspaces. Various flags can alter the exact behavior of the command:\n\n - If `-p,--parallel` is set, the commands will be ran in parallel; they'll by default be limited to a number of parallel tasks roughly equal to half your core number, but that can be overridden via `-j,--jobs`, or disabled by setting `-j unlimited`.\n\n - If `-p,--parallel` and `-i,--interlaced` are both set, Yarn will print the lines from the output as it receives them. If `-i,--interlaced` wasn't set, it would instead buffer the output from each process and print the resulting buffers only after their source processes have exited.\n\n - If `-t,--topological` is set, Yarn will only run the command after all workspaces that it depends on through the `dependencies` field have successfully finished executing. If `--topological-dev` is set, both the `dependencies` and `devDependencies` fields will be considered when figuring out the wait points.\n\n - If `-A,--all` is set, Yarn will run the command on all the workspaces of a project.\n\n - If `-R,--recursive` is set, Yarn will find workspaces to run the command on by recursively evaluating `dependencies` and `devDependencies` fields, instead of looking at the `workspaces` fields.\n\n - If `-W,--worktree` is set, Yarn will find workspaces to run the command on by looking at the current worktree.\n\n - If `--from` is set, Yarn will use the packages matching the 'from' glob as the starting point for any recursive search.\n\n - If `--since` is set, Yarn will only run the command on workspaces that have been modified since the specified ref. By default Yarn will use the refs specified by the `changesetBaseRefs` configuration option.\n\n - If `--dry-run` is set, Yarn will explain what it would do without actually doing anything.\n\n - The command may apply to only some workspaces through the use of `--include` which acts as a whitelist. The `--exclude` flag will do the opposite and will be a list of packages that mustn't execute the script. Both flags accept glob patterns (if valid Idents and supported by [micromatch](https://github.com/micromatch/micromatch)). Make sure to escape the patterns, to prevent your own shell from trying to expand them. You can also use the `--no-private` flag to avoid running the command in private workspaces.\n\n The `-v,--verbose` flag can be passed up to twice: once to prefix output lines with the originating workspace's name, and again to include start/finish/timing log lines. Maximum verbosity is enabled by default in terminal environments.\n\n If the command is `run` and the script being run does not exist the child workspace will be skipped without error.\n ",examples:[["Publish all packages","yarn workspaces foreach -A --no-private npm publish --tolerate-republish"],["Run the build script on all descendant packages","yarn workspaces foreach -A run build"],["Run the build script on current and all descendant packages in parallel, building package dependencies first","yarn workspaces foreach -Apt run build"],["Run the build script on several packages and all their dependencies, building dependencies first","yarn workspaces foreach -Rpt --from '{workspace-a,workspace-b}' run build"]]})}static{this.schema=[tB("all",qf.Forbids,["from","recursive","since","worktree"],{missingIf:"undefined"}),y_(["all","recursive","since","worktree"],{missingIf:"undefined"})]}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Tt.find(r,this.context.cwd);if(!this.all&&!a)throw new ar(s.cwd,this.context.cwd);await s.restoreInstallState();let n=this.cli.process([this.commandName,...this.args]),c=n.path.length===1&&n.path[0]==="run"&&typeof n.scriptName<"u"?n.scriptName:null;if(n.path.length===0)throw new nt("Invalid subcommand name for iteration - use the 'run' keyword if you wish to execute a script");let f=Ce=>{this.dryRun&&this.context.stdout.write(`${Ce} +`)},p=()=>{let Ce=this.from.map(g=>z1.default.matcher(g));return s.workspaces.filter(g=>{let we=G.stringifyIdent(g.anchoredLocator),ye=g.relativeCwd;return Ce.some(Ae=>Ae(we)||Ae(ye))})},h=[];if(this.since?(f("Option --since is set; selecting the changed workspaces as root for workspace selection"),h=Array.from(await ka.fetchChangedWorkspaces({ref:this.since,project:s}))):this.from?(f("Option --from is set; selecting the specified workspaces"),h=[...p()]):this.worktree?(f("Option --worktree is set; selecting the current workspace"),h=[a]):this.recursive?(f("Option --recursive is set; selecting the current workspace"),h=[a]):this.all&&(f("Option --all is set; selecting all workspaces"),h=[...s.workspaces]),this.dryRun&&!this.all){for(let Ce of h)f(` +- ${Ce.relativeCwd} + ${G.prettyLocator(r,Ce.anchoredLocator)}`);h.length>0&&f("")}let E;if(this.recursive?this.since?(f("Option --recursive --since is set; recursively selecting all dependent workspaces"),E=new Set(h.map(Ce=>[...Ce.getRecursiveWorkspaceDependents()]).flat())):(f("Option --recursive is set; recursively selecting all transitive dependencies"),E=new Set(h.map(Ce=>[...Ce.getRecursiveWorkspaceDependencies()]).flat())):this.worktree?(f("Option --worktree is set; recursively selecting all nested workspaces"),E=new Set(h.map(Ce=>[...Ce.getRecursiveWorkspaceChildren()]).flat())):E=null,E!==null&&(h=[...new Set([...h,...E])],this.dryRun))for(let Ce of E)f(` +- ${Ce.relativeCwd} + ${G.prettyLocator(r,Ce.anchoredLocator)}`);let C=[],S=!1;if(c?.includes(":")){for(let Ce of s.workspaces)if(Ce.manifest.scripts.has(c)&&(S=!S,S===!1))break}for(let Ce of h){if(c&&!Ce.manifest.scripts.has(c)&&!S&&!(await In.getWorkspaceAccessibleBinaries(Ce)).has(c)){f(`Excluding ${Ce.relativeCwd} because it doesn't have a "${c}" script`);continue}if(!(c===r.env.npm_lifecycle_event&&Ce.cwd===a.cwd)){if(this.include.length>0&&!z1.default.isMatch(G.stringifyIdent(Ce.anchoredLocator),this.include)&&!z1.default.isMatch(Ce.relativeCwd,this.include)){f(`Excluding ${Ce.relativeCwd} because it doesn't match the --include filter`);continue}if(this.exclude.length>0&&(z1.default.isMatch(G.stringifyIdent(Ce.anchoredLocator),this.exclude)||z1.default.isMatch(Ce.relativeCwd,this.exclude))){f(`Excluding ${Ce.relativeCwd} because it matches the --exclude filter`);continue}if(this.publicOnly&&Ce.manifest.private===!0){f(`Excluding ${Ce.relativeCwd} because it's a private workspace and --no-private was set`);continue}C.push(Ce)}}if(this.dryRun)return 0;let P=this.verbose??(this.context.stdout.isTTY?1/0:0),I=P>0,R=P>1,N=this.parallel?this.jobs==="unlimited"?1/0:Number(this.jobs)||Math.ceil(Ui.availableParallelism()/2):1,U=N===1?!1:this.parallel,W=U?this.interlaced:!0,ee=(0,gke.default)(N),ie=new Map,ue=new Set,le=0,me=null,pe=!1,Be=await Ot.start({configuration:r,stdout:this.context.stdout,includePrefix:!1},async Ce=>{let g=async(we,{commandIndex:ye})=>{if(pe)return-1;!U&&R&&ye>1&&Ce.reportSeparator();let Ae=mPt(we,{configuration:r,label:I,commandIndex:ye}),[se,Z]=hke(Ce,{prefix:Ae,interlaced:W}),[De,Re]=hke(Ce,{prefix:Ae,interlaced:W});try{R&&Ce.reportInfo(null,`${Ae?`${Ae} `:""}Process started`);let mt=Date.now(),j=await this.cli.run([this.commandName,...this.args],{cwd:we.cwd,stdout:se,stderr:De})||0;se.end(),De.end(),await Z,await Re;let rt=Date.now();if(R){let Fe=r.get("enableTimers")?`, completed in ${he.pretty(r,rt-mt,he.Type.DURATION)}`:"";Ce.reportInfo(null,`${Ae?`${Ae} `:""}Process exited (exit code ${j})${Fe}`)}return j===130&&(pe=!0,me=j),j}catch(mt){throw se.end(),De.end(),await Z,await Re,mt}};for(let we of C)ie.set(we.anchoredLocator.locatorHash,we);for(;ie.size>0&&!Ce.hasErrors();){let we=[];for(let[Z,De]of ie){if(ue.has(De.anchoredDescriptor.descriptorHash))continue;let Re=!0;if(this.topological||this.topologicalDev){let mt=this.topologicalDev?new Map([...De.manifest.dependencies,...De.manifest.devDependencies]):De.manifest.dependencies;for(let j of mt.values()){let rt=s.tryWorkspaceByDescriptor(j);if(Re=rt===null||!ie.has(rt.anchoredLocator.locatorHash),!Re)break}}if(Re&&(ue.add(De.anchoredDescriptor.descriptorHash),we.push(ee(async()=>{let mt=await g(De,{commandIndex:++le});return ie.delete(Z),ue.delete(De.anchoredDescriptor.descriptorHash),{workspace:De,exitCode:mt}})),!U))break}if(we.length===0){let Z=Array.from(ie.values()).map(De=>G.prettyLocator(r,De.anchoredLocator)).join(", ");Ce.reportError(3,`Dependency cycle detected (${Z})`);return}let ye=await Promise.all(we);ye.forEach(({workspace:Z,exitCode:De})=>{De!==0&&Ce.reportError(0,`The command failed in workspace ${G.prettyLocator(r,Z.anchoredLocator)} with exit code ${De}`)});let se=ye.map(Z=>Z.exitCode).find(Z=>Z!==0);(this.topological||this.topologicalDev)&&typeof se<"u"&&Ce.reportError(0,"The command failed for workspaces that are depended upon by other workspaces; can't satisfy the dependency graph")}});return me!==null?me:Be.exitCode()}};function hke(t,{prefix:e,interlaced:r}){let s=t.createStreamReporter(e),a=new je.DefaultStream;a.pipe(s,{end:!1}),a.on("finish",()=>{s.end()});let n=new Promise(f=>{s.on("finish",()=>{f(a.active)})});if(r)return[a,n];let c=new je.BufferStream;return c.pipe(a,{end:!1}),c.on("finish",()=>{a.end()}),[c,n]}function mPt(t,{configuration:e,commandIndex:r,label:s}){if(!s)return null;let n=`[${G.stringifyIdent(t.anchoredLocator)}]:`,c=["#2E86AB","#A23B72","#F18F01","#C73E1D","#CCE2A3"],f=c[r%c.length];return he.pretty(e,n,f)}var yPt={commands:[K1,X1]},EPt=yPt;var tC=()=>({modules:new Map([["@yarnpkg/cli",Gv],["@yarnpkg/core",jv],["@yarnpkg/fslib",_2],["@yarnpkg/libzip",fv],["@yarnpkg/parsers",J2],["@yarnpkg/shell",mv],["clipanion",oB],["semver",IPt],["typanion",Ea],["@yarnpkg/plugin-essentials",hq],["@yarnpkg/plugin-catalog",yq],["@yarnpkg/plugin-compat",Bq],["@yarnpkg/plugin-constraints",_q],["@yarnpkg/plugin-dlx",Hq],["@yarnpkg/plugin-exec",qq],["@yarnpkg/plugin-file",Yq],["@yarnpkg/plugin-git",pq],["@yarnpkg/plugin-github",Kq],["@yarnpkg/plugin-http",zq],["@yarnpkg/plugin-init",Xq],["@yarnpkg/plugin-interactive-tools",JW],["@yarnpkg/plugin-jsr",zW],["@yarnpkg/plugin-link",XW],["@yarnpkg/plugin-nm",FY],["@yarnpkg/plugin-npm",FK],["@yarnpkg/plugin-npm-cli",qK],["@yarnpkg/plugin-pack",bV],["@yarnpkg/plugin-patch",XK],["@yarnpkg/plugin-pnp",wY],["@yarnpkg/plugin-pnpm",ez],["@yarnpkg/plugin-stage",az],["@yarnpkg/plugin-typescript",lz],["@yarnpkg/plugin-version",pz],["@yarnpkg/plugin-workspace-tools",hz]]),plugins:new Set(["@yarnpkg/plugin-essentials","@yarnpkg/plugin-catalog","@yarnpkg/plugin-compat","@yarnpkg/plugin-constraints","@yarnpkg/plugin-dlx","@yarnpkg/plugin-exec","@yarnpkg/plugin-file","@yarnpkg/plugin-git","@yarnpkg/plugin-github","@yarnpkg/plugin-http","@yarnpkg/plugin-init","@yarnpkg/plugin-interactive-tools","@yarnpkg/plugin-jsr","@yarnpkg/plugin-link","@yarnpkg/plugin-nm","@yarnpkg/plugin-npm","@yarnpkg/plugin-npm-cli","@yarnpkg/plugin-pack","@yarnpkg/plugin-patch","@yarnpkg/plugin-pnp","@yarnpkg/plugin-pnpm","@yarnpkg/plugin-stage","@yarnpkg/plugin-typescript","@yarnpkg/plugin-version","@yarnpkg/plugin-workspace-tools"])});function yke({cwd:t,pluginConfiguration:e}){let r=new Ca({binaryLabel:"Yarn Package Manager",binaryName:"yarn",binaryVersion:fn??""});return Object.assign(r,{defaultContext:{...Ca.defaultContext,cwd:t,plugins:e,quiet:!1,stdin:process.stdin,stdout:process.stdout,stderr:process.stderr}})}function CPt(t){if(je.parseOptionalBoolean(process.env.YARN_IGNORE_NODE))return!0;let r=process.versions.node,s=">=18.12.0";if(Fr.satisfiesWithPrereleases(r,s))return!0;let a=new nt(`This tool requires a Node version compatible with ${s} (got ${r}). Upgrade Node, or set \`YARN_IGNORE_NODE=1\` in your environment.`);return Ca.defaultContext.stdout.write(t.error(a)),!1}async function Eke({selfPath:t,pluginConfiguration:e}){return await ze.find(fe.toPortablePath(process.cwd()),e,{strict:!1,usePathCheck:t})}function wPt(t,e,{yarnPath:r}){if(!ce.existsSync(r))return t.error(new Error(`The "yarn-path" option has been set, but the specified location doesn't exist (${r}).`)),1;process.on("SIGINT",()=>{});let s={stdio:"inherit",env:{...process.env,YARN_IGNORE_PATH:"1"}};try{(0,dke.execFileSync)(process.execPath,[fe.fromPortablePath(r),...e],s)}catch(a){return a.status??1}return 0}function BPt(t,e){let r=null,s=e;return e.length>=2&&e[0]==="--cwd"?(r=fe.toPortablePath(e[1]),s=e.slice(2)):e.length>=1&&e[0].startsWith("--cwd=")?(r=fe.toPortablePath(e[0].slice(6)),s=e.slice(1)):e[0]==="add"&&e[e.length-2]==="--cwd"&&(r=fe.toPortablePath(e[e.length-1]),s=e.slice(0,e.length-2)),t.defaultContext.cwd=r!==null?J.resolve(r):J.cwd(),s}function vPt(t,{configuration:e}){if(!e.get("enableTelemetry")||mke.isCI||!process.stdout.isTTY)return;ze.telemetry=new ZI(e,"puba9cdc10ec5790a2cf4969dd413a47270");let s=/^@yarnpkg\/plugin-(.*)$/;for(let a of e.plugins.keys())$I.has(a.match(s)?.[1]??"")&&ze.telemetry?.reportPluginName(a);t.binaryVersion&&ze.telemetry.reportVersion(t.binaryVersion)}function Ike(t,{configuration:e}){for(let r of e.plugins.values())for(let s of r.commands||[])t.register(s)}async function SPt(t,e,{selfPath:r,pluginConfiguration:s}){if(!CPt(t))return 1;let a=await Eke({selfPath:r,pluginConfiguration:s}),n=a.get("yarnPath"),c=a.get("ignorePath");if(n&&!c)return wPt(t,e,{yarnPath:n});delete process.env.YARN_IGNORE_PATH;let f=BPt(t,e);vPt(t,{configuration:a}),Ike(t,{configuration:a});let p=t.process(f,t.defaultContext);return p.help||ze.telemetry?.reportCommandName(p.path.join(" ")),await t.run(p,t.defaultContext)}async function bde({cwd:t=J.cwd(),pluginConfiguration:e=tC()}={}){let r=yke({cwd:t,pluginConfiguration:e}),s=await Eke({pluginConfiguration:e,selfPath:null});return Ike(r,{configuration:s}),r}async function VR(t,{cwd:e=J.cwd(),selfPath:r,pluginConfiguration:s}){let a=yke({cwd:e,pluginConfiguration:s});function n(){Ca.defaultContext.stdout.write(`ERROR: Yarn is terminating due to an unexpected empty event loop. +Please report this issue at https://github.com/yarnpkg/berry/issues.`)}process.once("beforeExit",n);try{process.exitCode=42,process.exitCode=await SPt(a,t,{selfPath:r,pluginConfiguration:s})}catch(c){Ca.defaultContext.stdout.write(a.error(c)),process.exitCode=1}finally{process.off("beforeExit",n),await ce.rmtempPromise()}}VR(process.argv.slice(2),{cwd:J.cwd(),selfPath:fe.toPortablePath(fe.resolve(process.argv[1])),pluginConfiguration:tC()});})(); +/** + @license + Copyright (c) 2015, Rebecca Turner + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + PERFORMANCE OF THIS SOFTWARE. + */ +/** + @license + Copyright Node.js contributors. All rights reserved. + + 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. +*/ +/** + @license + The MIT License (MIT) + + Copyright (c) 2014 Blake Embrey (hello@blakeembrey.com) + + 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. +*/ +/** + @license + Copyright Joyent, Inc. and other Node contributors. + + 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. +*/ +/*! Bundled license information: + +is-number/index.js: + (*! + * is-number + * + * Copyright (c) 2014-present, Jon Schlinkert. + * Released under the MIT License. + *) + +to-regex-range/index.js: + (*! + * to-regex-range + * + * Copyright (c) 2015-present, Jon Schlinkert. + * Released under the MIT License. + *) + +fill-range/index.js: + (*! + * fill-range + * + * Copyright (c) 2014-present, Jon Schlinkert. + * Licensed under the MIT License. + *) + +is-extglob/index.js: + (*! + * is-extglob + * + * Copyright (c) 2014-2016, Jon Schlinkert. + * Licensed under the MIT License. + *) + +is-glob/index.js: + (*! + * is-glob + * + * Copyright (c) 2014-2017, Jon Schlinkert. + * Released under the MIT License. + *) + +queue-microtask/index.js: + (*! queue-microtask. MIT License. Feross Aboukhadijeh *) + +run-parallel/index.js: + (*! run-parallel. MIT License. Feross Aboukhadijeh *) + +git-url-parse/lib/index.js: + (*! + * buildToken + * Builds OAuth token prefix (helper function) + * + * @name buildToken + * @function + * @param {GitUrl} obj The parsed Git url object. + * @return {String} token prefix + *) + +object-assign/index.js: + (* + object-assign + (c) Sindre Sorhus + @license MIT + *) + +react/cjs/react.production.min.js: + (** @license React v17.0.2 + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + *) + +scheduler/cjs/scheduler.production.min.js: + (** @license React v0.20.2 + * scheduler.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + *) + +react-reconciler/cjs/react-reconciler.production.min.js: + (** @license React v0.26.2 + * react-reconciler.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + *) + +is-windows/index.js: + (*! + * is-windows + * + * Copyright © 2015-2018, Jon Schlinkert. + * Released under the MIT License. + *) +*/ diff --git a/.yarnrc.yml b/.yarnrc.yml new file mode 100644 index 0000000000000..7120e557bd2ab --- /dev/null +++ b/.yarnrc.yml @@ -0,0 +1,16 @@ +enableScripts: false + +nmHoistingLimits: workspaces + +nodeLinker: node-modules + +npmMinimalAgeGate: 10080 + +npmPreapprovedPackages: + - "@electron/*" + +httpProxy: "${HTTP_PROXY:-}" + +httpsProxy: "${HTTPS_PROXY:-}" + +yarnPath: .yarn/releases/yarn-4.12.0.cjs diff --git a/BUILD.gn b/BUILD.gn index d1bd7ee29daf6..ba316192bd689 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1,13 +1,15 @@ import("//build/config/locales.gni") import("//build/config/ui.gni") import("//build/config/win/manifest.gni") +import("//components/os_crypt/sync/features.gni") import("//components/spellcheck/spellcheck_build_features.gni") import("//content/public/app/mac_helpers.gni") +import("//content/public/common/features.gni") import("//extensions/buildflags/buildflags.gni") import("//pdf/features.gni") -import("//ppapi/buildflags/buildflags.gni") import("//printing/buildflags/buildflags.gni") import("//testing/test.gni") +import("//third_party/electron_node/node.gni") import("//third_party/ffmpeg/ffmpeg_options.gni") import("//tools/generate_library_loader/generate_library_loader.gni") import("//tools/grit/grit_rule.gni") @@ -15,27 +17,35 @@ import("//tools/grit/repack.gni") import("//tools/v8_context_snapshot/v8_context_snapshot.gni") import("//v8/gni/snapshot_toolchain.gni") import("build/asar.gni") +import("build/electron_paks.gni") import("build/extract_symbols.gni") +import("build/js2c_toolchain.gni") import("build/npm.gni") import("build/templated_file.gni") import("build/tsc.gni") import("build/webpack/webpack.gni") import("buildflags/buildflags.gni") -import("electron_paks.gni") import("filenames.auto.gni") import("filenames.gni") import("filenames.hunspell.gni") +import("filenames.libcxx.gni") +import("filenames.libcxxabi.gni") if (is_mac) { import("//build/config/mac/rules.gni") import("//third_party/icu/config.gni") - import("//ui/gl/features.gni") import("//v8/gni/v8.gni") import("build/rules.gni") + + assert( + mac_deployment_target == "12.0", + "Chromium has updated the mac_deployment_target, please update this assert and flag this as a breaking change (docs/breaking-changes.md)") } if (is_linux) { import("//build/config/linux/pkg_config.gni") + import("//electron/build/linux/strip_binary.gni") + import("//tools/generate_stubs/rules.gni") pkg_config("gio_unix") { packages = [ "gio-unix-2.0" ] @@ -47,10 +57,44 @@ if (is_linux) { "gdk-pixbuf-2.0", ] } -} -declare_args() { - use_prebuilt_v8_context_snapshot = false + generate_library_loader("libnotify_loader") { + name = "LibNotifyLoader" + output_h = "libnotify_loader.h" + output_cc = "libnotify_loader.cc" + header = "" + config = ":libnotify_config" + + functions = [ + "notify_is_initted", + "notify_init", + "notify_get_server_caps", + "notify_get_server_info", + "notify_notification_new", + "notify_notification_add_action", + "notify_notification_set_image_from_pixbuf", + "notify_notification_set_timeout", + "notify_notification_set_urgency", + "notify_notification_set_hint", + "notify_notification_show", + "notify_notification_close", + ] + } + + # Generates headers which contain stubs for extracting function ptrs + # from the gtk library. Function signatures for which stubs are + # required should be declared in the sig files. + generate_stubs("electron_gtk_stubs") { + sigs = [ + "shell/browser/ui/electron_gdk.sigs", + "shell/browser/ui/electron_gdk_pixbuf.sigs", + ] + extra_header = "shell/browser/ui/electron_gtk.fragment" + output_name = "electron_gtk_stubs" + public_deps = [ "//ui/gtk:gtk_config" ] + logging_function = "LogNoop()" + logging_include = "ui/gtk/log_noop.h" + } } branding = read_file("shell/app/BRANDING.json", "json") @@ -58,6 +102,30 @@ electron_project_name = branding.project_name electron_product_name = branding.product_name electron_mac_bundle_id = branding.mac_bundle_id +if (override_electron_version != "") { + electron_version = override_electron_version +} else { + # When building from a source code tarball there is no git tag available and + # builders must explicitly pass override_electron_version in gn args. + # + # Resolve the real locations of packed-refs and HEAD via git so that this + # also works when electron/ is a `git worktree` (where .git is a file, not a + # directory, and GN's read_file cannot follow the gitdir indirection). + electron_git_ref_paths = + exec_script("script/get-git-ref-paths.py", [], "list lines") + + # This read_file call will assert if there is no git information, without it + # gn will generate a malformed build configuration and ninja will get into + # infinite loop. + read_file(electron_git_ref_paths[0], "string") + + # Set electron version from git tag. + electron_version = exec_script("script/get-git-version.py", + [], + "trim string", + electron_git_ref_paths) +} + if (is_mas_build) { assert(is_mac, "It doesn't make sense to build a MAS build on a non-mac platform") @@ -83,9 +151,28 @@ config("branding") { config("electron_lib_config") { include_dirs = [ "." ] + cflags = [] + if (is_clang && clang_use_chrome_plugins) { + # The plugin is built directly into clang, so there's no need to load it + # dynamically. + cflags += [ + "-Xclang", + "-add-plugin", + "-Xclang", + "blink-gc-plugin", + "-Xclang", + "-plugin-arg-blink-gc-plugin", + "-Xclang", + "check-directory=electron/shell/", + "-Xclang", + "-plugin-arg-blink-gc-plugin", + "-Xclang", + "check-directory=gin/", + ] + } } -# We geneate the definitions twice here, once in //electron/electron.d.ts +# We generate the definitions twice here, once in //electron/electron.d.ts # and once in $target_gen_dir # The one in $target_gen_dir is used for the actual TSC build later one # and the one in //electron/electron.d.ts is used by your IDE (vscode) @@ -98,15 +185,6 @@ npm_action("build_electron_definitions") { outputs = [ "$target_gen_dir/tsc/typings/electron.d.ts" ] } -webpack_build("electron_asar_bundle") { - deps = [ ":build_electron_definitions" ] - - inputs = auto_filenames.asar_bundle_deps - - config_file = "//electron/build/webpack/webpack.config.asar.js" - out_file = "$target_gen_dir/js2c/asar_bundle.js" -} - webpack_build("electron_browser_bundle") { deps = [ ":build_electron_definitions" ] @@ -152,32 +230,75 @@ webpack_build("electron_isolated_renderer_bundle") { out_file = "$target_gen_dir/js2c/isolated_bundle.js" } +webpack_build("electron_node_bundle") { + deps = [ ":build_electron_definitions" ] + + inputs = auto_filenames.node_bundle_deps + + config_file = "//electron/build/webpack/webpack.config.node.js" + out_file = "$target_gen_dir/js2c/node_init.js" +} + +webpack_build("electron_utility_bundle") { + deps = [ ":build_electron_definitions" ] + + inputs = auto_filenames.utility_bundle_deps + + config_file = "//electron/build/webpack/webpack.config.utility.js" + out_file = "$target_gen_dir/js2c/utility_init.js" +} + +webpack_build("electron_preload_realm_bundle") { + deps = [ ":build_electron_definitions" ] + + inputs = auto_filenames.preload_realm_bundle_deps + + config_file = "//electron/build/webpack/webpack.config.preload_realm.js" + out_file = "$target_gen_dir/js2c/preload_realm_bundle.js" +} + action("electron_js2c") { deps = [ - ":electron_asar_bundle", ":electron_browser_bundle", ":electron_isolated_renderer_bundle", + ":electron_node_bundle", + ":electron_preload_realm_bundle", ":electron_renderer_bundle", ":electron_sandboxed_renderer_bundle", + ":electron_utility_bundle", ":electron_worker_bundle", + "//third_party/electron_node:node_js2c($electron_js2c_toolchain)", ] sources = [ - "$target_gen_dir/js2c/asar_bundle.js", "$target_gen_dir/js2c/browser_init.js", "$target_gen_dir/js2c/isolated_bundle.js", + "$target_gen_dir/js2c/node_init.js", + "$target_gen_dir/js2c/preload_realm_bundle.js", "$target_gen_dir/js2c/renderer_init.js", "$target_gen_dir/js2c/sandbox_bundle.js", + "$target_gen_dir/js2c/utility_init.js", "$target_gen_dir/js2c/worker_init.js", ] - inputs = sources + [ "//third_party/electron_node/tools/js2c.py" ] + inputs = sources outputs = [ "$root_gen_dir/electron_natives.cc" ] script = "build/js2c.py" - args = [ rebase_path("//third_party/electron_node") ] + - rebase_path(outputs, root_build_dir) + - rebase_path(sources, root_build_dir) + out_dir = + get_label_info(":anything($electron_js2c_toolchain)", "root_out_dir") + args = [ + rebase_path("$out_dir/node_js2c"), + rebase_path("$root_gen_dir"), + ] + rebase_path(outputs, root_gen_dir) + + rebase_path(sources, root_gen_dir) +} + +action("generate_config_gypi") { + outputs = [ "$root_gen_dir/config.gypi" ] + script = "script/generate-config-gypi.py" + inputs = [ "//third_party/electron_node/configure.py" ] + args = rebase_path(outputs) + [ target_cpu ] } target_gen_default_app_js = "$target_gen_dir/js/default_app" @@ -217,18 +338,39 @@ asar("default_app_asar") { } grit("resources") { - source = "electron_resources.grd" + source = "build/electron_resources.grd" outputs = [ "grit/electron_resources.h", "electron_resources.pak", ] + if (translate_genders) { + outputs += [ + "electron_resources_MASCULINE.pak", + "electron_resources_FEMININE.pak", + "electron_resources_NEUTER.pak", + ] + } + + foreach(locale, all_chrome_locales) { + outputs += [ "electron_strings_$locale.pak" ] + if (translate_genders) { + outputs += [ + "electron_strings_${locale}_MASCULINE.pak", + "electron_strings_${locale}_FEMININE.pak", + "electron_strings_${locale}_NEUTER.pak", + ] + } + } # Mojo manifest overlays are generated. grit_flags = [ "-E", "target_gen_dir=" + rebase_path(target_gen_dir, root_build_dir), ] + if (translate_genders) { + grit_flags += [ "--translate-genders" ] + } deps = [ ":copy_shell_devtools_discovery_page" ] @@ -240,72 +382,62 @@ copy("copy_shell_devtools_discovery_page") { outputs = [ "$target_gen_dir/shell_devtools_discovery_page.html" ] } -if (is_linux) { - generate_library_loader("libnotify_loader") { - name = "LibNotifyLoader" - output_h = "libnotify_loader.h" - output_cc = "libnotify_loader.cc" - header = "" - config = ":libnotify_config" +npm_action("electron_version_args") { + script = "generate-version-json" - functions = [ - "notify_is_initted", - "notify_init", - "notify_get_server_caps", - "notify_get_server_info", - "notify_notification_new", - "notify_notification_add_action", - "notify_notification_set_image_from_pixbuf", - "notify_notification_set_timeout", - "notify_notification_set_urgency", - "notify_notification_set_hint_string", - "notify_notification_show", - "notify_notification_close", - ] - } + outputs = [ "$target_gen_dir/electron_version.args" ] + + args = rebase_path(outputs) + [ "$electron_version" ] + + inputs = [ "script/generate-version-json.js" ] } -source_set("manifests") { - sources = [ - "//electron/shell/app/manifests.cc", - "//electron/shell/app/manifests.h", - ] +templated_file("electron_version_header") { + deps = [ ":electron_version_args" ] - include_dirs = [ "//electron" ] + template = "build/templates/electron_version.tmpl" + output = "$target_gen_dir/electron_version.h" - deps = [ - "//electron/shell/common/api:mojo", - "//printing/buildflags", - "//services/service_manager/public/cpp", - ] + args_files = get_target_outputs(":electron_version_args") } -npm_action("electron_version_args") { - script = "generate-version-json" +templated_file("electron_win_rc") { + deps = [ ":electron_version_args" ] - outputs = [ "$target_gen_dir/electron_version.args" ] + template = "build/templates/electron_rc.tmpl" + output = "$target_gen_dir/win-resources/electron.rc" - args = rebase_path(outputs) + args_files = get_target_outputs(":electron_version_args") +} - inputs = [ - "ELECTRON_VERSION", - "script/generate-version-json.js", +copy("electron_win_resource_files") { + sources = [ + "shell/browser/resources/win/electron.ico", + "shell/browser/resources/win/resource.h", ] + outputs = [ "$target_gen_dir/win-resources/{{source_file_part}}" ] } -templated_file("electron_version_header") { +templated_file("electron_version_file") { deps = [ ":electron_version_args" ] - template = "build/templates/electron_version.tmpl" - output = "$target_gen_dir/electron_version.h" + template = "build/templates/version_string.tmpl" + output = "$root_build_dir/version" args_files = get_target_outputs(":electron_version_args") } +group("electron_win32_resources") { + public_deps = [ + ":electron_win_rc", + ":electron_win_resource_files", + ] +} + action("electron_fuses") { script = "build/fuses/build.py" - inputs = [ "build/fuses/fuses.json" ] + inputs = [ "build/fuses/fuses.json5" ] outputs = [ "$target_gen_dir/fuses.h", @@ -315,9 +447,28 @@ action("electron_fuses") { args = rebase_path(outputs) } +action("electron_generate_node_defines") { + script = "build/generate_node_defines.py" + + inputs = [ + "//third_party/electron_node/src/tracing/trace_event_common.h", + "//third_party/electron_node/src/tracing/trace_event.h", + "//third_party/electron_node/src/util.h", + ] + + outputs = [ + "$target_gen_dir/push_and_undef_node_defines.h", + "$target_gen_dir/pop_node_defines.h", + ] + + args = [ rebase_path(target_gen_dir) ] + rebase_path(inputs) +} + source_set("electron_lib") { - configs += [ "//v8:external_startup_data" ] - configs += [ "//third_party/electron_node:node_internals" ] + configs += [ + "//v8:external_startup_data", + "//third_party/electron_node:node_external_config", + ] public_configs = [ ":branding", @@ -326,83 +477,111 @@ source_set("electron_lib") { deps = [ ":electron_fuses", + ":electron_generate_node_defines", ":electron_js2c", ":electron_version_header", - ":manifests", ":resources", "buildflags", "chromium_src:chrome", "chromium_src:chrome_spellchecker", - "shell/common/api:mojo", + "shell/common:mojo", + "shell/common:plugin", + "shell/common:web_contents_utility", + "shell/services/node/public/mojom", "//base:base_static", "//base/allocator:buildflags", + "//build/util:chromium_git_revision", + "//chrome:strings", "//chrome/app:command_ids", "//chrome/app/resources:platform_locale_settings", + "//chrome/common/notifications", + "//components/autofill/core/common:features", "//components/certificate_transparency", + "//components/compose:buildflags", + "//components/embedder_support:user_agent", + "//components/heap_profiling/multi_process", + "//components/input", "//components/language/core/browser", + "//components/memory_system", "//components/net_log", "//components/network_hints/browser", "//components/network_hints/common:mojo_bindings", "//components/network_hints/renderer", "//components/network_session_configurator/common", + "//components/omnibox/browser:buildflags", + "//components/os_crypt/async/browser", + "//components/os_crypt/async/browser:key_provider_interface", + "//components/os_crypt/sync", "//components/pref_registry", "//components/prefs", + "//components/security_state/content", + "//components/tracing:tracing_metrics", "//components/upload_list", "//components/user_prefs", "//components/viz/host", "//components/viz/service", + "//components/webrtc", "//content/public/browser", "//content/public/child", - "//content/public/common:service_names", "//content/public/gpu", "//content/public/renderer", "//content/public/utility", "//device/bluetooth", "//device/bluetooth/public/cpp", "//gin", - "//media/blink:blink", + "//gpu/ipc/client", "//media/capture/mojom:video_capture", "//media/mojo/mojom", + "//media/mojo/mojom:web_speech_recognition", "//net:extras", "//net:net_resources", - "//ppapi/host", - "//ppapi/proxy", - "//ppapi/shared_impl", "//printing/buildflags", + "//services/device/public/cpp/bluetooth", "//services/device/public/cpp/geolocation", + "//services/device/public/cpp/hid", "//services/device/public/mojom", "//services/proxy_resolver:lib", "//services/video_capture/public/mojom:constants", "//services/viz/privileged/mojom/compositing", + "//services/viz/public/mojom", "//skia", "//third_party/blink/public:blink", "//third_party/blink/public:blink_devtools_inspector_resources", + "//third_party/blink/public/platform/media", "//third_party/boringssl", - "//third_party/electron_node:node_lib", + "//third_party/electron_node:libnode", + "//third_party/highway:libhwy", "//third_party/inspector_protocol:crdtp", "//third_party/leveldatabase", "//third_party/libyuv", "//third_party/webrtc_overrides:webrtc_component", "//third_party/widevine/cdm:headers", "//third_party/zlib/google:zip", + "//ui/base:ozone_buildflags", "//ui/base/idle", + "//ui/compositor", "//ui/events:dom_keycode_converter", "//ui/gl", "//ui/native_theme", "//ui/shell_dialogs", "//ui/views", + "//ui/views/controls/webview", "//v8", "//v8:v8_libplatform", ] + if (v8_use_external_startup_data && use_v8_context_snapshot) { + deps += [ ":mksnapshot_checksum_gen" ] + } + public_deps = [ "//base", "//base:i18n", "//content/public/app", + "//ui/base/unowned_user_data", ] include_dirs = [ - "chromium_src", ".", "$target_gen_dir", @@ -411,7 +590,10 @@ source_set("electron_lib") { "//third_party/blink/renderer", ] - defines = [ "V8_DEPRECATION_WARNINGS" ] + defines = [ + "BLINK_MOJO_IMPL=1", + "V8_DEPRECATION_WARNINGS", + ] libs = [] if (is_linux) { @@ -419,9 +601,14 @@ source_set("electron_lib") { } if (!is_mas_build) { - deps += [ "//components/crash/core/app" ] + deps += [ + "//components/crash/core/app", + "//components/crash/core/browser", + ] } + deps += [ "//electron/build/config:generate_mas_config" ] + sources = filenames.lib_sources if (is_win) { sources += filenames.lib_sources_win @@ -450,14 +637,18 @@ source_set("electron_lib") { ] } - if (is_linux) { - deps += [ "//components/crash/content/browser" ] - } - if (is_mac) { + # Disable C++ modules to resolve linking error when including MacOS SDK + # headers from third_party/electron_node/deps/uv/include/uv/darwin.h + # TODO(samuelmaddock): consider revisiting this in the future + use_libcxx_modules = false + deps += [ + "//components/os_crypt/async/browser:keychain_key_provider", + "//components/os_crypt/common:keychain_password_mac", "//components/remote_cocoa/app_shim", - "//content/common:mac_helpers", + "//components/remote_cocoa/browser", + "//content/browser:mac_helpers", "//ui/accelerated_widget_mac", ] @@ -466,6 +657,7 @@ source_set("electron_lib") { } frameworks = [ + "AuthenticationServices.framework", "AVFoundation.framework", "Carbon.framework", "LocalAuthentication.framework", @@ -475,8 +667,11 @@ source_set("electron_lib") { "SecurityInterface.framework", "ServiceManagement.framework", "StoreKit.framework", + "UserNotifications.framework", ] + weak_frameworks = [ "QuickLookThumbnailing.framework" ] + sources += [ "shell/browser/ui/views/autofill_popup_view.cc", "shell/browser/ui/views/autofill_popup_view.h", @@ -484,7 +679,6 @@ source_set("electron_lib") { if (is_mas_build) { sources += [ "shell/browser/api/electron_api_app_mas.mm" ] sources -= [ "shell/browser/auto_updater_mac.mm" ] - defines += [ "MAS_BUILD" ] sources -= [ "shell/app/electron_crash_reporter_client.cc", "shell/app/electron_crash_reporter_client.h", @@ -508,22 +702,32 @@ source_set("electron_lib") { } } if (is_linux) { + libs = [ "xshmfence" ] deps += [ + ":electron_gtk_stubs", ":libnotify_loader", "//build/config/linux/gtk", + "//components/crash/content/browser", + "//components/os_crypt/async/browser:freedesktop_secret_key_provider", + "//components/os_crypt/async/browser:posix_key_provider", + "//components/os_crypt/async/browser:secret_portal_key_provider", "//dbus", "//device/bluetooth", + "//third_party/crashpad/crashpad/client", + "//ui/base/ime/linux", "//ui/events/devices/x11", "//ui/events/platform/x11", - "//ui/gtk", - "//ui/views/controls/webview", + "//ui/gtk:gtk_config", + "//ui/linux:display_server_utils", + "//ui/linux:linux_ui", + "//ui/linux:linux_ui_factory", "//ui/wm", ] - if (use_x11) { + if (ozone_platform_x11) { sources += filenames.lib_sources_linux_x11 - deps += [ - "//ui/gfx/x", - "//ui/gtk/x", + public_deps += [ + "//ui/base/x", + "//ui/ozone/platform/x11", ] } configs += [ ":gio_unix" ] @@ -532,28 +736,23 @@ source_set("electron_lib") { "GLIB_DISABLE_DEPRECATION_WARNINGS", ] - sources += filenames.lib_sources_nss sources += [ - "shell/browser/ui/gtk/app_indicator_icon.cc", - "shell/browser/ui/gtk/app_indicator_icon.h", - "shell/browser/ui/gtk/app_indicator_icon_menu.cc", - "shell/browser/ui/gtk/app_indicator_icon_menu.h", - "shell/browser/ui/gtk/gtk_status_icon.cc", - "shell/browser/ui/gtk/gtk_status_icon.h", - "shell/browser/ui/gtk/menu_util.cc", - "shell/browser/ui/gtk/menu_util.h", - "shell/browser/ui/gtk/status_icon.cc", - "shell/browser/ui/gtk/status_icon.h", + "shell/browser/certificate_manager_model.cc", + "shell/browser/certificate_manager_model.h", + "shell/browser/linux/x11_util.cc", + "shell/browser/linux/x11_util.h", "shell/browser/ui/gtk_util.cc", "shell/browser/ui/gtk_util.h", ] } if (is_win) { libs += [ "dwmapi.lib" ] + sources += [ "shell/common/asar/archive_win.cc" ] deps += [ + "//components/app_launch_prefetch", "//components/crash/core/app:crash_export_thunks", - "//ui/native_theme:native_theme_browser", - "//ui/views/controls/webview", + "//components/os_crypt/async/browser:dpapi_key_provider", + "//third_party/libxml:xml_writer", "//ui/wm", "//ui/wm/public", ] @@ -564,70 +763,20 @@ source_set("electron_lib") { } if (enable_plugins) { - deps += [ "chromium_src:plugins" ] - sources += [ - "shell/renderer/pepper_helper.cc", - "shell/renderer/pepper_helper.h", - ] - } - - if (enable_run_as_node) { - sources += [ - "shell/app/node_main.cc", - "shell/app/node_main.h", - ] - } - - if (enable_osr) { - sources += [ - "shell/browser/osr/osr_host_display_client.cc", - "shell/browser/osr/osr_host_display_client.h", - "shell/browser/osr/osr_render_widget_host_view.cc", - "shell/browser/osr/osr_render_widget_host_view.h", - "shell/browser/osr/osr_video_consumer.cc", - "shell/browser/osr/osr_video_consumer.h", - "shell/browser/osr/osr_view_proxy.cc", - "shell/browser/osr/osr_view_proxy.h", - "shell/browser/osr/osr_web_contents_view.cc", - "shell/browser/osr/osr_web_contents_view.h", - ] - if (is_mac) { - sources += [ - "shell/browser/osr/osr_host_display_client_mac.mm", - "shell/browser/osr/osr_web_contents_view_mac.mm", - ] - } - deps += [ - "//components/viz/service", - "//services/viz/public/mojom", - "//ui/compositor", - ] - } - - if (enable_desktop_capturer) { - if (is_component_build && !is_linux) { - # On windows the implementation relies on unexported - # DxgiDuplicatorController class. On macOS the implementation - # relies on unexported webrtc::GetWindowOwnerPid method. - deps += [ "//third_party/webrtc/modules/desktop_capture" ] - } - sources += [ - "shell/browser/api/electron_api_desktop_capturer.cc", - "shell/browser/api/electron_api_desktop_capturer.h", - ] - } - - if (enable_views_api) { sources += [ - "shell/browser/api/views/electron_api_image_view.cc", - "shell/browser/api/views/electron_api_image_view.h", + "shell/browser/electron_plugin_info_host_impl.cc", + "shell/browser/electron_plugin_info_host_impl.h", + "shell/common/plugin_info.cc", + "shell/common/plugin_info.h", ] } - if (enable_basic_printing) { + if (enable_printing) { sources += [ - "shell/browser/printing/print_preview_message_handler.cc", - "shell/browser/printing/print_preview_message_handler.h", + "shell/browser/printing/print_view_manager_electron.cc", + "shell/browser/printing/print_view_manager_electron.h", + "shell/browser/printing/printing_utils.cc", + "shell/browser/printing/printing_utils.h", "shell/renderer/printing/print_render_frame_helper_delegate.cc", "shell/renderer/printing/print_render_frame_helper_delegate.h", ] @@ -635,6 +784,9 @@ source_set("electron_lib") { "//chrome/services/printing/public/mojom", "//components/printing/common:mojo_interfaces", ] + if (is_mac) { + deps += [ "//chrome/services/mac_notifications/public/mojom" ] + } } if (enable_electron_extensions) { @@ -644,10 +796,13 @@ source_set("electron_lib") { "shell/common/extensions/api", "shell/common/extensions/api:extensions_features", "//chrome/browser/resources:component_extension_resources", - "//components/update_client:update_client", + "//components/guest_view/common:mojom", + "//components/update_client", "//components/zoom", "//extensions/browser", - "//extensions/browser:core_api_provider", + "//extensions/browser/api:api_provider", + "//extensions/browser/mime_handler:stream_info", + "//extensions/browser/updater", "//extensions/common", "//extensions/common:core_api_provider", "//extensions/renderer", @@ -664,27 +819,44 @@ source_set("electron_lib") { } if (enable_pdf_viewer) { deps += [ + "//chrome/browser/resources/pdf:resources", + "//chrome/browser/ui:browser_element_identifiers", "//components/pdf/browser", + "//components/pdf/browser:interceptors", + "//components/pdf/common:constants", + "//components/pdf/common:util", "//components/pdf/renderer", - "//pdf:pdf_ppapi", + "//components/user_education/webui", + "//pdf", + "//pdf:content_restriction", ] sources += [ - "shell/browser/electron_pdf_web_contents_helper_client.cc", - "shell/browser/electron_pdf_web_contents_helper_client.h", + "shell/browser/electron_pdf_document_helper_client.cc", + "shell/browser/electron_pdf_document_helper_client.h", + "shell/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_api.cc", + "shell/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_api.h", ] } sources += get_target_outputs(":electron_fuses") - if (is_win && enable_win_dark_mode_window_ui) { - sources += [ - "shell/browser/win/dark_mode.cc", - "shell/browser/win/dark_mode.h", - ] - libs += [ "uxtheme.lib" ] + if (allow_runtime_configurable_key_storage) { + defines += [ "ALLOW_RUNTIME_CONFIGURABLE_KEY_STORAGE" ] } } +action("mksnapshot_checksum_gen") { + script = "build/checksum_header.py" + + outputs = [ "$target_gen_dir/snapshot_checksum.h" ] + inputs = [ "$root_out_dir/$v8_context_snapshot_filename" ] + args = rebase_path(inputs) + + args += rebase_path(outputs) + + deps = [ "//tools/v8_context_snapshot" ] +} + electron_paks("packed_resources") { if (is_mac) { output_dir = "$root_gen_dir/electron_repack" @@ -699,21 +871,11 @@ if (is_mac) { electron_helper_name = "$electron_product_name Helper" electron_login_helper_name = "$electron_product_name Login Helper" electron_framework_version = "A" - electron_version = read_file("ELECTRON_VERSION", "trim string") mac_xib_bundle_data("electron_xibs") { sources = [ "shell/common/resources/mac/MainMenu.xib" ] } - action("fake_v8_context_snapshot_generator") { - script = "build/fake_v8_context_snapshot_generator.py" - args = [ - rebase_path("$root_out_dir/$v8_context_snapshot_filename"), - rebase_path("$root_out_dir/fake/$v8_context_snapshot_filename"), - ] - outputs = [ "$root_out_dir/fake/$v8_context_snapshot_filename" ] - } - bundle_data("electron_framework_resources") { public_deps = [ ":packed_resources" ] sources = [] @@ -724,13 +886,8 @@ if (is_mac) { if (v8_use_external_startup_data) { public_deps += [ "//v8" ] if (use_v8_context_snapshot) { - if (use_prebuilt_v8_context_snapshot) { - sources += [ "$root_out_dir/fake/$v8_context_snapshot_filename" ] - public_deps += [ ":fake_v8_context_snapshot_generator" ] - } else { - sources += [ "$root_out_dir/$v8_context_snapshot_filename" ] - public_deps += [ "//tools/v8_context_snapshot" ] - } + sources += [ "$root_out_dir/$v8_context_snapshot_filename" ] + public_deps += [ "//tools/v8_context_snapshot" ] } else { sources += [ "$root_out_dir/snapshot_blob.bin" ] } @@ -743,49 +900,40 @@ if (is_mac) { sources = [] public_deps = [] sources += [ "$root_out_dir/libffmpeg.dylib" ] - public_deps += [ "//third_party/ffmpeg:ffmpeg" ] + public_deps += [ "//third_party/ffmpeg" ] outputs = [ "{{bundle_contents_dir}}/Libraries/{{source_file_part}}" ] } } else { group("electron_framework_libraries") { } } - if (use_egl) { - # Add the ANGLE .dylibs in the Libraries directory of the Framework. - bundle_data("electron_angle_binaries") { - sources = [ - "$root_out_dir/egl_intermediates/libEGL.dylib", - "$root_out_dir/egl_intermediates/libGLESv2.dylib", - ] - outputs = [ "{{bundle_contents_dir}}/Libraries/{{source_file_part}}" ] - public_deps = [ "//ui/gl:angle_library_copy" ] - } - # Add the SwiftShader .dylibs in the Libraries directory of the Framework. - bundle_data("electron_swiftshader_binaries") { - sources = [ - "$root_out_dir/egl_intermediates/libswiftshader_libEGL.dylib", - "$root_out_dir/egl_intermediates/libswiftshader_libGLESv2.dylib", - "$root_out_dir/vk_intermediates/libvk_swiftshader.dylib", - "$root_out_dir/vk_intermediates/vk_swiftshader_icd.json", - ] - outputs = [ "{{bundle_contents_dir}}/Libraries/{{source_file_part}}" ] - public_deps = [ - "//ui/gl:swiftshader_egl_library_copy", - "//ui/gl:swiftshader_vk_library_copy", - ] - } + # Add the ANGLE .dylibs in the Libraries directory of the Framework. + bundle_data("electron_angle_binaries") { + sources = [ + "$root_out_dir/egl_intermediates/libEGL.dylib", + "$root_out_dir/egl_intermediates/libGLESv2.dylib", + ] + outputs = [ "{{bundle_contents_dir}}/Libraries/{{source_file_part}}" ] + public_deps = [ "//ui/gl:angle_library_copy" ] } + + # Add the SwiftShader .dylibs in the Libraries directory of the Framework. + bundle_data("electron_swiftshader_binaries") { + sources = [ + "$root_out_dir/vk_intermediates/libvk_swiftshader.dylib", + "$root_out_dir/vk_intermediates/vk_swiftshader_icd.json", + ] + outputs = [ "{{bundle_contents_dir}}/Libraries/{{source_file_part}}" ] + public_deps = [ "//ui/gl:swiftshader_vk_library_copy" ] + } + group("electron_angle_library") { - if (use_egl) { - deps = [ ":electron_angle_binaries" ] - } + deps = [ ":electron_angle_binaries" ] } group("electron_swiftshader_library") { - if (use_egl) { - deps = [ ":electron_swiftshader_binaries" ] - } + deps = [ ":electron_swiftshader_binaries" ] } bundle_data("electron_crashpad_helper") { @@ -798,7 +946,7 @@ if (is_mac) { if (is_asan) { # crashpad_handler requires the ASan runtime at its @executable_path. sources += [ "$root_out_dir/libclang_rt.asan_osx_dynamic.dylib" ] - public_deps += [ "//build/config/sanitizers:copy_asan_runtime" ] + public_deps += [ "//build/config/sanitizers:copy_sanitizer_runtime" ] } } @@ -822,6 +970,7 @@ if (is_mac) { ":electron_framework_resources", ":electron_swiftshader_library", ":electron_xibs", + "//third_party/electron_node:libnode", ] if (!is_mas_build) { deps += [ ":electron_crashpad_helper" ] @@ -835,11 +984,7 @@ if (is_mac) { include_dirs = [ "." ] sources = filenames.framework_sources - frameworks = [] - - if (enable_osr) { - frameworks += [ "IOSurface.framework" ] - } + frameworks = [ "IOSurface.framework" ] ldflags = [ "-Wl,-install_name,@rpath/$output_name.framework/$output_name", @@ -855,6 +1000,13 @@ if (is_mac) { "@executable_path/../../../../../..", ] } + + # For component ffmpeg under non-component build, it is linked from + # @loader_path. However the ffmpeg.dylib is moved to a different place + # when generating app bundle, and we should change to link from @rpath. + if (is_component_ffmpeg && !is_component_build) { + ldflags += [ "-Wcrl,installnametool,-change,@loader_path/libffmpeg.dylib,@rpath/libffmpeg.dylib" ] + } } template("electron_helper_app") { @@ -862,13 +1014,19 @@ if (is_mac) { assert(defined(invoker.helper_name_suffix)) output_name = electron_helper_name + invoker.helper_name_suffix - deps = [ ":electron_framework+link" ] + deps = [ + ":electron_framework+link", + "//electron/build/config:generate_mas_config", + ] if (!is_mas_build) { deps += [ "//sandbox/mac:seatbelt" ] } defines = [ "HELPER_EXECUTABLE" ] - sources = filenames.app_sources - sources += [ "shell/common/electron_constants.cc" ] + sources = [ + "shell/app/electron_main_mac.cc", + "shell/app/uv_stdio_fix.cc", + "shell/app/uv_stdio_fix.h", + ] include_dirs = [ "." ] info_plist = "shell/renderer/resources/mac/Info.plist" extra_substitutions = @@ -886,7 +1044,17 @@ if (is_mac) { } } - foreach(helper_params, content_mac_helpers) { + # Electron defines its own plugin helper (using CHILD_EMBEDDER_FIRST + 1) to + # allow loading of unsigned or third-party-signed libraries. + _electron_plugin_helper_params = [ + "plugin", + ".plugin", + " (Plugin)", + ] + electron_mac_helpers = + content_mac_helpers + [ _electron_plugin_helper_params ] + + foreach(helper_params, electron_mac_helpers) { _helper_target = helper_params[0] _helper_bundle_id = helper_params[1] _helper_suffix = helper_params[2] @@ -939,7 +1107,7 @@ if (is_mac) { ":stripped_squirrel_framework", ] - foreach(helper_params, content_mac_helpers) { + foreach(helper_params, electron_mac_helpers) { sources += [ "$root_out_dir/${electron_helper_name}${helper_params[2]}.app" ] public_deps += [ ":electron_helper_app_${helper_params[0]}" ] @@ -966,14 +1134,14 @@ if (is_mac) { action("electron_app_lproj_dirs") { outputs = [] - foreach(locale, locales_as_mac_outputs) { + foreach(locale, locales_as_apple_outputs) { outputs += [ "$target_gen_dir/app_infoplist_strings/$locale.lproj" ] } script = "build/mac/make_locale_dirs.py" args = rebase_path(outputs) } - foreach(locale, locales_as_mac_outputs) { + foreach(locale, locales_as_apple_outputs) { bundle_data("electron_app_strings_${locale}_bundle_data") { sources = [ "$target_gen_dir/app_infoplist_strings/$locale.lproj" ] outputs = [ "{{bundle_resources_dir}}/$locale.lproj" ] @@ -982,7 +1150,7 @@ if (is_mac) { } group("electron_app_strings_bundle_data") { public_deps = [] - foreach(locale, locales_as_mac_outputs) { + foreach(locale, locales_as_apple_outputs) { public_deps += [ ":electron_app_strings_${locale}_bundle_data" ] } } @@ -999,19 +1167,32 @@ if (is_mac) { outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ] } + asar_hashed_info_plist("electron_app_plist") { + keys = [ "DEFAULT_APP_ASAR_HEADER_SHA" ] + hash_targets = [ ":default_app_asar_header_hash" ] + plist_file = "shell/browser/resources/mac/Info.plist" + } + mac_app_bundle("electron_app") { output_name = electron_product_name - sources = filenames.app_sources - sources += [ "shell/common/electron_constants.cc" ] + sources = [ + "shell/app/electron_main_mac.cc", + "shell/app/uv_stdio_fix.cc", + "shell/app/uv_stdio_fix.h", + ] include_dirs = [ "." ] deps = [ ":electron_app_framework_bundle_data", + ":electron_app_plist", ":electron_app_resources", + ":electron_fuses", + "//electron/build/config:generate_mas_config", + "//electron/buildflags", ] if (is_mas_build) { deps += [ ":electron_login_helper_app" ] } - info_plist = "shell/browser/resources/mac/Info.plist" + info_plist_target = ":electron_app_plist" extra_substitutions = [ "ELECTRON_BUNDLE_ID=$electron_mac_bundle_id", "ELECTRON_VERSION=$electron_version", @@ -1030,7 +1211,7 @@ if (is_mac) { deps = [ ":electron_framework" ] } - foreach(helper_params, content_mac_helpers) { + foreach(helper_params, electron_mac_helpers) { _helper_target = helper_params[0] _helper_bundle_id = helper_params[1] _helper_suffix = helper_params[2] @@ -1049,21 +1230,18 @@ if (is_mac) { deps = [ ":electron_app" ] } - extract_symbols("swiftshader_egl_syms") { - binary = "$root_out_dir/libswiftshader_libEGL.dylib" + extract_symbols("egl_syms") { + binary = "$root_out_dir/libEGL.dylib" symbol_dir = "$root_out_dir/breakpad_symbols" - dsym_file = "$root_out_dir/libswiftshader_libEGL.dylib.dSYM/Contents/Resources/DWARF/libswiftshader_libEGL.dylib" - deps = - [ "//third_party/swiftshader/src/OpenGL/libEGL:swiftshader_libEGL" ] + dsym_file = "$root_out_dir/libEGL.dylib.dSYM/Contents/Resources/DWARF/libEGL.dylib" + deps = [ "//third_party/angle:libEGL" ] } - extract_symbols("swiftshader_gles_syms") { - binary = "$root_out_dir/libswiftshader_libGLESv2.dylib" + extract_symbols("gles_syms") { + binary = "$root_out_dir/libGLESv2.dylib" symbol_dir = "$root_out_dir/breakpad_symbols" - dsym_file = "$root_out_dir/libswiftshader_libGLESv2.dylib.dSYM/Contents/Resources/DWARF/libswiftshader_libGLESv2.dylib" - deps = [ - "//third_party/swiftshader/src/OpenGL/libGLESv2:swiftshader_libGLESv2", - ] + dsym_file = "$root_out_dir/libGLESv2.dylib.dSYM/Contents/Resources/DWARF/libGLESv2.dylib" + deps = [ "//third_party/angle:libGLESv2" ] } extract_symbols("crashpad_handler_syms") { @@ -1075,17 +1253,17 @@ if (is_mac) { group("electron_symbols") { deps = [ + ":egl_syms", ":electron_app_syms", ":electron_framework_syms", - ":swiftshader_egl_syms", - ":swiftshader_gles_syms", + ":gles_syms", ] if (!is_mas_build) { deps += [ ":crashpad_handler_syms" ] } - foreach(helper_params, content_mac_helpers) { + foreach(helper_params, electron_mac_helpers) { _helper_target = helper_params[0] deps += [ ":electron_helper_syms_${_helper_target}" ] } @@ -1107,27 +1285,38 @@ if (is_mac) { executable("electron_app") { output_name = electron_project_name - sources = filenames.app_sources + if (is_win) { + sources = [ "shell/app/electron_main_win.cc" ] + } else if (is_linux) { + sources = [ + "shell/app/electron_main_linux.cc", + "shell/app/uv_stdio_fix.cc", + "shell/app/uv_stdio_fix.h", + ] + } include_dirs = [ "." ] deps = [ ":default_app_asar", ":electron_app_manifest", ":electron_lib", + ":electron_win32_resources", ":packed_resources", "//components/crash/core/app", "//content:sandbox_helper_win", "//electron/buildflags", + "//third_party/electron_node:libnode", "//ui/strings", ] data = [] + data_deps = [] data += [ "$root_out_dir/resources.pak" ] data += [ "$root_out_dir/chrome_100_percent.pak" ] if (enable_hidpi) { data += [ "$root_out_dir/chrome_200_percent.pak" ] } - foreach(locale, locales) { + foreach(locale, platform_pak_locales) { data += [ "$root_out_dir/locales/$locale.pak" ] } @@ -1136,22 +1325,25 @@ if (is_mac) { } if (use_v8_context_snapshot) { - public_deps = [ "//tools/v8_context_snapshot:v8_context_snapshot" ] + public_deps = [ "//tools/v8_context_snapshot" ] + } + + if (is_linux) { + data_deps += [ "//components/crash/core/app:chrome_crashpad_handler" ] } if (is_win) { sources += [ - # TODO: we should be generating our .rc files more like how chrome does - "shell/browser/resources/win/electron.rc", + "$target_gen_dir/win-resources/electron.rc", "shell/browser/resources/win/resource.h", ] deps += [ - "//components/browser_watcher:browser_watcher_client", + "//chrome/app:exit_code_watcher", "//components/crash/core/app:run_as_crashpad_handler", ] - ldflags = [] + ldflags = [ "/DELAYLOAD:ffmpeg.dll" ] libs = [ "comctl32.lib", @@ -1165,9 +1357,17 @@ if (is_mac) { "//build/config/win:delayloads", ] - if (target_cpu == "arm64") { - configs -= [ "//build/config/win:cfi_linker" ] - ldflags += [ "/guard:cf,nolongjmp" ] + if (current_cpu == "x86") { + # Set the initial stack size to 0.5MiB, instead of the 1.5MiB needed by + # Chrome's main thread. This saves significant memory on threads (like + # those in the Windows thread pool, and others) whose stack size we can + # only control through this setting. Because Chrome's main thread needs + # a minimum 1.5 MiB stack, the main thread (in 32-bit builds only) uses + # fibers to switch to a 1.5 MiB stack before running any other code. + ldflags += [ "/STACK:0x80000" ] + } else { + # Increase the initial stack size. The default is 1MB, this is 8MB. + ldflags += [ "/STACK:0x800000" ] } # This is to support renaming of electron.exe. node-gyp has hard-coded @@ -1194,6 +1394,10 @@ if (is_mac) { if (!is_component_build && is_component_ffmpeg) { configs += [ "//build/config/gcc:rpath_for_built_shared_libraries" ] } + + if (is_linux) { + deps += [ "//sandbox/linux:chrome_sandbox" ] + } } } @@ -1212,51 +1416,28 @@ if (is_mac) { deps = [ ":electron_app" ] } - extract_symbols("swiftshader_egl_symbols") { - binary = "$root_out_dir/swiftshader/libEGL$_target_shared_library_suffix" + extract_symbols("egl_symbols") { + binary = "$root_out_dir/libEGL$_target_shared_library_suffix" symbol_dir = "$root_out_dir/breakpad_symbols" - deps = - [ "//third_party/swiftshader/src/OpenGL/libEGL:swiftshader_libEGL" ] + deps = [ "//third_party/angle:libEGL" ] } - extract_symbols("swiftshader_gles_symbols") { - binary = - "$root_out_dir/swiftshader/libGLESv2$_target_shared_library_suffix" + extract_symbols("gles_symbols") { + binary = "$root_out_dir/libGLESv2$_target_shared_library_suffix" symbol_dir = "$root_out_dir/breakpad_symbols" - deps = [ - "//third_party/swiftshader/src/OpenGL/libGLESv2:swiftshader_libGLESv2", - ] + deps = [ "//third_party/angle:libGLESv2" ] } group("electron_symbols") { deps = [ + ":egl_symbols", ":electron_app_symbols", - ":swiftshader_egl_symbols", - ":swiftshader_gles_symbols", + ":gles_symbols", ] } } } -test("shell_browser_ui_unittests") { - sources = [ - "//electron/shell/browser/ui/accelerator_util_unittests.cc", - "//electron/shell/browser/ui/run_all_unittests.cc", - ] - - configs += [ ":electron_lib_config" ] - - deps = [ - ":electron_lib", - "//base", - "//base/test:test_support", - "//testing/gmock", - "//testing/gtest", - "//ui/base", - "//ui/strings", - ] -} - template("dist_zip") { _runtime_deps_target = "${target_name}__deps" _runtime_deps_file = @@ -1283,13 +1464,18 @@ template("dist_zip") { "testonly", ]) flatten = false + flatten_relative_to = false if (defined(invoker.flatten)) { flatten = invoker.flatten + if (defined(invoker.flatten_relative_to)) { + flatten_relative_to = invoker.flatten_relative_to + } } args = rebase_path(outputs + [ _runtime_deps_file ], root_build_dir) + [ target_cpu, target_os, "$flatten", + "$flatten_relative_to", ] } } @@ -1311,31 +1497,40 @@ group("licenses") { ] } -copy("electron_version") { - sources = [ "ELECTRON_VERSION" ] - outputs = [ "$root_build_dir/version" ] -} - dist_zip("electron_dist_zip") { data_deps = [ ":electron_app", - ":electron_version", + ":electron_version_file", ":licenses", ] if (is_linux) { + if (is_official_build) { + data_deps += [ + ":strip_chrome_crashpad_handler", + ":strip_chrome_sandbox", + ":strip_electron_binary", + ":strip_libEGL_shlib", + ":strip_libGLESv2_shlib", + ":strip_libffmpeg_shlib", + ":strip_libvk_swiftshader_shlib", + ] + } + data_deps += [ "//sandbox/linux:chrome_sandbox" ] } + deps = data_deps outputs = [ "$root_build_dir/dist.zip" ] } dist_zip("electron_ffmpeg_zip") { data_deps = [ "//third_party/ffmpeg" ] + deps = data_deps outputs = [ "$root_build_dir/ffmpeg.zip" ] } electron_chromedriver_deps = [ ":licenses", - "//chrome/test/chromedriver", + "//chrome/test/chromedriver:chromedriver_server", "//electron/buildflags", ] @@ -1347,6 +1542,7 @@ group("electron_chromedriver") { dist_zip("electron_chromedriver_zip") { testonly = true data_deps = electron_chromedriver_deps + deps = data_deps outputs = [ "$root_build_dir/chromedriver.zip" ] } @@ -1365,6 +1561,17 @@ group("electron_mksnapshot") { dist_zip("electron_mksnapshot_zip") { data_deps = mksnapshot_deps + if (is_linux && is_official_build) { + data_deps += [ + ":strip_libEGL_shlib", + ":strip_libGLESv2_shlib", + ":strip_libffmpeg_shlib", + ":strip_libvk_swiftshader_shlib", + ":strip_mksnapshot_binary", + ":strip_v8_context_snapshot_generator_binary", + ] + } + deps = data_deps outputs = [ "$root_build_dir/mksnapshot.zip" ] } @@ -1375,11 +1582,216 @@ copy("hunspell_dictionaries") { dist_zip("hunspell_dictionaries_zip") { data_deps = [ ":hunspell_dictionaries" ] + deps = data_deps flatten = true outputs = [ "$root_build_dir/hunspell_dictionaries.zip" ] } +copy("libcxx_headers") { + sources = libcxx_headers + libcxx_licenses + [ + "//buildtools/third_party/libc++/__assertion_handler", + "//buildtools/third_party/libc++/__config_site", + ] + outputs = [ "$target_gen_dir/electron_libcxx_include/{{source_root_relative_dir}}/{{source_file_part}}" ] +} + +dist_zip("libcxx_headers_zip") { + data_deps = [ ":libcxx_headers" ] + deps = data_deps + flatten = true + flatten_relative_to = + rebase_path( + "$target_gen_dir/electron_libcxx_include/third_party/libc++/src", + "$root_out_dir") + + outputs = [ "$root_build_dir/libcxx_headers.zip" ] +} + +copy("libcxxabi_headers") { + sources = libcxxabi_headers + libcxxabi_licenses + outputs = [ "$target_gen_dir/electron_libcxxabi_include/{{source_root_relative_dir}}/{{source_file_part}}" ] +} + +dist_zip("libcxxabi_headers_zip") { + data_deps = [ ":libcxxabi_headers" ] + deps = data_deps + flatten = true + flatten_relative_to = rebase_path( + "$target_gen_dir/electron_libcxxabi_include/third_party/libc++abi/src", + "$root_out_dir") + + outputs = [ "$root_build_dir/libcxxabi_headers.zip" ] +} + +action("libcxx_objects_zip") { + deps = [ "//buildtools/third_party/libc++" ] + script = "build/zip_libcxx.py" + outputs = [ "$root_build_dir/libcxx_objects.zip" ] + args = rebase_path(outputs) +} + group("electron") { public_deps = [ ":electron_app" ] } + +##### node_headers + +node_dir = "../third_party/electron_node" +node_headers_dir = "$root_gen_dir/node_headers" + +copy("zlib_headers") { + sources = [ + "$node_dir/deps/zlib/zconf.h", + "$node_dir/deps/zlib/zlib.h", + ] + outputs = [ "$node_headers_dir/include/node/{{source_file_part}}" ] +} + +copy("node_gypi_headers") { + deps = [ ":generate_config_gypi" ] + sources = [ + "$node_dir/common.gypi", + "$root_gen_dir/config.gypi", + ] + outputs = [ "$node_headers_dir/include/node/{{source_file_part}}" ] +} + +action("node_version_header") { + inputs = [ "$node_dir/src/node_version.h" ] + outputs = [ "$node_headers_dir/include/node/node_version.h" ] + script = "script/node/generate_node_version_header.py" + args = rebase_path(inputs) + rebase_path(outputs) + if (node_module_version != "") { + args += [ "$node_module_version" ] + } +} + +action("generate_node_headers") { + deps = [ ":generate_config_gypi" ] + script = "script/node/generate_node_headers.py" + inputs = auto_filenames.node_header_sources + outputs = [ "$root_gen_dir/node_headers.json" ] + args = [ rebase_path("$root_gen_dir") ] +} + +action("tar_node_headers") { + deps = [ ":copy_node_headers" ] + outputs = [ "$root_gen_dir/node_headers.tar.gz" ] + script = "script/tar.py" + args = [ + rebase_path("$root_gen_dir/node_headers"), + rebase_path(outputs[0]), + ] +} + +group("copy_node_headers") { + public_deps = [ + ":generate_node_headers", + ":node_gypi_headers", + ":node_version_header", + ":zlib_headers", + ] +} + +group("node_headers") { + public_deps = [ ":tar_node_headers" ] +} + +group("testing_build") { + public_deps = [ + ":electron_dist_zip", + ":electron_mksnapshot_zip", + ":node_headers", + ] +} + +group("release_build") { + public_deps = [ ":testing_build" ] + if (is_official_build) { + public_deps += [ ":electron_symbols" ] + } + if (is_linux) { + public_deps += [ + ":hunspell_dictionaries_zip", + ":libcxx_headers_zip", + ":libcxx_objects_zip", + ":libcxxabi_headers_zip", + ] + } +} + +if (is_linux && is_official_build) { + strip_binary("strip_electron_binary") { + binary_input = "$root_out_dir/$electron_project_name" + symbol_output = "$root_out_dir/debug/$electron_project_name.debug" + compress_debug_sections = true + deps = [ ":electron_app" ] + } + + strip_binary("strip_chrome_crashpad_handler") { + binary_input = "$root_out_dir/chrome_crashpad_handler" + symbol_output = "$root_out_dir/debug/chrome_crashpad_handler.debug" + compress_debug_sections = true + deps = [ "//components/crash/core/app:chrome_crashpad_handler" ] + } + + strip_binary("strip_chrome_sandbox") { + binary_input = "$root_out_dir/chrome_sandbox" + symbol_output = "$root_out_dir/debug/chrome-sandbox.debug" + compress_debug_sections = true + deps = [ "//sandbox/linux:chrome_sandbox" ] + } + + strip_binary("strip_libEGL_shlib") { + binary_input = "$root_out_dir/libEGL.so" + symbol_output = "$root_out_dir/debug/libEGL.so.debug" + compress_debug_sections = true + deps = [ "//third_party/angle:libEGL" ] + } + + strip_binary("strip_libGLESv2_shlib") { + binary_input = "$root_out_dir/libGLESv2.so" + symbol_output = "$root_out_dir/debug/libGLESv2.so.debug" + compress_debug_sections = true + deps = [ "//third_party/angle:libGLESv2" ] + } + + strip_binary("strip_libffmpeg_shlib") { + binary_input = "$root_out_dir/libffmpeg.so" + symbol_output = "$root_out_dir/debug/libffmpeg.so.debug" + compress_debug_sections = true + deps = [ "//third_party/ffmpeg" ] + } + + strip_binary("strip_libvk_swiftshader_shlib") { + binary_input = "$root_out_dir/libvk_swiftshader.so" + symbol_output = "$root_out_dir/debug/libvk_swiftshader.so.debug" + compress_debug_sections = true + deps = [ "//third_party/swiftshader/src/Vulkan:swiftshader_libvulkan" ] + } + + strip_binary("strip_mksnapshot_binary") { + _binary_path = rebase_path( + get_label_info( + ":v8_context_snapshot_generator($v8_snapshot_toolchain)", + "root_out_dir") + "/mksnapshot", + root_build_dir) + binary_input = "$root_out_dir/$_binary_path" + symbol_output = "$root_out_dir/debug/${_binary_path}.debug" + compress_debug_sections = true + deps = mksnapshot_deps + } + + strip_binary("strip_v8_context_snapshot_generator_binary") { + _binary_path = rebase_path( + get_label_info( + ":v8_context_snapshot_generator($v8_snapshot_toolchain)", + "root_out_dir") + "/v8_context_snapshot_generator", + root_build_dir) + binary_input = "$root_out_dir/$_binary_path" + symbol_output = "$root_out_dir/debug/${_binary_path}.debug" + compress_debug_sections = true + deps = mksnapshot_deps + } +} diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000000000..a5cff94733d89 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,284 @@ +# Electron Development Guide + +## Running node_modules binaries + +**Never use `npx`.** It is considered dangerous because it can silently fetch and execute arbitrary packages from the registry. Always run binaries through one of these safer mechanisms instead: + +1. **Preferred** — spawn the executable directly from `node_modules/.bin/` (or the platform equivalent on Windows). This is what `script/lint.js` does for `oxlint`. +2. **Acceptable** — invoke via `yarn ` or `yarn run `, which resolves to the locally installed version without the registry fallback that `npx` performs. + +This rule applies to shell commands you run yourself and to any scripts you author or modify in this repo. + +## Project Overview + +Electron is a framework for building cross-platform desktop applications using web technologies. It embeds Chromium for rendering and Node.js for backend functionality. + +## Directory Structure + +```text +electron/ # This repo (run `e` commands here) +├── shell/ # Core C++ application code +│ ├── browser/ # Main process implementation (107+ API modules) +│ ├── renderer/ # Renderer process code +│ ├── common/ # Shared code between processes +│ ├── app/ # Application entry points +│ └── services/ # Node.js service integration +├── lib/ # TypeScript/JavaScript library code +│ ├── browser/ # Main process JS (47 API implementations) +│ ├── renderer/ # Renderer process JS +│ └── common/ # Shared JS modules +├── patches/ # Patches for upstream dependencies +│ ├── chromium/ # ~159 patches to Chromium +│ ├── node/ # ~48 patches to Node.js +│ └── ... # Other targets (v8, boringssl, etc.) +├── spec/ # Test suite (1189+ TypeScript test files) +├── docs/ # API documentation and guides +├── build/ # Build configuration +├── script/ # Build and automation scripts +└── chromium_src/ # Chromium source overrides +../ # Parent directory is Chromium source +``` + +## Build Tools Setup + +Electron uses `@electron/build-tools` for development. The `e` command is the primary CLI. + +**Installation:** + +```bash +npm i -g @electron/build-tools +``` + +**Configuration location:** `~/.electron_build_tools/configs/` + +## Essential Commands + +### Configuration Management + +| Command | Purpose | +|---------|---------| +| `e init --root= --bootstrap testing` | Create new build config and sync | +| `e use ` | Switch to a different build configuration | +| `e show current` | Display active configuration name | +| `e show configs` | List all available configurations | + +### Build & Development Loop + +| Command | Purpose | +|---------|---------| +| `e sync` | Fetch/update all source code and apply patches | +| `e sync --3` | Sync with 3-way merge (required for Chromium upgrades) | +| `e build` | Build Electron (runs GN + Ninja) | +| `e build -k 999` | Build and continue on errors (up to 999) | +| `e build -t ` | Build specific target (e.g., `electron:node_headers`) | +| `e start` | Run the built Electron executable | +| `e start --version` | Verify Electron launches and print version | +| `e test` | Run the test suite | +| `e debug` | Run Electron in debugger (lldb on macOS, gdb on Linux) | + +### Patch Management + +| Command | Purpose | +|---------|---------| +| `e patches ` | Export patches for a target (chromium, node, v8, etc.) | +| `e patches all` | Export all patches from all targets | +| `e patches --list-targets` | List available patch targets | + +## Typical Development Workflow + +```bash +# 1. Ensure you're on the right config +e show current + +# 2. Sync to get latest code +e sync + +# 3. Make your changes in shell/ or lib/ or ../ + +# 4. Build +e build + +# 5. Test your changes (Leave the user to do this, don't run these commands unless asked) +e start +e test + +# 6. If you modified patched files in Chromium: +cd .. # Go to Chromium repo +git add +git commit -m "description of change" +cd electron +e patches chromium # Export the patch +``` + +## Patches System + +Electron patches upstream dependencies (Chromium, Node.js, V8, etc.) to add features or modify behavior. + +**How patches work:** + +```text +patches/{target}/*.patch → [e sync --3] → target repo commits + ← [e patches] ← +``` + +**Patch configuration:** `patches/config.json` maps patch directories to target repos. + +**Key rules:** + +- Fix existing patches 99% of the time rather than creating new ones +- Preserve original authorship in TODO comments +- Never change TODO assignees (`TODO(name)` must retain original name) +- Each patch file includes commit message explaining its purpose + +**Creating/modifying patches:** + +1. Make changes in the target repo (e.g., `../` for Chromium) +2. Create a git commit +3. Run `e patches ` to export + +**Fixing patch conflicts on an existing PR:** + +If asked to fix a patch conflict on a branch that already has an open PR, check the PR's failed **Apply Patches** CI run for an `update-patches` artifact before running `e sync` locally. CI has already performed the 3-way merge and exported the resolved patch diff — applying it is much faster than a full local sync. + +```bash +# Find the failed Apply Patches run for the PR and download the artifact +gh run list --repo electron/electron --branch --workflow "Apply Patches" --limit 1 +gh run download --repo electron/electron --name update-patches + +# Apply the CI-generated fix, then push +git am update-patches.patch +git push +``` + +If no artifact exists (e.g. the 3-way merge itself failed), fall back to `e sync --3` and resolve manually. + +## Testing + +**Test location:** `spec/` directory + +**Running tests:** + +```bash +e test # Run full test suite +``` + +**Test frameworks:** Mocha, Chai, Sinon + +## Build Configuration + +**GN build arguments:** Located in `build/args/`: + +- `testing.gn` - Debug/testing builds +- `release.gn` - Release builds +- `all.gn` - Common arguments for all builds + +**Main build file:** `BUILD.gn` + +**Feature flags:** `buildflags/buildflags.gni` + +## Chromium Upgrade Workflow + +When working on the `roller/chromium/main` branch to upgrade Chromium activate the "Electron Chromium Upgrade" skill. + +## Node.js Upgrade Workflow + +When working on the `roller/node/main` branch to upgrade Node.js activate the "Electron Node.js Upgrade" skill. + +## Pull Requests + +PR bodies must always include a `Notes:` section as the **last line** of the body. This is a consumer-facing release note for Electron app developers — describe the user-visible fix or change, not internal implementation details. Use `Notes: none` if there is no user-facing change. + +### PR Labeling (write-access only) + +When the user has write access to `electron/electron`, add these labels when creating PRs: + +**Semver label** — one of: + +- `semver/none` — build changes, refactors, CI, or anything with no end-user impact +- `semver/patch` — backwards-compatible bug fixes +- `semver/minor` — backwards-compatible new functionality +- `semver/major` — incompatible API changes + +**Backport target labels** — add `target/{N}-x-y` for each supported release branch the change should land on. Default policy: + +- **Bug fixes** — backport to all active release lines _except the oldest_ +- **Security fixes** — backport to all active release lines _including the oldest_ +- **Features (semver/minor) and breaking changes (semver/major)** — no backport labels; main-only by default + +To find which release branches are active, check label colors — active `target/*` labels use color `#ad244f`, older/EOL ones use `#ededed`: + +```bash +gh label list --repo electron/electron --search target/ --json name,color --jq '.[] | select(.color == "ad244f") | .name' +``` + +## Code Style + +**C++:** Follows Chromium style, enforced by clang-format +**TypeScript/JavaScript:** [oxlint](https://oxc.rs/docs/guide/usage/linter) configuration in `.oxlintrc.json` + +**Linting:** + +```bash +npm run lint # Run all linters +npm run lint:js # Run oxlint over all JS/TS/MJS sources +npm run lint:clang-format # C++ formatting +npm run lint:api-history # Validate API history YAML blocks in docs +``` + +## Key Files + +| File | Purpose | +|------|---------| +| `BUILD.gn` | Main GN build configuration | +| `DEPS` | Dependency versions and checkout paths | +| `patches/config.json` | Patch target configuration | +| `filenames.gni` | Source file lists by platform | +| `package.json` | Node.js dependencies and scripts | + +## Environment Variables + +| Variable | Purpose | +|----------|---------| +| `GN_EXTRA_ARGS` | Additional GN arguments (useful in CI) | +| `ELECTRON_RUN_AS_NODE=1` | Run Electron as Node.js | + +## Useful Git Commands for Chromium + +```bash +# Find CL that changed a file +cd .. +git log --oneline -10 -- {file} +git blame -L {start},{end} -- {file} + +# Look for Chromium CL reference in commit +git log -1 {commit_sha} # Find "Reviewed-on:" line + +# Find which patch affects a file +grep -l "filename.cc" patches/chromium/*.patch +``` + +## CI/CD + +GitHub Actions workflows in `.github/workflows/`: + +- `build.yml` - Main build workflow +- `pipeline-electron-lint.yml` - Linting +- `pipeline-segment-electron-test.yml` - Testing + +## Common Issues + +**Patch conflict during sync:** + +- Use `e sync --3` for 3-way merge +- Check if file was renamed/moved upstream +- Verify patch is still needed + +**Build error in patched file:** + +- Find the patch: `grep -l "filename" patches/chromium/*.patch` +- Match existing patch style (#if 0 guards, BUILDFLAG conditionals, etc.) + +**Remote build issues:** + +- Try `e build --no-remote` to build locally +- Check reclient/siso configuration in your build config diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 0822c140e2cd4..819fb406e6ef1 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -2,8 +2,8 @@ As a member project of the OpenJS Foundation, Electron uses [Contributor Covenant v2.0](https://contributor-covenant.org/version/2/0/code_of_conduct) as their code of conduct. The full text is included [below](#contributor-covenant-code-of-conduct) in English, and translations are available from the Contributor Covenant organisation: -- [contributor-covenant.org/translations](https://www.contributor-covenant.org/translations) -- [github.com/ContributorCovenant](https://github.com/ContributorCovenant/contributor_covenant/tree/release/content/version/2/0) +* [contributor-covenant.org/translations](https://www.contributor-covenant.org/translations) +* [github.com/ContributorCovenant](https://github.com/ContributorCovenant/contributor_covenant/tree/release/content/version/2/0) ## Contributor Covenant Code of Conduct @@ -125,8 +125,8 @@ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. -Community Impact Guidelines were inspired by [Mozilla's code of conduct -enforcement ladder](https://github.com/mozilla/diversity). +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/inclusion). [homepage]: https://www.contributor-covenant.org diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1802b9c7fa80d..7199e7b0caebd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,7 +12,7 @@ propose changes to this document in a pull request. ## [Issues](https://electronjs.org/docs/development/issues) -Issues are created [here](https://github.com/electron/electron/issues/new). +Issues are created [here](https://github.com/electron/electron/issues/new/choose). * [How to Contribute in Issues](https://electronjs.org/docs/development/issues#how-to-contribute-in-issues) * [Asking for General Help](https://electronjs.org/docs/development/issues#asking-for-general-help) @@ -22,13 +22,13 @@ Issues are created [here](https://github.com/electron/electron/issues/new). ### Issue Closure -Bug reports will be closed if the issue has been inactive and the latest affected version no longer receives support. At the moment, Electron maintains its three latest major versions, with a new major version being released every 12 weeks. (For more information on Electron's release cadence, see [this blog post](https://electronjs.org/blog/12-week-cadence).) +Bug reports will be closed if the issue has been inactive and the latest affected version no longer receives support. At the moment, Electron maintains its three latest major versions, with a new major version being released every 8 weeks. (For more information on Electron's release cadence, see [this blog post](https://electronjs.org/blog/8-week-cadence).) _If an issue has been closed and you still feel it's relevant, feel free to ping a maintainer or add a comment!_ ### Languages -We accept issues in *any* language. +We accept issues in _any_ language. When an issue is posted in a language besides English, it is acceptable and encouraged to post an English-translated copy as a reply. Anyone may post the translated reply. In most cases, a quick pass through translation software is sufficient. @@ -36,7 +36,7 @@ Having the original text _as well as_ the translation can help mitigate translat Responses to posted issues may or may not be in the original language. -**Please note** that using non-English as an attempt to circumvent our [Code of Conduct](https://github.com/electron/electron/blob/master/CODE_OF_CONDUCT.md) will be an immediate, and possibly indefinite, ban from the project. +**Please note** that using non-English as an attempt to circumvent our [Code of Conduct](https://github.com/electron/electron/blob/main/CODE_OF_CONDUCT.md) will be an immediate, and possibly indefinite, ban from the project. ## [Pull Requests](https://electronjs.org/docs/development/pull-requests) @@ -60,6 +60,18 @@ dependencies, and tools contained in the `electron/electron` repository. * [Step 11: Landing](https://electronjs.org/docs/development/pull-requests#step-11-landing) * [Continuous Integration Testing](https://electronjs.org/docs/development/pull-requests#continuous-integration-testing) +### Dependencies Upgrades Policy + +Dependencies in Electron's `package.json` or `yarn.lock` files should only be altered by maintainers. For security reasons, we will not accept PRs that alter our `package.json` or `yarn.lock` files. We invite contributors to make requests updating these files in our issue tracker. If the change is significantly complicated, draft PRs are welcome, with the understanding that these PRs will be closed in favor of a duplicate PR submitted by an Electron maintainer. + +## AI Tool Policy + + + +If you use AI tools in any way to contribute to our project, please read our [AI Tool Policy](https://github.com/electron/governance/blob/main/policy/ai.md). Unreviewed AI-generated contributions waste maintainer time and we kindly decline them. + +> The short version: **there must be a human in the loop**. You are responsible for reviewing, understanding, and being able to explain your contributions. AI assistance doesn't change that, and unreviewed AI-generated content will be declined. + ## Style Guides See [Coding Style](https://electronjs.org/docs/development/coding-style) for information about which standards Electron adheres to in different parts of its codebase. @@ -67,4 +79,4 @@ See [Coding Style](https://electronjs.org/docs/development/coding-style) for inf ## Further Reading For more in-depth guides on developing Electron, see -[/docs/development](/docs/development/README.md) +[/docs/development](/docs/development/README.md). diff --git a/DEPS b/DEPS index dcb73e7560bac..210bd075d5a16 100644 --- a/DEPS +++ b/DEPS @@ -1,39 +1,34 @@ -gclient_gn_args_file = 'src/build/config/gclient_args.gni' -gclient_gn_args = [ - 'build_with_chromium', - 'checkout_android', - 'checkout_android_native_support', - 'checkout_libaom', - 'checkout_nacl', - 'checkout_pgo_profiles', - 'checkout_oculus_sdk', - 'checkout_openxr', - 'checkout_google_benchmark', - 'mac_xcode_version', -] +gclient_gn_args_from = 'src' vars = { 'chromium_version': - '3a75ada69d1ac06d6903a2c981ab90a8162f1ba0', + '149.0.7798.0', 'node_version': - 'v14.15.1', + 'v24.15.0', 'nan_version': - '2c4ee8a32a299eada3cd6e468bbd0a473bfea96d', + '675cefebca42410733da8a454c8d9391fcebfbc2', 'squirrel.mac_version': - 'a3a5b3f03b824441c014893b18f99a103b2603e9', + '0e5d146ba13101a1302d59ea6e6e0b3cace4ae38', + 'reactiveobjc_version': + '74ab5baccc6f7202c8ac69a8d1e152c29dc1ea76', + 'mantle_version': + '2a8e2123a3931038179ee06105c9e6ec336b12ea', + 'engflow_reclient_configs_version': + '955335c30a752e9ef7bff375baab5e0819b6c00d', 'pyyaml_version': '3.12', - 'requests_version': 'e4d59bedfd3c7f4f254f4f5d036587bcd8152458', 'chromium_git': 'https://chromium.googlesource.com', 'electron_git': 'https://github.com/electron', 'nodejs_git': 'https://github.com/nodejs', - 'requests_git': 'https://github.com/kennethreitz', 'yaml_git': 'https://github.com/yaml', 'squirrel_git': 'https://github.com/Squirrel', - - # KEEP IN SYNC WITH utils.js FILE - 'yarn_version': '1.15.2', + 'reactiveobjc_git': 'https://github.com/ReactiveCocoa', + 'mantle_git': 'https://github.com/Mantle', + 'engflow_git': 'https://github.com/EngFlow', + + # The path of the sysroots.json file. + 'sysroots_json_path': 'electron/script/sysroots.json', # To be able to build clean Chromium from sources. 'apply_patches': True, @@ -50,24 +45,20 @@ vars = { # It's only needed to parse the native tests configurations. 'checkout_pyyaml': False, - # Python "requests" module is used for releases only. - 'checkout_requests': False, + # Can be used to disable the sysroot hooks. + 'install_sysroot': True, + + 'use_rts': False, 'mac_xcode_version': 'default', + 'generate_location_tags': False, + # To allow running hooks without parsing the DEPS tree 'process_deps': True, - # It is always needed for normal Electron builds, - # but might be impossible for custom in-house builds. - 'download_external_binaries': True, - 'checkout_nacl': False, - 'checkout_libaom': - True, - 'checkout_oculus_sdk': - False, 'checkout_openxr': False, 'build_with_chromium': @@ -76,8 +67,6 @@ vars = { False, 'checkout_android_native_support': False, - 'checkout_google_benchmark': - False, 'checkout_clang_tidy': True, } @@ -95,25 +84,25 @@ deps = { 'url': (Var("nodejs_git")) + '/node.git@' + (Var("node_version")), 'condition': 'checkout_node and process_deps', }, - 'src/electron/vendor/pyyaml': { + 'src/third_party/pyyaml': { 'url': (Var("yaml_git")) + '/pyyaml.git@' + (Var("pyyaml_version")), 'condition': 'checkout_pyyaml and process_deps', }, - 'src/electron/vendor/requests': { - 'url': Var('requests_git') + '/requests.git' + '@' + Var('requests_version'), - 'condition': 'checkout_requests and process_deps', - }, 'src/third_party/squirrel.mac': { 'url': Var("squirrel_git") + '/Squirrel.Mac.git@' + Var("squirrel.mac_version"), 'condition': 'process_deps', }, 'src/third_party/squirrel.mac/vendor/ReactiveObjC': { - 'url': 'https://github.com/ReactiveCocoa/ReactiveObjC.git@74ab5baccc6f7202c8ac69a8d1e152c29dc1ea76', + 'url': Var("reactiveobjc_git") + '/ReactiveObjC.git@' + Var("reactiveobjc_version"), 'condition': 'process_deps' }, 'src/third_party/squirrel.mac/vendor/Mantle': { - 'url': 'https://github.com/Mantle/Mantle.git@78d3966b3c331292ea29ec38661b25df0a245948', + 'url': Var("mantle_git") + '/Mantle.git@' + Var("mantle_version"), 'condition': 'process_deps', + }, + 'src/third_party/engflow-reclient-configs': { + 'url': Var("engflow_git") + '/reclient-configs.git@' + Var("engflow_reclient_configs_version"), + 'condition': 'process_deps' } } @@ -157,37 +146,65 @@ hooks = [ 'src/electron/patches/mtime-cache.json', ], }, - { - 'name': 'electron_external_binaries', - 'pattern': 'src/electron/script/update-external-binaries.py', - 'condition': 'download_external_binaries', - 'action': [ - 'python3', - 'src/electron/script/update-external-binaries.py', - ], - }, { 'name': 'electron_npm_deps', 'pattern': 'src/electron/package.json', 'action': [ 'python3', '-c', - 'import os, subprocess; os.chdir(os.path.join("src", "electron")); subprocess.check_call(["python", "script/lib/npx.py", "yarn@' + (Var("yarn_version")) + '", "install", "--frozen-lockfile"]);', + 'import os, subprocess; os.chdir(os.path.join("src", "electron")); subprocess.check_call(["node", ".yarn/releases/yarn-4.12.0.cjs", "install", "--immutable"]);', ], }, { - 'name': 'setup_requests', - 'pattern': 'src/electron', - 'condition': 'checkout_requests and process_deps', - 'action': [ - 'python3', - '-c', - 'import os, subprocess; os.chdir(os.path.join("src", "electron", "vendor", "requests")); subprocess.check_call(["python", "setup.py", "build"]);', - ], + 'name': 'sysroot_arm', + 'pattern': '.', + 'condition': 'install_sysroot and checkout_linux and checkout_arm', + 'action': ['python3', 'src/build/linux/sysroot_scripts/install-sysroot.py', + '--sysroots-json-path=' + Var('sysroots_json_path'), + '--arch=arm'], + }, + { + 'name': 'sysroot_arm64', + 'pattern': '.', + 'condition': 'install_sysroot and checkout_linux and checkout_arm64', + 'action': ['python3', 'src/build/linux/sysroot_scripts/install-sysroot.py', + '--sysroots-json-path=' + Var('sysroots_json_path'), + '--arch=arm64'], + }, + { + 'name': 'sysroot_x86', + 'pattern': '.', + 'condition': 'install_sysroot and checkout_linux and (checkout_x86 or checkout_x64)', + 'action': ['python3', 'src/build/linux/sysroot_scripts/install-sysroot.py', + '--sysroots-json-path=' + Var('sysroots_json_path'), + '--arch=x86'], + }, + { + 'name': 'sysroot_mips', + 'pattern': '.', + 'condition': 'install_sysroot and checkout_linux and checkout_mips', + 'action': ['python3', 'src/build/linux/sysroot_scripts/install-sysroot.py', + '--sysroots-json-path=' + Var('sysroots_json_path'), + '--arch=mips'], + }, + { + 'name': 'sysroot_mips64', + 'pattern': '.', + 'condition': 'install_sysroot and checkout_linux and checkout_mips64', + 'action': ['python3', 'src/build/linux/sysroot_scripts/install-sysroot.py', + '--sysroots-json-path=' + Var('sysroots_json_path'), + '--arch=mips64el'], + }, + { + 'name': 'sysroot_x64', + 'pattern': '.', + 'condition': 'install_sysroot and checkout_linux and checkout_x64', + 'action': ['python3', 'src/build/linux/sysroot_scripts/install-sysroot.py', + '--sysroots-json-path=' + Var('sysroots_json_path'), + '--arch=x64'], }, ] recursedeps = [ 'src', - 'src/third_party/squirrel.mac', ] diff --git a/ELECTRON_VERSION b/ELECTRON_VERSION deleted file mode 100644 index 973a773ef37d4..0000000000000 --- a/ELECTRON_VERSION +++ /dev/null @@ -1 +0,0 @@ -13.0.0-nightly.20201119 \ No newline at end of file diff --git a/LICENSE b/LICENSE index 96c37c5f7fa66..536d54efc3fd3 100644 --- a/LICENSE +++ b/LICENSE @@ -1,3 +1,4 @@ +Copyright (c) Electron contributors Copyright (c) 2013-2020 GitHub Inc. Permission is hereby granted, free of charge, to any person obtaining diff --git a/README.md b/README.md index 5b9ff57c30b5a..cf69aaa75182d 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,21 @@ [![Electron Logo](https://electronjs.org/images/electron-logo.svg)](https://electronjs.org) -[![CircleCI Build Status](https://circleci.com/gh/electron/electron/tree/master.svg?style=shield)](https://circleci.com/gh/electron/electron/tree/master) -[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/4lggi9dpjc1qob7k/branch/master?svg=true)](https://ci.appveyor.com/project/electron-bot/electron-ljo26/branch/master) -[![devDependency Status](https://david-dm.org/electron/electron/dev-status.svg)](https://david-dm.org/electron/electron?type=dev) -[![Electron Discord Invite](https://img.shields.io/discord/745037351163527189?color=%237289DA&label=chat&logo=discord&logoColor=white)](https://discord.com/invite/electron) +[![GitHub Actions Build Status](https://github.com/electron/electron/actions/workflows/build.yml/badge.svg)](https://github.com/electron/electron/actions/workflows/build.yml) +[![Electron Discord Invite](https://img.shields.io/discord/745037351163527189?color=%237289DA&label=chat&logo=discord&logoColor=white)](https://discord.gg/electronjs) -:memo: Available Translations: 🇨🇳 🇹🇼 🇧🇷 🇪🇸 🇰🇷 🇯🇵 🇷🇺 🇫🇷 🇹🇭 🇳🇱 🇹🇷 🇮🇩 🇺🇦 🇨🇿 🇮🇹 🇵🇱. -View these docs in other languages at [electron/i18n](https://github.com/electron/i18n/tree/master/content/). +:memo: Available Translations: 🇨🇳 🇧🇷 🇪🇸 🇯🇵 🇷🇺 🇫🇷 🇺🇸 🇩🇪. +View these docs in other languages on our [Crowdin](https://crowdin.com/project/electron) project. The Electron framework lets you write cross-platform desktop applications using JavaScript, HTML and CSS. It is based on [Node.js](https://nodejs.org/) and -[Chromium](https://www.chromium.org) and is used by the [Atom -editor](https://github.com/atom/atom) and many other [apps](https://electronjs.org/apps). +[Chromium](https://www.chromium.org) and is used by the +[Visual Studio Code](https://github.com/Microsoft/vscode/) and many other [apps](https://electronjs.org/apps). -Follow [@ElectronJS](https://twitter.com/electronjs) on Twitter for important +Follow [@electronjs](https://twitter.com/electronjs) on Twitter for important announcements. This project adheres to the Contributor Covenant -[code of conduct](https://github.com/electron/electron/tree/master/CODE_OF_CONDUCT.md). +[code of conduct](https://github.com/electron/electron/tree/main/CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to [coc@electronjs.org](mailto:coc@electronjs.org). @@ -28,43 +26,36 @@ The preferred method is to install Electron as a development dependency in your app: ```sh -npm install electron --save-dev [--save-exact] +npm install electron --save-dev ``` -The `--save-exact` flag is recommended for Electron prior to version 2, as it does not follow semantic -versioning. As of version 2.0.0, Electron follows semver, so you don't need `--save-exact` flag. For info on how to manage Electron versions in your apps, see +For more installation options and troubleshooting tips, see +[installation](docs/tutorial/installation.md). For info on how to manage Electron versions in your apps, see [Electron versioning](docs/tutorial/electron-versioning.md). -For more installation options and troubleshooting tips, see -[installation](docs/tutorial/installation.md). +## Platform support + +Each Electron release provides binaries for macOS, Windows, and Linux. -## Quick start & Electron Fiddle +* macOS (Monterey and up): Electron provides 64-bit Intel and Apple Silicon / ARM binaries for macOS. +* Windows (Windows 10 and up): Electron provides `ia32` (`x86`), `x64` (`amd64`), and `arm64` binaries for Windows. Windows on ARM support was added in Electron 5.0.8. Support for Windows 7, 8 and 8.1 was [removed in Electron 23, in line with Chromium's Windows deprecation policy](https://www.electronjs.org/blog/windows-7-to-8-1-deprecation-notice). +* Linux: The prebuilt binaries of Electron are built on Ubuntu 22.04. They have also been verified to work on: + * Ubuntu 18.04 and newer + * Fedora 32 and newer + * Debian 10 and newer + +## Electron Fiddle Use [`Electron Fiddle`](https://github.com/electron/fiddle) to build, run, and package small Electron experiments, to see code examples for all of Electron's APIs, and to try out different versions of Electron. It's designed to make the start of your journey with Electron easier. -Alternatively, clone and run the -[electron/electron-quick-start](https://github.com/electron/electron-quick-start) -repository to see a minimal Electron app in action: - -```sh -git clone https://github.com/electron/electron-quick-start -cd electron-quick-start -npm install -npm start -``` - ## Resources for learning Electron -- [electronjs.org/docs](https://electronjs.org/docs) - All of Electron's documentation -- [electron/fiddle](https://github.com/electron/fiddle) - A tool to build, run, and package small Electron experiments -- [electron/electron-quick-start](https://github.com/electron/electron-quick-start) - A very basic starter Electron app -- [electronjs.org/community#boilerplates](https://electronjs.org/community#boilerplates) - Sample starter apps created by the community -- [electron/simple-samples](https://github.com/electron/simple-samples) - Small applications with ideas for taking them further -- [electron/electron-api-demos](https://github.com/electron/electron-api-demos) - An Electron app that teaches you how to use Electron -- [hokein/electron-sample-apps](https://github.com/hokein/electron-sample-apps) - Small demo apps for the various Electron APIs +* [electronjs.org/docs](https://electronjs.org/docs) - All of Electron's documentation +* [electron/fiddle](https://github.com/electron/fiddle) - A tool to build, run, and package small Electron experiments +* [electronjs.org/community#boilerplates](https://electronjs.org/community#boilerplates) - Sample starter apps created by the community ## Programmatic usage @@ -74,7 +65,7 @@ binary. Use this to spawn Electron from Node scripts: ```javascript const electron = require('electron') -const proc = require('child_process') +const proc = require('node:child_process') // will print something similar to /Users/maf/.../Electron console.log(electron) @@ -85,11 +76,15 @@ const child = proc.spawn(electron) ### Mirrors -- [China](https://npm.taobao.org/mirrors/electron) +* [China](https://npmmirror.com/mirrors/electron/) + +See the [Advanced Installation Instructions](https://www.electronjs.org/docs/latest/tutorial/installation#mirror) to learn how to use a custom mirror. -## Documentation Translations +## Documentation translations -Find documentation translations in [electron/i18n](https://github.com/electron/i18n). +We crowdsource translations for our documentation via [Crowdin](https://crowdin.com/project/electron). +We currently accept translations for Chinese (Simplified), French, German, Japanese, Portuguese, +Russian, and Spanish. ## Contributing @@ -98,10 +93,10 @@ If you are interested in reporting/fixing issues and contributing directly to th ## Community Info on reporting bugs, getting help, finding third-party tools and sample apps, -and more can be found in the [support document](docs/tutorial/support.md#finding-support). +and more can be found on the [Community page](https://www.electronjs.org/community). ## License -[MIT](https://github.com/electron/electron/blob/master/LICENSE) +[MIT](https://github.com/electron/electron/blob/main/LICENSE) -When using the Electron or other GitHub logos, be sure to follow the [GitHub logo guidelines](https://github.com/logos). +When using Electron logos, make sure to follow [OpenJS Foundation Trademark Policy](https://trademark-policy.openjsf.org/). diff --git a/SECURITY.md b/SECURITY.md index 9e1f55fdae38e..7b1e3dd46a025 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,15 +2,21 @@ The Electron team and community take security bugs in Electron seriously. We appreciate your efforts to responsibly disclose your findings, and will make every effort to acknowledge your contributions. -To report a security issue, email [security@electronjs.org](mailto:security@electronjs.org) and include the word "SECURITY" in the subject line. +To report a security issue, please use the GitHub Security Advisory ["Report a Vulnerability"](https://github.com/electron/electron/security/advisories/new) tab. The Electron team will send a response indicating the next steps in handling your report. After the initial reply to your report, the security team will keep you informed of the progress towards a fix and full announcement, and may ask for additional information or guidance. Report security bugs in third-party modules to the person or team maintaining the module. You can also report a vulnerability through the [npm contact form](https://www.npmjs.com/support) by selecting "I'm reporting a security vulnerability". +## Escalation + +If you do not receive an acknowledgement of your report within 6 business days, or if you cannot find a private security contact for the project, you may escalate to the OpenJS Foundation CNA at `security@lists.openjsf.org`. + +If the project acknowledges your report but does not provide any further response or engagement within 14 days, escalation is also appropriate. + ## The Electron Security Notification Process -For context on Electron's security notification process, please see the [Notifications](https://github.com/electron/governance/blob/master/wg-security/membership-and-notifications.md#notifications) section of the Security WG's [Membership and Notifications](https://github.com/electron/governance/blob/master/wg-security/membership-and-notifications.md) Governance document. +For context on Electron's security notification process, please see the [Notifications](https://github.com/electron/governance/blob/main/wg-security/membership-and-notifications.md#notifications) section of the Security WG's [Membership and Notifications](https://github.com/electron/governance/blob/main/wg-security/membership-and-notifications.md) Governance document. ## Learning More About Security diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 36f7e5fd7705e..0000000000000 --- a/appveyor.yml +++ /dev/null @@ -1,236 +0,0 @@ -# The config expects the following environment variables to be set: -# - "GN_CONFIG" Build type. One of {'testing', 'release'}. -# - "GN_EXTRA_ARGS" Additional gn arguments for a build config, -# e.g. 'target_cpu="x86"' to build for a 32bit platform. -# https://gn.googlesource.com/gn/+/master/docs/reference.md#target_cpu -# Don't forget to set up "NPM_CONFIG_ARCH" and "TARGET_ARCH" accordningly -# if you pass a custom value for 'target_cpu'. -# - "ELECTRON_RELEASE" Set it to '1' upload binaries on success. -# - "NPM_CONFIG_ARCH" E.g. 'x86'. Is used to build native Node.js modules. -# Must match 'target_cpu' passed to "GN_EXTRA_ARGS" and "TARGET_ARCH" value. -# - "TARGET_ARCH" Choose from {'ia32', 'x64', 'arm', 'arm64', 'mips64el'}. -# Is used in some publishing scripts, but does NOT affect the Electron binary. -# Must match 'target_cpu' passed to "GN_EXTRA_ARGS" and "NPM_CONFIG_ARCH" value. -# - "UPLOAD_TO_S3" Set it to '1' upload a release to the S3 bucket. -# Otherwise the release will be uploaded to the Github Releases. -# (The value is only checked if "ELECTRON_RELEASE" is defined.) -# -# The publishing scripts expect access tokens to be defined as env vars, -# but those are not covered here. -# -# AppVeyor docs on variables: -# https://www.appveyor.com/docs/environment-variables/ -# https://www.appveyor.com/docs/build-configuration/#secure-variables -# https://www.appveyor.com/docs/build-configuration/#custom-environment-variables - -# Uncomment these lines to enable RDP -#on_finish: -# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) - -version: 1.0.{build} -build_cloud: electron-16-core -image: vs2019bt-16.6.2 -environment: - GIT_CACHE_PATH: C:\Users\electron\libcc_cache - ELECTRON_OUT_DIR: Default - ELECTRON_ENABLE_STACK_DUMPING: 1 - MOCHA_REPORTER: mocha-multi-reporters - MOCHA_MULTI_REPORTERS: mocha-appveyor-reporter, tap -notifications: - - provider: Webhook - url: https://electron-mission-control.herokuapp.com/rest/appveyor-hook - method: POST - headers: - x-mission-control-secret: - secure: 90BLVPcqhJPG7d24v0q/RRray6W3wDQ8uVQlQjOHaBWkw1i8FoA1lsjr2C/v1dVok+tS2Pi6KxDctPUkwIb4T27u4RhvmcPzQhVpfwVJAG9oNtq+yKN7vzHfg7k/pojEzVdJpQLzeJGcSrZu7VY39Q== - on_build_success: false - on_build_failure: true - on_build_status_changed: false -build_script: - - ps: >- - if(($env:APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME -split "/")[0] -eq ($env:APPVEYOR_REPO_NAME -split "/")[0]) { - Write-warning "Skipping PR build for branch"; Exit-AppveyorBuild - } else { - node script/yarn.js install --frozen-lockfile - - $result = node script/doc-only-change.js --prNumber=$env:APPVEYOR_PULL_REQUEST_NUMBER --prBranch=$env:APPVEYOR_REPO_BRANCH - Write-Output $result - if ($result.ExitCode -eq 0) { - Write-warning "Skipping build for doc only change"; Exit-AppveyorBuild - } - } - - echo "Building $env:GN_CONFIG build" - - git config --global core.longpaths true - - cd .. - - mkdir src - - update_depot_tools.bat - - ps: Move-Item $env:APPVEYOR_BUILD_FOLDER -Destination src\electron - - ps: $env:CHROMIUM_BUILDTOOLS_PATH="$pwd\src\buildtools" - - ps: >- - if ($env:GN_CONFIG -eq 'release') { - $env:GCLIENT_EXTRA_ARGS="$env:GCLIENT_EXTRA_ARGS --custom-var=checkout_requests=True" - } else { - $env:NINJA_STATUS="[%r processes, %f/%t @ %o/s : %es] " - } - - >- - gclient config - --name "src\electron" - --unmanaged - %GCLIENT_EXTRA_ARGS% - "https://github.com/electron/electron" - - ps: >- - if ($env:GN_CONFIG -eq 'release') { - $env:RUN_GCLIENT_SYNC="true" - } else { - cd src\electron - node script\generate-deps-hash.js - $depshash = Get-Content .\.depshash -Raw - $zipfile = "Z:\$depshash.7z" - cd ..\.. - if (Test-Path -Path $zipfile) { - # file exists, unzip and then gclient sync - 7z x -y $zipfile -mmt=30 -aoa - if (-not (Test-Path -Path "src\buildtools")) { - # the zip file must be corrupt - resync - $env:RUN_GCLIENT_SYNC="true" - if ($env:TARGET_ARCH -ne 'ia32') { - # only save on x64/woa to avoid contention saving - $env:SAVE_GCLIENT_SRC="true" - } - } else { - # update external binaries - python src/electron/script/update-external-binaries.py - # update angle - cd src\third_party\angle - git remote set-url origin https://chromium.googlesource.com/angle/angle.git - git fetch - cd ..\..\.. - } - } else { - # file does not exist, gclient sync, then zip - $env:RUN_GCLIENT_SYNC="true" - if ($env:TARGET_ARCH -ne 'ia32') { - # only save on x64/woa to avoid contention saving - $env:SAVE_GCLIENT_SRC="true" - } - } - } - - if "%RUN_GCLIENT_SYNC%"=="true" ( gclient sync --with_branch_heads --with_tags --ignore_locks) - - ps: >- - if ($env:SAVE_GCLIENT_SRC -eq 'true') { - # archive current source for future use - # only run on x64/woa to avoid contention saving - $(7z a $zipfile src -xr!android_webview -xr!electron -xr'!*\.git' -xr!third_party\WebKit\LayoutTests! -xr!third_party\blink\web_tests -xr!third_party\blink\perf_tests -slp -t7z -mmt=30) - if ($LASTEXITCODE -ne 0) { - Write-warning "Could not save source to shared drive; continuing anyway" - } - # build time generation of file gen/angle/angle_commit.h depends on - # third_party/angle/.git - # https://chromium-review.googlesource.com/c/angle/angle/+/2074924 - $(7z a $zipfile src\third_party\angle\.git) - if ($LASTEXITCODE -ne 0) { - Write-warning "Failed to add third_party\angle\.git; continuing anyway" - } - } - - ps: >- - if (Test-Path 'env:RAW_GOMA_AUTH') { - $env:GOMA_OAUTH2_CONFIG_FILE = "$pwd\.goma_oauth2_config" - $env:RAW_GOMA_AUTH | Set-Content $env:GOMA_OAUTH2_CONFIG_FILE - } - - git clone https://github.com/electron/build-tools.git - - cd build-tools - - npm install - - mkdir third_party - - node -e "require('./src/utils/goma.js').downloadAndPrepare()" - - ps: $env:GN_GOMA_FILE = node -e "console.log(require('./src/utils/goma.js').gnFilePath)" - - ps: $env:LOCAL_GOMA_DIR = node -e "console.log(require('./src/utils/goma.js').dir)" - - cd .. - - ps: .\src\electron\script\start-goma.ps1 -gomaDir $env:LOCAL_GOMA_DIR - - cd src - - set BUILD_CONFIG_PATH=//electron/build/args/%GN_CONFIG%.gn - - gn gen out/Default "--args=import(\"%BUILD_CONFIG_PATH%\") import(\"%GN_GOMA_FILE%\") %GN_EXTRA_ARGS% " - - gn check out/Default //electron:electron_lib - - gn check out/Default //electron:electron_app - - gn check out/Default //electron:manifests - - gn check out/Default //electron/shell/common/api:mojo - - if DEFINED GN_GOMA_FILE (ninja -j 300 -C out/Default electron:electron_app) else (ninja -C out/Default electron:electron_app) - - if "%GN_CONFIG%"=="testing" ( python C:\depot_tools\post_build_ninja_summary.py -C out\Default ) - - gn gen out/ffmpeg "--args=import(\"//electron/build/args/ffmpeg.gn\") %GN_EXTRA_ARGS%" - - ninja -C out/ffmpeg electron:electron_ffmpeg_zip - - ninja -C out/Default electron:electron_dist_zip - - ninja -C out/Default shell_browser_ui_unittests - - gn desc out/Default v8:run_mksnapshot_default args > out/Default/mksnapshot_args - - ninja -C out/Default electron:electron_mksnapshot_zip - - cd out\Default - - 7z a mksnapshot.zip mksnapshot_args gen\v8\embedded.S - - cd ..\.. - - ninja -C out/Default electron:hunspell_dictionaries_zip - - ninja -C out/Default electron:electron_chromedriver_zip - - ninja -C out/Default third_party/electron_node:headers - - python %LOCAL_GOMA_DIR%\goma_ctl.py stat - - python electron/build/profile_toolchain.py --output-json=out/Default/windows_toolchain_profile.json - - appveyor PushArtifact out/Default/windows_toolchain_profile.json - - appveyor PushArtifact out/Default/dist.zip - - appveyor PushArtifact out/Default/shell_browser_ui_unittests.exe - - appveyor PushArtifact out/Default/chromedriver.zip - - appveyor PushArtifact out/ffmpeg/ffmpeg.zip - - 7z a node_headers.zip out\Default\gen\node_headers - - appveyor PushArtifact node_headers.zip - - appveyor PushArtifact out/Default/mksnapshot.zip - - appveyor PushArtifact out/Default/hunspell_dictionaries.zip - - appveyor PushArtifact out/Default/electron.lib - - ps: >- - if ($env:GN_CONFIG -eq 'release') { - # Needed for msdia140.dll on 64-bit windows - $env:Path += ";$pwd\third_party\llvm-build\Release+Asserts\bin" - ninja -C out/Default electron:electron_symbols - } - - ps: >- - if ($env:GN_CONFIG -eq 'release') { - python electron\script\zip-symbols.py - appveyor-retry appveyor PushArtifact out/Default/symbols.zip - } else { - # It's useful to have pdb files when debugging testing builds that are - # built on CI. - 7z a pdb.zip out\Default\*.pdb - appveyor-retry appveyor PushArtifact pdb.zip - } - - python electron/script/zip_manifests/check-zip-manifest.py out/Default/dist.zip electron/script/zip_manifests/dist_zip.win.%TARGET_ARCH%.manifest -test_script: - # Workaround for https://github.com/appveyor/ci/issues/2420 - - set "PATH=%PATH%;C:\Program Files\Git\mingw64\libexec\git-core" - - ps: >- - if ((-Not (Test-Path Env:\TEST_WOA)) -And (-Not (Test-Path Env:\ELECTRON_RELEASE)) -And ($env:GN_CONFIG -in "testing", "release")) { - $env:RUN_TESTS="true" - } - - ps: >- - if ($env:RUN_TESTS -eq 'true') { - New-Item .\out\Default\gen\node_headers\Release -Type directory - Copy-Item -path .\out\Default\electron.lib -destination .\out\Default\gen\node_headers\Release\node.lib - } else { - echo "Skipping tests for $env:GN_CONFIG build" - } - - cd electron - # CalculateNativeWinOcclusion is disabled due to https://bugs.chromium.org/p/chromium/issues/detail?id=1139022 - - if "%RUN_TESTS%"=="true" ( echo Running test suite & node script/yarn test -- --trace-uncaught --enable-logging --disable-features=CalculateNativeWinOcclusion ) - - cd .. - - if "%RUN_TESTS%"=="true" ( echo Verifying non proprietary ffmpeg & python electron\script\verify-ffmpeg.py --build-dir out\Default --source-root %cd% --ffmpeg-path out\ffmpeg ) - - echo "About to verify mksnapshot" - - if "%RUN_TESTS%"=="true" ( echo Verifying mksnapshot & python electron\script\verify-mksnapshot.py --build-dir out\Default --source-root %cd% ) - - echo "Done verifying mksnapshot" - - if "%RUN_TESTS%"=="true" ( echo Verifying chromedriver & python electron\script\verify-chromedriver.py --build-dir out\Default --source-root %cd% ) - - echo "Done verifying chromedriver" -deploy_script: - - cd electron - - ps: >- - if (Test-Path Env:\ELECTRON_RELEASE) { - if (Test-Path Env:\UPLOAD_TO_S3) { - Write-Output "Uploading Electron release distribution to s3" - & python script\release\uploaders\upload.py --verbose --upload_to_s3 - } else { - Write-Output "Uploading Electron release distribution to github releases" - & python script\release\uploaders\upload.py --verbose - } - } elseif (Test-Path Env:\TEST_WOA) { - node script/release/ci-release-build.js --job=electron-woa-testing --ci=VSTS --armTest --appveyorJobId=$env:APPVEYOR_JOB_ID $env:APPVEYOR_REPO_BRANCH - } diff --git a/azure-pipelines-arm.yml b/azure-pipelines-arm.yml deleted file mode 100644 index 7df2ab6275d0b..0000000000000 --- a/azure-pipelines-arm.yml +++ /dev/null @@ -1,104 +0,0 @@ -steps: -- task: CopyFiles@2 - displayName: 'Copy Files to: src/electron' - inputs: - TargetFolder: src/electron - -- bash: | - cd src/electron - node script/yarn.js install --frozen-lockfile - displayName: 'Yarn install' - -- bash: | - export ZIP_DEST=$PWD/src/out/Default - echo "##vso[task.setvariable variable=ZIP_DEST]$ZIP_DEST" - mkdir -p $ZIP_DEST - cd src/electron - node script/download-circleci-artifacts.js --buildNum=$CIRCLE_BUILD_NUM --name=dist.zip --dest=$ZIP_DEST - cd $ZIP_DEST - unzip -o dist.zip - displayName: 'Download and unzip dist files for test' - env: - CIRCLE_TOKEN: $(CIRCLECI_TOKEN) - -- bash: | - export FFMPEG_ZIP_DEST=$PWD/src/out/ffmpeg - mkdir -p $FFMPEG_ZIP_DEST - cd src/electron - node script/download-circleci-artifacts.js --buildNum=$CIRCLE_BUILD_NUM --name=ffmpeg.zip --dest=$FFMPEG_ZIP_DEST - cd $FFMPEG_ZIP_DEST - unzip -o ffmpeg.zip - displayName: 'Download and unzip ffmpeg for test' - env: - CIRCLE_TOKEN: $(CIRCLECI_TOKEN) - -- bash: | - export NODE_HEADERS_DEST=$PWD/src/out/Default/gen - mkdir -p $NODE_HEADERS_DEST - cd src/electron - node script/download-circleci-artifacts.js --buildNum=$CIRCLE_BUILD_NUM --name=node_headers.tar.gz --dest=$NODE_HEADERS_DEST - cd $NODE_HEADERS_DEST - tar xzf node_headers.tar.gz - displayName: 'Download and untar node header files for test' - env: - CIRCLE_TOKEN: $(CIRCLECI_TOKEN) - -- bash: | - export CROSS_ARCH_SNAPSHOTS=$PWD/src/out/Default/cross-arch-snapshots - mkdir -p $CROSS_ARCH_SNAPSHOTS - cd src/electron - node script/download-circleci-artifacts.js --buildNum=$CIRCLE_BUILD_NUM --name=cross-arch-snapshots/snapshot_blob.bin --dest=$CROSS_ARCH_SNAPSHOTS - node script/download-circleci-artifacts.js --buildNum=$CIRCLE_BUILD_NUM --name=cross-arch-snapshots/v8_context_snapshot.bin --dest=$CROSS_ARCH_SNAPSHOTS - displayName: 'Download cross arch snapshot files' - env: - CIRCLE_TOKEN: $(CIRCLECI_TOKEN) - -- bash: | - export NATIVE_UNITTESTS_DEST=$PWD/src/out/Default - cd src/electron - node script/download-circleci-artifacts.js --buildNum=$CIRCLE_BUILD_NUM --name=shell_browser_ui_unittests --dest=$NATIVE_UNITTESTS_DEST - chmod +x $NATIVE_UNITTESTS_DEST/shell_browser_ui_unittests - displayName: 'Download native unittest executables' - env: - CIRCLE_TOKEN: $(CIRCLECI_TOKEN) - -- bash: | - cd src - export ELECTRON_OUT_DIR=Default - set npm_config_arch=arm64 - (cd electron && node script/yarn test -- --enable-logging) - displayName: 'Run Electron tests' - timeoutInMinutes: 20 - env: - ELECTRON_DISABLE_SECURITY_WARNINGS: 1 - IGNORE_YARN_INSTALL_ERROR: 1 - ELECTRON_TEST_RESULTS_DIR: junit - -- bash: | - cd src - python electron/script/verify-ffmpeg.py --source-root "$PWD" --build-dir out/Default --ffmpeg-path out/ffmpeg - displayName: Verify non proprietary ffmpeg - timeoutInMinutes: 5 - condition: succeededOrFailed() - -- bash: | - cd src - echo Verify cross arch snapshot - python electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default --snapshot-files-dir $PWD/out/Default/cross-arch-snapshots - displayName: Verify cross arch snapshot - timeoutInMinutes: 5 - condition: succeededOrFailed() - -- task: PublishTestResults@2 - displayName: 'Publish Test Results' - inputs: - testResultsFiles: '*.xml' - - searchFolder: '$(System.DefaultWorkingDirectory)/src/junit/' - - condition: succeededOrFailed() - -- task: mspremier.PostBuildCleanup.PostBuildCleanup-task.PostBuildCleanup@3 - displayName: 'Clean Agent Directories' - - condition: always() diff --git a/azure-pipelines-woa.yml b/azure-pipelines-woa.yml deleted file mode 100644 index 8393941bb4997..0000000000000 --- a/azure-pipelines-woa.yml +++ /dev/null @@ -1,98 +0,0 @@ -steps: -- task: CopyFiles@2 - displayName: 'Copy Files to: src\electron' - inputs: - TargetFolder: src\electron - -- script: | - cd src\electron - node script/yarn.js install --frozen-lockfile - displayName: 'Yarn install' - -- powershell: | - $localArtifactPath = "$pwd\dist.zip" - $serverArtifactPath = "$env:APPVEYOR_URL/buildjobs/$env:APPVEYOR_JOB_ID/artifacts/dist.zip" - Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer $env:APPVEYOR_TOKEN" } - & "${env:ProgramFiles(x86)}\7-Zip\7z.exe" x -osrc\out\Default -y $localArtifactPath - displayName: 'Download and extract dist.zip for test' - env: - APPVEYOR_TOKEN: $(APPVEYOR_TOKEN) - -- powershell: | - $localArtifactPath = "$pwd\src\out\Default\shell_browser_ui_unittests.exe" - $serverArtifactPath = "$env:APPVEYOR_URL/buildjobs/$env:APPVEYOR_JOB_ID/artifacts/shell_browser_ui_unittests.exe" - Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer $env:APPVEYOR_TOKEN" } - displayName: 'Download and extract native test executables for test' - env: - APPVEYOR_TOKEN: $(APPVEYOR_TOKEN) - -- powershell: | - $localArtifactPath = "$pwd\ffmpeg.zip" - $serverArtifactPath = "$env:APPVEYOR_URL/buildjobs/$env:APPVEYOR_JOB_ID/artifacts/ffmpeg.zip" - Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer $env:APPVEYOR_TOKEN" } - & "${env:ProgramFiles(x86)}\7-Zip\7z.exe" x -osrc\out\ffmpeg $localArtifactPath - displayName: 'Download and extract ffmpeg.zip for test' - env: - APPVEYOR_TOKEN: $(APPVEYOR_TOKEN) - -- powershell: | - $localArtifactPath = "$pwd\src\node_headers.zip" - $serverArtifactPath = "$env:APPVEYOR_URL/buildjobs/$env:APPVEYOR_JOB_ID/artifacts/node_headers.zip" - Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer $env:APPVEYOR_TOKEN" } - cd src - & "${env:ProgramFiles(x86)}\7-Zip\7z.exe" x -y node_headers.zip - displayName: 'Download node headers for test' - env: - APPVEYOR_TOKEN: $(APPVEYOR_TOKEN) - -- powershell: | - $localArtifactPath = "$pwd\src\out\Default\electron.lib" - $serverArtifactPath = "$env:APPVEYOR_URL/buildjobs/$env:APPVEYOR_JOB_ID/artifacts/electron.lib" - Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer $env:APPVEYOR_TOKEN" } - displayName: 'Download electron.lib for test' - env: - APPVEYOR_TOKEN: $(APPVEYOR_TOKEN) - -- powershell: | - New-Item src\out\Default\gen\node_headers\Release -Type directory - Copy-Item -path src\out\Default\electron.lib -destination src\out\Default\gen\node_headers\Release\node.lib - displayName: 'Setup node headers' - -- script: | - cd src - set npm_config_nodedir=%cd%\out\Default\gen\node_headers - set npm_config_arch=arm64 - cd electron - # CalculateNativeWinOcclusion is disabled due to https://bugs.chromium.org/p/chromium/issues/detail?id=1139022 - node script/yarn test -- --enable-logging --verbose --disable-features=CalculateNativeWinOcclusion - displayName: 'Run Electron tests' - env: - ELECTRON_OUT_DIR: Default - IGNORE_YARN_INSTALL_ERROR: 1 - ELECTRON_TEST_RESULTS_DIR: junit - MOCHA_MULTI_REPORTERS: 'mocha-junit-reporter, tap' - MOCHA_REPORTER: mocha-multi-reporters - -- task: PublishTestResults@2 - displayName: 'Publish Test Results' - inputs: - testResultsFiles: '*.xml' - searchFolder: '$(System.DefaultWorkingDirectory)/src/junit/' - condition: always() - -- script: | - cd src - echo "Verifying non proprietary ffmpeg" - python electron\script\verify-ffmpeg.py --build-dir out\Default --source-root %cd% --ffmpeg-path out\ffmpeg - displayName: 'Verify ffmpeg' - -- powershell: | - Get-Process | Where Name –Like "electron*" | Stop-Process - Get-Process | Where Name –Like "msedge*" | Stop-Process - displayName: 'Kill processes left running from last test run' - condition: always() - -- powershell: | - Remove-Item -path $env:APPDATA/Electron* -Recurse - displayName: 'Delete user app data directories' - condition: always() diff --git a/build/args/all.gn b/build/args/all.gn index 361ef77ac2523..45939f456f01e 100644 --- a/build/args/all.gn +++ b/build/args/all.gn @@ -1,22 +1,74 @@ is_electron_build = true root_extra_deps = [ "//electron" ] -# Registry of NMVs --> https://github.com/nodejs/node/blob/master/doc/abi_version_registry.json -node_module_version = 87 +# Registry of NMVs --> https://github.com/nodejs/node/blob/main/doc/abi_version_registry.json +node_module_version = 146 v8_promise_internal_field_count = 1 -v8_typed_array_max_size_in_heap = 0 v8_embedder_string = "-electron.0" # TODO: this breaks mksnapshot v8_enable_snapshot_native_code_counters = false +# we use this api +v8_enable_javascript_promise_hooks = true + enable_cdm_host_verification = false -proprietary_codecs = true ffmpeg_branding = "Chrome" +proprietary_codecs = true + +enable_printing = true -enable_basic_printing = true +# Refs https://chromium-review.googlesource.com/c/chromium/src/+/6986517 +# CI is using MacOS 15.5 which doesn't have the required modulemaps. +use_clang_modules = false + +# Removes DLLs from the build, which are only meant to be used for Chromium development. +# See https://github.com/electron/electron/pull/17985 angle_enable_vulkan_validation_layers = false dawn_enable_vulkan_validation_layers = false +# These are disabled because they cause the zip manifest to differ between +# testing and release builds. +# See https://chromium-review.googlesource.com/c/chromium/src/+/2774898. +enable_pseudolocales = false + +# Make application name configurable at runtime for cookie crypto +allow_runtime_configurable_key_storage = true + +# CET shadow stack is incompatible with v8, until v8 is CET compliant +# enabling this flag causes main process crashes where CET is enabled +# Ref: https://source.chromium.org/chromium/chromium/src/+/45fba672185aae233e75d6ddc81ea1e0b30db050:v8/BUILD.gn;l=357 +enable_cet_shadow_stack = false + +# For similar reasons, disable CFI, which is not well supported in V8. +# Chromium doesn't have any problems with this because they do not run +# V8 in the browser process. +# Ref: https://source.chromium.org/chromium/chromium/src/+/45fba672185aae233e75d6ddc81ea1e0b30db050:v8/BUILD.gn;l=281 is_cfi = false + +# TODO: fix this once sysroots have been updated. +use_qt5 = false +use_qt6 = false + +# https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr.md +# TODO(vertedinde): hunt down dangling pointers on Linux +enable_dangling_raw_ptr_checks = false +enable_dangling_raw_ptr_feature_flag = false + +# This flag speeds up the performance of fork/execve on linux systems. +# Ref: https://chromium-review.googlesource.com/c/v8/v8/+/4602858 +v8_enable_private_mapping_fork_optimization = true + +# Expose public V8 symbols for native modules. +v8_expose_public_symbols = true + +# Disable snapshotting a page when printing for its content to be analyzed for +# sensitive content by enterprise users. +enterprise_cloud_content_analysis = false + +# We don't use anything from here, and it causes target collisions +enable_linux_installer = false + +# Disable "Save to Drive" feature in PDF viewer +enable_pdf_save_to_drive = false diff --git a/build/args/ffmpeg.gn b/build/args/ffmpeg.gn index 3ccd99d6be6f1..c25abfd25fa4b 100644 --- a/build/args/ffmpeg.gn +++ b/build/args/ffmpeg.gn @@ -1,7 +1,7 @@ -import("all.gn") +import("//electron/build/args/all.gn") is_component_build = false is_component_ffmpeg = true is_official_build = true -proprietary_codecs = false ffmpeg_branding = "Chromium" enable_dsyms = false +proprietary_codecs = false diff --git a/build/args/native_tests.gn b/build/args/native_tests.gn index 416b9556cc19d..26d6bf3dce4f3 100644 --- a/build/args/native_tests.gn +++ b/build/args/native_tests.gn @@ -1,4 +1,4 @@ -root_extra_deps = [ "//electron/spec" ] +root_extra_deps = [ "//electron/spec-chromium:spec" ] dcheck_always_on = true is_debug = false diff --git a/build/args/release.gn b/build/args/release.gn index e5017f6e16f9c..77351cc181ad9 100644 --- a/build/args/release.gn +++ b/build/args/release.gn @@ -1,14 +1,7 @@ -import("all.gn") +import("//electron/build/args/all.gn") is_component_build = false is_official_build = true -# This may be guarded behind is_chrome_branded alongside -# proprietary_codecs https://webrtc-review.googlesource.com/c/src/+/36321, -# explicitly override here to build OpenH264 encoder/FFmpeg decoder. -# The initialization of the decoder depends on whether ffmpeg has -# been built with H.264 support. -rtc_use_h264 = proprietary_codecs - # By default, Electron builds ffmpeg with proprietary codecs enabled. In order # to facilitate users who don't want to ship proprietary codecs in ffmpeg, or # who have an LGPL requirement to ship ffmpeg as a dynamically linked library, diff --git a/build/args/testing.gn b/build/args/testing.gn index 8f62af6e4b95f..395734c594329 100644 --- a/build/args/testing.gn +++ b/build/args/testing.gn @@ -1,14 +1,7 @@ -import("all.gn") +import("//electron/build/args/all.gn") is_debug = false is_component_build = false is_component_ffmpeg = true is_official_build = false dcheck_always_on = true symbol_level = 1 - -# This may be guarded behind is_chrome_branded alongside -# proprietary_codecs https://webrtc-review.googlesource.com/c/src/+/36321, -# explicitly override here to build OpenH264 encoder/FFmpeg decoder. -# The initialization of the decoder depends on whether ffmpeg has -# been built with H.264 support. -rtc_use_h264 = proprietary_codecs diff --git a/build/asar.gni b/build/asar.gni index 4df8ea34dd9ba..b8b290da2c670 100644 --- a/build/asar.gni +++ b/build/asar.gni @@ -1,33 +1,22 @@ -import("node.gni") - -# TODO(MarshallOfSound): Move to electron/node, this is the only place it is used now -# Run an action with a given working directory. Behaves identically to the -# action() target type, with the exception that it changes directory before -# running the script. -# -# Parameters: -# cwd [required]: Directory to change to before running the script. -template("chdir_action") { +template("node_action") { + assert(defined(invoker.script), "Need script path to run") + assert(defined(invoker.args), "Need script arguments") + action(target_name) { forward_variables_from(invoker, - "*", [ - "script", - "args", + "deps", + "public_deps", + "sources", + "inputs", + "outputs", ]) - assert(defined(cwd), "Need cwd in $target_name") - script = "//electron/build/run-in-dir.py" - if (defined(sources)) { - sources += [ invoker.script ] - } else { - assert(defined(inputs)) - inputs += [ invoker.script ] + if (!defined(inputs)) { + inputs = [] } - args = [ - rebase_path(cwd), - rebase_path(invoker.script), - ] - args += invoker.args + inputs += [ invoker.script ] + script = "//electron/build/run-node.py" + args = [ rebase_path(invoker.script) ] + invoker.args } } @@ -57,4 +46,42 @@ template("asar") { rebase_path(outputs[0]), ] } + + node_action(target_name + "_header_hash") { + invoker_out = invoker.outputs + + deps = [ ":" + invoker.target_name ] + sources = invoker.outputs + + script = "//electron/script/gn-asar-hash.js" + outputs = [ "$target_gen_dir/asar_hashes/$target_name.hash" ] + + args = [ + rebase_path(invoker_out[0]), + rebase_path(outputs[0]), + ] + } +} + +template("asar_hashed_info_plist") { + node_action(target_name) { + assert(defined(invoker.plist_file), + "Need plist_file to add hashed assets to") + assert(defined(invoker.keys), "Need keys to replace with asset hash") + assert(defined(invoker.hash_targets), "Need hash_targets to read hash from") + + deps = invoker.hash_targets + + script = "//electron/script/gn-plist-but-with-hashes.js" + inputs = [ invoker.plist_file ] + outputs = [ "$target_gen_dir/hashed_plists/$target_name.plist" ] + hash_files = [] + foreach(hash_target, invoker.hash_targets) { + hash_files += get_target_outputs(hash_target) + } + args = [ + rebase_path(invoker.plist_file), + rebase_path(outputs[0]), + ] + invoker.keys + rebase_path(hash_files) + } } diff --git a/build/checksum_header.py b/build/checksum_header.py new file mode 100644 index 0000000000000..86237e8885557 --- /dev/null +++ b/build/checksum_header.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 + +import os +import sys +import hashlib + +dir_path = os.path.dirname(os.path.realpath(__file__)) + +TEMPLATE_H = """ +#ifndef ELECTRON_SNAPSHOT_CHECKSUM_H_ +#define ELECTRON_SNAPSHOT_CHECKSUM_H_ + +namespace electron::snapshot_checksum { + +inline constexpr std::string_view kChecksum = "{checksum}"; + +} // namespace electron::snapshot_checksum + +#endif // ELECTRON_SNAPSHOT_CHECKSUM_H_ +""" + +def calculate_sha256(filepath): + sha256_hash = hashlib.sha256() + with open(filepath, "rb") as f: + for byte_block in iter(lambda: f.read(4096), b""): + sha256_hash.update(byte_block) + return sha256_hash.hexdigest() + +input_file = sys.argv[1] +output_file = sys.argv[2] + +checksum = calculate_sha256(input_file) + +checksum_h = TEMPLATE_H.replace("{checksum}", checksum) + +with open(output_file, 'w') as f: + f.write(checksum_h) diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn index e805478b21a86..a82a0d7e316ee 100644 --- a/build/config/BUILD.gn +++ b/build/config/BUILD.gn @@ -1,26 +1,11 @@ -config("build_time_executable") { - configs = [] - - if (is_electron_build && !is_component_build) { - # The executables which have this config applied are dependent on ffmpeg, - # which is always a shared library in an Electron build. However, in the - # non-component build, executables don't have rpath set to search for - # libraries in the executable's directory, so ffmpeg cannot be found. So - # let's make sure rpath is set here. - # See '//build/config/gcc/BUILD.gn' for details on the rpath setting. - if (is_linux) { - configs += [ "//build/config/gcc:rpath_for_built_shared_libraries" ] - } - - if (is_mac) { - ldflags = [ "-Wl,-rpath,@loader_path/." ] - } - } -} - -# For MAS build, we force defining "MAS_BUILD". -config("mas_build") { +action("generate_mas_config") { + outputs = [ "$target_gen_dir/../../mas.h" ] + script = "../../script/generate-mas-config.py" if (is_mas_build) { - defines = [ "MAS_BUILD" ] + args = [ "true" ] + } else { + args = [ "false" ] } + + args += rebase_path(outputs) } diff --git a/build/dump_syms.py b/build/dump_syms.py index a606cb8789e1b..8b38944928e59 100644 --- a/build/dump_syms.py +++ b/build/dump_syms.py @@ -1,4 +1,4 @@ -from __future__ import print_function +#!/usr/bin/env python3 import collections import os @@ -39,7 +39,7 @@ def main(dump_syms, binary, out_dir, stamp_file, dsym_file=None): args += ["-g", dsym_file] args += [binary] - symbol_data = subprocess.check_output(args) + symbol_data = subprocess.check_output(args).decode(sys.stdout.encoding) symbol_path = os.path.join(out_dir, get_symbol_path(symbol_data)) mkdir_p(os.path.dirname(symbol_path)) diff --git a/electron_paks.gni b/build/electron_paks.gni similarity index 77% rename from electron_paks.gni rename to build/electron_paks.gni index 3814ee0e38ee3..36663da20e69d 100644 --- a/electron_paks.gni +++ b/build/electron_paks.gni @@ -19,14 +19,12 @@ template("electron_repack_percent") { # All sources should also have deps for completeness. sources = [ "$root_gen_dir/components/components_resources_${percent}_percent.pak", - "$root_gen_dir/content/app/resources/content_resources_${percent}_percent.pak", "$root_gen_dir/third_party/blink/public/resources/blink_scaled_resources_${percent}_percent.pak", "$root_gen_dir/ui/resources/ui_resources_${percent}_percent.pak", ] deps = [ "//components/resources", - "//content/app/resources", "//third_party/blink/public:scaled_resources_${percent}_percent", "//ui/resources", ] @@ -54,26 +52,30 @@ template("electron_extra_paks") { ]) output = "${invoker.output_dir}/resources.pak" sources = [ - "$root_gen_dir/chrome/dev_ui_browser_resources.pak", + "$root_gen_dir/chrome/accessibility_resources.pak", + "$root_gen_dir/chrome/browser_resources.pak", + "$root_gen_dir/chrome/common_resources.pak", "$root_gen_dir/components/components_resources.pak", "$root_gen_dir/content/browser/resources/media/media_internals_resources.pak", "$root_gen_dir/content/browser/tracing/tracing_resources.pak", "$root_gen_dir/content/browser/webrtc/resources/webrtc_internals_resources.pak", "$root_gen_dir/content/content_resources.pak", - "$root_gen_dir/content/dev_ui_content_resources.pak", + "$root_gen_dir/content/gpu_resources.pak", "$root_gen_dir/mojo/public/js/mojo_bindings_resources.pak", "$root_gen_dir/net/net_resources.pak", "$root_gen_dir/third_party/blink/public/resources/blink_resources.pak", "$root_gen_dir/third_party/blink/public/resources/inspector_overlay_resources.pak", - "$root_gen_dir/ui/resources/webui_resources.pak", "$target_gen_dir/electron_resources.pak", ] deps = [ - "//chrome/browser:dev_ui_browser_resources", + "//chrome/browser:resources", + "//chrome/browser/resources/accessibility:resources", + "//chrome/common:resources", "//components/resources", "//content:content_resources", - "//content:dev_ui_content_resources", - "//content/browser/resources/media:media_internals_resources", + "//content/browser/resources/gpu:resources", + "//content/browser/resources/media:resources", + "//content/browser/resources/process:resources", "//content/browser/tracing:resources", "//content/browser/webrtc/resources", "//electron:resources", @@ -81,7 +83,7 @@ template("electron_extra_paks") { "//net:net_resources", "//third_party/blink/public:devtools_inspector_resources", "//third_party/blink/public:resources", - "//ui/resources", + "//ui/webui/resources", ] if (defined(invoker.deps)) { deps += invoker.deps @@ -91,13 +93,19 @@ template("electron_extra_paks") { } # New paks should be added here by default. - sources += - [ "$root_gen_dir/content/browser/devtools/devtools_resources.pak" ] + sources += [ + "$root_gen_dir/content/browser/devtools/devtools_resources.pak", + "$root_gen_dir/content/process_resources.pak", + "$root_gen_dir/ui/webui/resources/webui_resources.pak", + ] deps += [ "//content/browser/devtools:devtools_resources" ] + if (enable_pdf_viewer) { + sources += [ "$root_gen_dir/chrome/pdf_resources.pak" ] + deps += [ "//chrome/browser/resources/pdf:resources" ] + } if (enable_print_preview) { sources += [ "$root_gen_dir/chrome/print_preview_resources.pak" ] - deps += - [ "//chrome/browser/resources/print_preview:print_preview_resources" ] + deps += [ "//chrome/browser/resources/print_preview:resources" ] } if (enable_electron_extensions) { sources += [ @@ -168,31 +176,47 @@ template("electron_paks") { } source_patterns = [ + "${root_gen_dir}/chrome/branded_strings_", + "${root_gen_dir}/chrome/locale_settings_", "${root_gen_dir}/chrome/platform_locale_settings_", + "${root_gen_dir}/chrome/generated_resources_", + "${root_gen_dir}/components/strings/components_locale_settings_", "${root_gen_dir}/components/strings/components_strings_", - "${root_gen_dir}/third_party/blink/public/strings/blink_strings_", "${root_gen_dir}/device/bluetooth/strings/bluetooth_strings_", + "${root_gen_dir}/electron/electron_strings_", + "${root_gen_dir}/extensions/strings/extensions_strings_", "${root_gen_dir}/services/strings/services_strings_", + "${root_gen_dir}/third_party/blink/public/strings/blink_strings_", "${root_gen_dir}/ui/strings/app_locale_settings_", + "${root_gen_dir}/ui/strings/auto_image_annotation_strings_", + "${root_gen_dir}/ui/strings/ax_strings_", "${root_gen_dir}/ui/strings/ui_strings_", ] deps = [ + "//chrome/app:branded_strings", + "//chrome/app:generated_resources", + "//chrome/app/resources:locale_settings", "//chrome/app/resources:platform_locale_settings", + "//components/strings:components_locale_settings", "//components/strings:components_strings", "//device/bluetooth/strings", + "//electron:resources", + "//extensions/strings", "//services/strings", "//third_party/blink/public/strings", "//ui/strings:app_locale_settings", + "//ui/strings:auto_image_annotation_strings", + "//ui/strings:ax_strings", "//ui/strings:ui_strings", ] - input_locales = locales + input_locales = platform_pak_locales output_dir = "${invoker.output_dir}/locales" if (is_mac) { - output_locales = locales_as_mac_outputs + output_locales = locales_as_apple_outputs } else { - output_locales = locales + output_locales = platform_pak_locales } } diff --git a/build/electron_resources.grd b/build/electron_resources.grd new file mode 100644 index 0000000000000..edb39bcf7f15c --- /dev/null +++ b/build/electron_resources.grd @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Reply + + + Show + + + + + + + \ No newline at end of file diff --git a/build/extract_symbols.gni b/build/extract_symbols.gni index e3fa2a30f4ca0..8d6c2e72b9386 100644 --- a/build/extract_symbols.gni +++ b/build/extract_symbols.gni @@ -24,7 +24,8 @@ template("extract_symbols") { assert(defined(invoker.binary), "Need binary to dump") assert(defined(invoker.symbol_dir), "Need directory for symbol output") - dump_syms_label = "//third_party/breakpad:dump_syms($host_toolchain)" + dump_syms_label = + "//third_party/breakpad:dump_syms($host_system_allocator_toolchain)" dump_syms_binary = get_label_info(dump_syms_label, "root_out_dir") + "/dump_syms$_host_executable_suffix" diff --git a/build/fake_v8_context_snapshot_generator.py b/build/fake_v8_context_snapshot_generator.py deleted file mode 100644 index 2309b22484bac..0000000000000 --- a/build/fake_v8_context_snapshot_generator.py +++ /dev/null @@ -1,8 +0,0 @@ -import os -import shutil -import sys - -if os.path.exists(sys.argv[2]): - os.remove(sys.argv[2]) - -shutil.copy(sys.argv[1], sys.argv[2]) diff --git a/build/fuses/build.py b/build/fuses/build.py index f17c08fdb8451..77f269f6e837d 100755 --- a/build/fuses/build.py +++ b/build/fuses/build.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 +from collections import OrderedDict import json import os import sys @@ -18,39 +19,37 @@ #define FUSE_EXPORT __attribute__((visibility("default"))) #endif -namespace electron { - -namespace fuses { +namespace electron::fuses { extern const volatile char kFuseWire[]; {getters} -} // namespace fuses - -} // namespace electron +} // namespace electron::fuses #endif // ELECTRON_FUSES_H_ """ TEMPLATE_CC = """ #include "electron/fuses.h" +#include "base/dcheck_is_on.h" -namespace electron { +#if DCHECK_IS_ON() +#include "base/command_line.h" +#include +#endif -namespace fuses { +namespace electron::fuses { const volatile char kFuseWire[] = { /* sentinel */ {sentinel}, /* fuse_version */ {fuse_version}, /* fuse_wire_length */ {fuse_wire_length}, /* fuse_wire */ {initial_config}}; {getters} -} - -} +} // namespace electron:fuses """ -with open(os.path.join(dir_path, "fuses.json"), 'r') as f: - fuse_defaults = json.load(f) +with open(os.path.join(dir_path, "fuses.json5"), 'r') as f: + fuse_defaults = json.loads(''.join(line for line in f.readlines() if not line.strip()[0] == "/"), object_pairs_hook=OrderedDict) fuse_version = fuse_defaults['_version'] del fuse_defaults['_version'] @@ -73,9 +72,20 @@ getters_h += "FUSE_EXPORT bool Is{name}Enabled();\n".replace("{name}", name) getters_cc += """ bool Is{name}Enabled() { +#if DCHECK_IS_ON() + // RunAsNode is checked so early that base::CommandLine isn't yet + // initialized, so guard here to avoid a CHECK. + if (base::CommandLine::InitializedForCurrentProcess()) { + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + if (command_line->HasSwitch("{switch_name}")) { + std::string switch_value = command_line->GetSwitchValueASCII("{switch_name}"); + return switch_value == "1"; + } + } +#endif return kFuseWire[{index}] == '1'; } -""".replace("{name}", name).replace("{index}", str(index)) +""".replace("{name}", name).replace("{switch_name}", f"set-fuse-{fuse.lower()}").replace("{index}", str(index)) def c_hex(n): s = hex(n)[2:] diff --git a/build/fuses/fuses.json b/build/fuses/fuses.json deleted file mode 100644 index 9ff211adb43e3..0000000000000 --- a/build/fuses/fuses.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "_comment": "Modifying the fuse schema in any breaking way should result in the _version prop being incremented. NEVER remove a fuse or change its meaning, instead mark it as removed with 'r'", - "_schema": "0 == off, 1 == on, r == removed fuse", - "_version": 1, - "run_as_node": "1" -} diff --git a/build/fuses/fuses.json5 b/build/fuses/fuses.json5 new file mode 100644 index 0000000000000..1e251db281268 --- /dev/null +++ b/build/fuses/fuses.json5 @@ -0,0 +1,14 @@ +{ + "_comment": "Modifying the fuse schema in any breaking way should result in the _version prop being incremented. NEVER remove a fuse or change its meaning, instead mark it as removed with 'r'", + "_schema": "0 == off, 1 == on, r == removed fuse", + "_version": 1, + "run_as_node": "1", + "cookie_encryption": "0", + "node_options": "1", + "node_cli_inspect": "1", + "embedded_asar_integrity_validation": "0", + "only_load_app_from_asar": "0", + "load_browser_process_specific_v8_snapshot": "0", + "grant_file_protocol_extra_privileges": "1", + "wasm_trap_handlers": "1" +} diff --git a/build/generate_node_defines.py b/build/generate_node_defines.py new file mode 100755 index 0000000000000..31e43d3c66b3a --- /dev/null +++ b/build/generate_node_defines.py @@ -0,0 +1,34 @@ +import os +import re +import sys + +DEFINE_EXTRACT_REGEX = re.compile(r'^ *# *define (\w*)', re.MULTILINE) + +def main(out_dir, headers): + defines = [] + for filename in headers: + with open(filename, 'r') as f: + content = f.read() + defines += read_defines(content) + + push_and_undef = '' + for define in defines: + push_and_undef += '#pragma push_macro("%s")\n' % define + push_and_undef += '#undef %s\n' % define + with open(os.path.join(out_dir, 'push_and_undef_node_defines.h'), 'w') as o: + o.write(push_and_undef) + + pop = '' + for define in defines: + pop += '#pragma pop_macro("%s")\n' % define + with open(os.path.join(out_dir, 'pop_node_defines.h'), 'w') as o: + o.write(pop) + +def read_defines(content): + defines = [] + for match in DEFINE_EXTRACT_REGEX.finditer(content): + defines.append(match.group(1)) + return defines + +if __name__ == '__main__': + main(sys.argv[1], sys.argv[2:]) diff --git a/build/install-build-deps.sh b/build/install-build-deps.sh deleted file mode 100755 index 2a1266e9f7bbf..0000000000000 --- a/build/install-build-deps.sh +++ /dev/null @@ -1,653 +0,0 @@ -#!/bin/bash -e -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -# Script to install everything needed to build chromium (well, ideally, anyway) -# See https://chromium.googlesource.com/chromium/src/+/master/docs/linux_build_instructions.md -usage() { - echo "Usage: $0 [--options]" - echo "Options:" - echo "--[no-]syms: enable or disable installation of debugging symbols" - echo "--lib32: enable installation of 32-bit libraries, e.g. for V8 snapshot" - echo "--[no-]arm: enable or disable installation of arm cross toolchain" - echo "--[no-]chromeos-fonts: enable or disable installation of Chrome OS"\ - "fonts" - echo "--[no-]nacl: enable or disable installation of prerequisites for"\ - "building standalone NaCl and all its toolchains" - echo "--[no-]backwards-compatible: enable or disable installation of packages - that are no longer currently needed and have been removed from this - script. Useful for bisection." - echo "--no-prompt: silently select standard options/defaults" - echo "--quick-check: quickly try to determine if dependencies are installed" - echo " (this avoids interactive prompts and sudo commands," - echo " so might not be 100% accurate)" - echo "--unsupported: attempt installation even on unsupported systems" - echo "Script will prompt interactively if options not given." - exit 1 -} -# Checks whether a particular package is available in the repos. -# USAGE: $ package_exists -package_exists() { - # 'apt-cache search' takes a regex string, so eg. the +'s in packages like - # "libstdc++" need to be escaped. - local escaped="$(echo $1 | sed 's/[\~\+\.\:-]/\\&/g')" - [ ! -z "$(apt-cache search --names-only "${escaped}" | \ - awk '$1 == "'$1'" { print $1; }')" ] -} -# These default to on because (some) bots need them and it keeps things -# simple for the bot setup if all bots just run the script in its default -# mode. Developers who don't want stuff they don't need installed on their -# own workstations can pass --no-arm --no-nacl when running the script. -do_inst_arm=1 -do_inst_nacl=1 -while [ "$1" != "" ] -do - case "$1" in - --syms) do_inst_syms=1;; - --no-syms) do_inst_syms=0;; - --lib32) do_inst_lib32=1;; - --arm) do_inst_arm=1;; - --no-arm) do_inst_arm=0;; - --chromeos-fonts) do_inst_chromeos_fonts=1;; - --no-chromeos-fonts) do_inst_chromeos_fonts=0;; - --nacl) do_inst_nacl=1;; - --no-nacl) do_inst_nacl=0;; - --backwards-compatible) do_inst_backwards_compatible=1;; - --no-backwards-compatible) do_inst_backwards_compatible=0;; - --add-cross-tool-repo) add_cross_tool_repo=1;; - --no-prompt) do_default=1 - do_quietly="-qq --assume-yes" - ;; - --quick-check) do_quick_check=1;; - --unsupported) do_unsupported=1;; - *) usage;; - esac - shift -done -if [ "$do_inst_arm" = "1" ]; then - do_inst_lib32=1 -fi -# Check for lsb_release command in $PATH -if ! which lsb_release > /dev/null; then - echo "ERROR: lsb_release not found in \$PATH" >&2 - exit 1; -fi -distro_codename=$(lsb_release --codename --short) -distro_id=$(lsb_release --id --short) -supported_codenames="(trusty|xenial|artful|bionic)" -supported_ids="(Debian)" -if [ 0 -eq "${do_unsupported-0}" ] && [ 0 -eq "${do_quick_check-0}" ] ; then - if [[ ! $distro_codename =~ $supported_codenames && - ! $distro_id =~ $supported_ids ]]; then - echo -e "ERROR: The only supported distros are\n" \ - "\tUbuntu 14.04 LTS (trusty)\n" \ - "\tUbuntu 16.04 LTS (xenial)\n" \ - "\tUbuntu 17.10 (artful)\n" \ - "\tUbuntu 18.04 LTS (bionic)\n" \ - "\tDebian 8 (jessie) or later" >&2 - exit 1 - fi - if ! uname -m | egrep -q "i686|x86_64"; then - echo "Only x86 architectures are currently supported" >&2 - exit - fi -fi -if [ "x$(id -u)" != x0 ] && [ 0 -eq "${do_quick_check-0}" ]; then - echo "Running as non-root user." - echo "You might have to enter your password one or more times for 'sudo'." - echo -fi -# Packages needed for chromeos only -chromeos_dev_list="libbluetooth-dev libxkbcommon-dev" -if package_exists realpath; then - chromeos_dev_list="${chromeos_dev_list} realpath" -fi -# Packages needed for development -dev_list="\ - binutils - bison - bzip2 - cdbs - curl - dbus-x11 - dpkg-dev - elfutils - devscripts - fakeroot - flex - g++ - git-core - git-svn - gperf - libappindicator3-dev - libasound2-dev - libatspi2.0-dev - libbrlapi-dev - libbz2-dev - libcairo2-dev - libcap-dev - libcups2-dev - libcurl4-gnutls-dev - libdrm-dev - libelf-dev - libffi-dev - libgbm-dev - libglib2.0-dev - libglu1-mesa-dev - libgnome-keyring-dev - libgtk-3-dev - libkrb5-dev - libnspr4-dev - libnss3-dev - libpam0g-dev - libpci-dev - libpulse-dev - libsctp-dev - libspeechd-dev - libsqlite3-dev - libssl-dev - libudev-dev - libwww-perl - libxslt1-dev - libxss-dev - libxt-dev - libxtst-dev - locales - openbox - p7zip - patch - perl - pkg-config - python - python-cherrypy3 - python-crypto - python-dev - python-numpy - python-opencv - python-openssl - python-psutil - python-yaml - rpm - ruby - subversion - uuid-dev - wdiff - x11-utils - xcompmgr - xz-utils - zip - $chromeos_dev_list -" -# 64-bit systems need a minimum set of 32-bit compat packages for the pre-built -# NaCl binaries. -if file -L /sbin/init | grep -q 'ELF 64-bit'; then - dev_list="${dev_list} libc6-i386 lib32gcc1 lib32stdc++6" -fi -# Run-time libraries required by chromeos only -chromeos_lib_list="libpulse0 libbz2-1.0" -# List of required run-time libraries -common_lib_list="\ - libappindicator3-1 - libasound2 - libatk1.0-0 - libatspi2.0-0 - libc6 - libcairo2 - libcap2 - libcups2 - libexpat1 - libffi6 - libfontconfig1 - libfreetype6 - libglib2.0-0 - libgnome-keyring0 - libgtk-3-0 - libpam0g - libpango1.0-0 - libpci3 - libpcre3 - libpixman-1-0 - libspeechd2 - libstdc++6 - libsqlite3-0 - libuuid1 - libwayland-egl1-mesa - libx11-6 - libx11-xcb1 - libxau6 - libxcb1 - libxcomposite1 - libxcursor1 - libxdamage1 - libxdmcp6 - libxext6 - libxfixes3 - libxi6 - libxinerama1 - libxrandr2 - libxrender1 - libxtst6 - zlib1g -" -# Full list of required run-time libraries -lib_list="\ - $common_lib_list - $chromeos_lib_list -" -# 32-bit libraries needed e.g. to compile V8 snapshot for Android or armhf -lib32_list="linux-libc-dev:i386 libpci3:i386" -# 32-bit libraries needed for a 32-bit build -lib32_list="$lib32_list libx11-xcb1:i386" -# Packages that have been removed from this script. Regardless of configuration -# or options passed to this script, whenever a package is removed, it should be -# added here. -backwards_compatible_list="\ - 7za - fonts-indic - fonts-ipafont - fonts-stix - fonts-thai-tlwg - fonts-tlwg-garuda - language-pack-da - language-pack-fr - language-pack-he - language-pack-zh-hant - libappindicator-dev - libappindicator1 - libappindicator3-1:i386 - libexif-dev - libexif12 - libexif12:i386 - libgbm-dev - libgl1-mesa-dev - libgl1-mesa-glx:i386 - libgles2-mesa-dev - libgtk2.0-0 - libgtk2.0-0:i386 - libgtk2.0-dev - mesa-common-dev - msttcorefonts - ttf-dejavu-core - ttf-indic-fonts - ttf-kochi-gothic - ttf-kochi-mincho - ttf-mscorefonts-installer - xfonts-mathml -" -case $distro_codename in - trusty) - backwards_compatible_list+=" \ - libgbm-dev-lts-trusty - libgl1-mesa-dev-lts-trusty - libgl1-mesa-glx-lts-trusty:i386 - libgles2-mesa-dev-lts-trusty - mesa-common-dev-lts-trusty" - ;; - xenial) - backwards_compatible_list+=" \ - libgbm-dev-lts-xenial - libgl1-mesa-dev-lts-xenial - libgl1-mesa-glx-lts-xenial:i386 - libgles2-mesa-dev-lts-xenial - mesa-common-dev-lts-xenial" - ;; -esac -# arm cross toolchain packages needed to build chrome on armhf -EM_REPO="deb http://emdebian.org/tools/debian/ jessie main" -EM_SOURCE=$(cat </dev/null); then - arm_list+=" ${GPP_ARM_PACKAGE}" - else - if [ "${add_cross_tool_repo}" = "1" ]; then - gpg --keyserver pgp.mit.edu --recv-keys ${EM_ARCHIVE_KEY_FINGER} - gpg -a --export ${EM_ARCHIVE_KEY_FINGER} | sudo apt-key add - - if ! grep "^${EM_REPO}" "${CROSSTOOLS_LIST}" &>/dev/null; then - echo "${EM_SOURCE}" | sudo tee -a "${CROSSTOOLS_LIST}" >/dev/null - fi - arm_list+=" ${GPP_ARM_PACKAGE}" - else - echo "The Debian Cross-toolchains repository is necessary to" - echo "cross-compile Chromium for arm." - echo "Rerun with --add-deb-cross-tool-repo to have it added for you." - fi - fi - fi - ;; - # All necessary ARM packages are available on the default repos on - # Debian 9 and later. - *) - arm_list="libc6-dev-armhf-cross - linux-libc-dev-armhf-cross - ${GPP_ARM_PACKAGE}" - ;; -esac -# Work around for dependency issue Ubuntu/Trusty: http://crbug.com/435056 -case $distro_codename in - trusty) - arm_list+=" g++-4.8-multilib-arm-linux-gnueabihf - gcc-4.8-multilib-arm-linux-gnueabihf" - ;; - xenial|artful|bionic) - arm_list+=" g++-5-multilib-arm-linux-gnueabihf - gcc-5-multilib-arm-linux-gnueabihf - gcc-arm-linux-gnueabihf" - ;; -esac -# Packages to build NaCl, its toolchains, and its ports. -naclports_list="ant autoconf bison cmake gawk intltool xutils-dev xsltproc" -nacl_list="\ - g++-mingw-w64-i686 - lib32z1-dev - libasound2:i386 - libcap2:i386 - libelf-dev:i386 - libfontconfig1:i386 - libglib2.0-0:i386 - libgpm2:i386 - libgtk-3-0:i386 - libncurses5:i386 - lib32ncurses5-dev - libnss3:i386 - libpango1.0-0:i386 - libssl-dev:i386 - libtinfo-dev - libtinfo-dev:i386 - libtool - libuuid1:i386 - libxcomposite1:i386 - libxcursor1:i386 - libxdamage1:i386 - libxi6:i386 - libxrandr2:i386 - libxss1:i386 - libxtst6:i386 - texinfo - xvfb - ${naclports_list} -" -if package_exists libssl1.1; then - nacl_list="${nacl_list} libssl1.1:i386" -elif package_exists libssl1.0.2; then - nacl_list="${nacl_list} libssl1.0.2:i386" -else - nacl_list="${nacl_list} libssl1.0.0:i386" -fi -# Some package names have changed over time -if package_exists libpng16-16; then - lib_list="${lib_list} libpng16-16" -else - lib_list="${lib_list} libpng12-0" -fi -if package_exists libnspr4; then - lib_list="${lib_list} libnspr4 libnss3" -else - lib_list="${lib_list} libnspr4-0d libnss3-1d" -fi -if package_exists libjpeg-dev; then - dev_list="${dev_list} libjpeg-dev" -else - dev_list="${dev_list} libjpeg62-dev" -fi -if package_exists libudev1; then - dev_list="${dev_list} libudev1" - nacl_list="${nacl_list} libudev1:i386" -else - dev_list="${dev_list} libudev0" - nacl_list="${nacl_list} libudev0:i386" -fi -if package_exists libbrlapi0.6; then - dev_list="${dev_list} libbrlapi0.6" -else - dev_list="${dev_list} libbrlapi0.5" -fi -if package_exists apache2.2-bin; then - dev_list="${dev_list} apache2.2-bin" -else - dev_list="${dev_list} apache2-bin" -fi -if package_exists libav-tools; then - dev_list="${dev_list} libav-tools" -fi -if package_exists php7.2-cgi; then - dev_list="${dev_list} php7.2-cgi libapache2-mod-php7.2" -elif package_exists php7.1-cgi; then - dev_list="${dev_list} php7.1-cgi libapache2-mod-php7.1" -elif package_exists php7.0-cgi; then - dev_list="${dev_list} php7.0-cgi libapache2-mod-php7.0" -else - dev_list="${dev_list} php5-cgi libapache2-mod-php5" -fi -# Some packages are only needed if the distribution actually supports -# installing them. -if package_exists appmenu-gtk; then - lib_list="$lib_list appmenu-gtk" -fi -# Cross-toolchain strip is needed for building the sysroots. -if package_exists binutils-arm-linux-gnueabihf; then - dev_list="${dev_list} binutils-arm-linux-gnueabihf" -fi -if package_exists binutils-aarch64-linux-gnu; then - dev_list="${dev_list} binutils-aarch64-linux-gnu" -fi -if package_exists binutils-mipsel-linux-gnu; then - dev_list="${dev_list} binutils-mipsel-linux-gnu" -fi -if package_exists binutils-mips64el-linux-gnuabi64; then - dev_list="${dev_list} binutils-mips64el-linux-gnuabi64" -fi -# When cross building for arm/Android on 64-bit systems the host binaries -# that are part of v8 need to be compiled with -m32 which means -# that basic multilib support is needed. -if file -L /sbin/init | grep -q 'ELF 64-bit'; then - # gcc-multilib conflicts with the arm cross compiler (at least in trusty) but - # g++-X.Y-multilib gives us the 32-bit support that we need. Find out the - # appropriate value of X and Y by seeing what version the current - # distribution's g++-multilib package depends on. - multilib_package=$(apt-cache depends g++-multilib --important | \ - grep -E --color=never --only-matching '\bg\+\+-[0-9.]+-multilib\b') - lib32_list="$lib32_list $multilib_package" -fi -if [ "$do_inst_syms" = "1" ]; then - echo "Including debugging symbols." - # Debian is in the process of transitioning to automatic debug packages, which - # have the -dbgsym suffix (https://wiki.debian.org/AutomaticDebugPackages). - # Untransitioned packages have the -dbg suffix. And on some systems, neither - # will be available, so exclude the ones that are missing. - dbg_package_name() { - if package_exists "$1-dbgsym"; then - echo "$1-dbgsym" - elif package_exists "$1-dbg"; then - echo "$1-dbg" - fi - } - for package in "${common_lib_list}"; do - dbg_list="$dbg_list $(dbg_package_name ${package})" - done - # Debugging symbols packages not following common naming scheme - if [ "$(dbg_package_name libstdc++6)" == "" ]; then - if package_exists libstdc++6-8-dbg; then - dbg_list="${dbg_list} libstdc++6-8-dbg" - elif package_exists libstdc++6-7-dbg; then - dbg_list="${dbg_list} libstdc++6-7-dbg" - elif package_exists libstdc++6-6-dbg; then - dbg_list="${dbg_list} libstdc++6-6-dbg" - elif package_exists libstdc++6-5-dbg; then - dbg_list="${dbg_list} libstdc++6-5-dbg" - elif package_exists libstdc++6-4.9-dbg; then - dbg_list="${dbg_list} libstdc++6-4.9-dbg" - elif package_exists libstdc++6-4.8-dbg; then - dbg_list="${dbg_list} libstdc++6-4.8-dbg" - elif package_exists libstdc++6-4.7-dbg; then - dbg_list="${dbg_list} libstdc++6-4.7-dbg" - elif package_exists libstdc++6-4.6-dbg; then - dbg_list="${dbg_list} libstdc++6-4.6-dbg" - fi - fi - if [ "$(dbg_package_name libatk1.0-0)" == "" ]; then - dbg_list="$dbg_list $(dbg_package_name libatk1.0)" - fi - if [ "$(dbg_package_name libpango1.0-0)" == "" ]; then - dbg_list="$dbg_list $(dbg_package_name libpango1.0-dev)" - fi -else - echo "Skipping debugging symbols." - dbg_list= -fi -if [ "$do_inst_lib32" = "1" ]; then - echo "Including 32-bit libraries." -else - echo "Skipping 32-bit libraries." - lib32_list= -fi -if [ "$do_inst_arm" = "1" ]; then - echo "Including ARM cross toolchain." -else - echo "Skipping ARM cross toolchain." - arm_list= -fi -if [ "$do_inst_nacl" = "1" ]; then - echo "Including NaCl, NaCl toolchain, NaCl ports dependencies." -else - echo "Skipping NaCl, NaCl toolchain, NaCl ports dependencies." - nacl_list= -fi -filtered_backwards_compatible_list= -if [ "$do_inst_backwards_compatible" = "1" ]; then - echo "Including backwards compatible packages." - for package in ${backwards_compatible_list}; do - if package_exists ${package}; then - filtered_backwards_compatible_list+=" ${package}" - fi - done -fi -# The `sort -r -s -t: -k2` sorts all the :i386 packages to the front, to avoid -# confusing dpkg-query (crbug.com/446172). -packages="$( - echo "${dev_list} ${lib_list} ${dbg_list} ${lib32_list} ${arm_list}" \ - "${nacl_list}" ${filtered_backwards_compatible_list} | tr " " "\n" | \ - sort -u | sort -r -s -t: -k2 | tr "\n" " " -)" -if [ 1 -eq "${do_quick_check-0}" ] ; then - if ! missing_packages="$(dpkg-query -W -f ' ' ${packages} 2>&1)"; then - # Distinguish between packages that actually aren't available to the - # system (i.e. not in any repo) and packages that just aren't known to - # dpkg (i.e. managed by apt). - missing_packages="$(echo "${missing_packages}" | awk '{print $NF}')" - not_installed="" - unknown="" - for p in ${missing_packages}; do - if apt-cache show ${p} > /dev/null 2>&1; then - not_installed="${p}\n${not_installed}" - else - unknown="${p}\n${unknown}" - fi - done - if [ -n "${not_installed}" ]; then - echo "WARNING: The following packages are not installed:" - echo -e "${not_installed}" | sed -e "s/^/ /" - fi - if [ -n "${unknown}" ]; then - echo "WARNING: The following packages are unknown to your system" - echo "(maybe missing a repo or need to 'sudo apt-get update'):" - echo -e "${unknown}" | sed -e "s/^/ /" - fi - exit 1 - fi - exit 0 -fi -if [ "$do_inst_lib32" = "1" ] || [ "$do_inst_nacl" = "1" ]; then - sudo dpkg --add-architecture i386 -fi -sudo apt-get update -# We initially run "apt-get" with the --reinstall option and parse its output. -# This way, we can find all the packages that need to be newly installed -# without accidentally promoting any packages from "auto" to "manual". -# We then re-run "apt-get" with just the list of missing packages. -echo "Finding missing packages..." -# Intentionally leaving $packages unquoted so it's more readable. -echo "Packages required: " $packages -echo -new_list_cmd="sudo apt-get install --reinstall $(echo $packages)" -if new_list="$(yes n | LANGUAGE=en LANG=C $new_list_cmd)"; then - # We probably never hit this following line. - echo "No missing packages, and the packages are up to date." -elif [ $? -eq 1 ]; then - # We expect apt-get to have exit status of 1. - # This indicates that we cancelled the install with "yes n|". - new_list=$(echo "$new_list" | - sed -e '1,/The following NEW packages will be installed:/d;s/^ //;t;d') - new_list=$(echo "$new_list" | sed 's/ *$//') - if [ -z "$new_list" ] ; then - echo "No missing packages, and the packages are up to date." - else - echo "Installing missing packages: $new_list." - sudo apt-get install ${do_quietly-} ${new_list} - fi - echo -else - # An apt-get exit status of 100 indicates that a real error has occurred. - # I am intentionally leaving out the '"'s around new_list_cmd, - # as this makes it easier to cut and paste the output - echo "The following command failed: " ${new_list_cmd} - echo - echo "It produces the following output:" - yes n | $new_list_cmd || true - echo - echo "You will have to install the above packages yourself." - echo - exit 100 -fi -# Install the Chrome OS default fonts. This must go after running -# apt-get, since install-chromeos-fonts depends on curl. -if [ "$do_inst_chromeos_fonts" != "0" ]; then - echo - echo "Installing Chrome OS fonts." - dir=`echo $0 | sed -r -e 's/\/[^/]+$//'` - if ! sudo $dir/linux/install-chromeos-fonts.py; then - echo "ERROR: The installation of the Chrome OS default fonts failed." - if [ `stat -f -c %T $dir` == "nfs" ]; then - echo "The reason is that your repo is installed on a remote file system." - else - echo "This is expected if your repo is installed on a remote file system." - fi - echo "It is recommended to install your repo on a local file system." - echo "You can skip the installation of the Chrome OS default founts with" - echo "the command line option: --no-chromeos-fonts." - exit 1 - fi -else - echo "Skipping installation of Chrome OS fonts." -fi -echo "Installing locales." -CHROMIUM_LOCALES="da_DK.UTF-8 fr_FR.UTF-8 he_IL.UTF-8 zh_TW.UTF-8" -LOCALE_GEN=/etc/locale.gen -if [ -e ${LOCALE_GEN} ]; then - OLD_LOCALE_GEN="$(cat /etc/locale.gen)" - for CHROMIUM_LOCALE in ${CHROMIUM_LOCALES}; do - sudo sed -i "s/^# ${CHROMIUM_LOCALE}/${CHROMIUM_LOCALE}/" ${LOCALE_GEN} - done - # Regenerating locales can take a while, so only do it if we need to. - if (echo "${OLD_LOCALE_GEN}" | cmp -s ${LOCALE_GEN}); then - echo "Locales already up-to-date." - else - sudo locale-gen - fi -else - for CHROMIUM_LOCALE in ${CHROMIUM_LOCALES}; do - sudo locale-gen ${CHROMIUM_LOCALE} - done -fi diff --git a/build/js2c.py b/build/js2c.py old mode 100755 new mode 100644 index 0f7178baf0e08..1529d3d0365d4 --- a/build/js2c.py +++ b/build/js2c.py @@ -1,39 +1,17 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import os import subprocess import sys -TEMPLATE = """ -#include "node_native_module.h" -#include "node_internals.h" - -namespace node {{ - -namespace native_module {{ - -{definitions} - -void NativeModuleLoader::LoadEmbedderJavaScriptSource() {{ - {initializers} -}} - -}} // namespace native_module - -}} // namespace node -""" - def main(): - node_path = os.path.abspath(sys.argv[1]) - natives = os.path.abspath(sys.argv[2]) - js_source_files = sys.argv[3:] + js2c = sys.argv[1] + root = sys.argv[2] + natives = sys.argv[3] + js_source_files = sys.argv[4:] - js2c = os.path.join(node_path, 'tools', 'js2c.py') subprocess.check_call( - [sys.executable, js2c] + - js_source_files + - ['--only-js', '--target', natives]) - + [js2c, natives] + js_source_files + ['--only-js', "--root", root]) if __name__ == '__main__': - sys.exit(main()) + sys.exit(main()) \ No newline at end of file diff --git a/build/js2c_toolchain.gni b/build/js2c_toolchain.gni new file mode 100644 index 0000000000000..b56590857cec2 --- /dev/null +++ b/build/js2c_toolchain.gni @@ -0,0 +1,71 @@ +# Copyright (c) 2023 Microsoft, GmbH +# Use of this source code is governed by the MIT license that can be +# found in the LICENSE file. + +declare_args() { + electron_js2c_toolchain = "" +} + +if (electron_js2c_toolchain == "") { + if (current_os == host_os && current_cpu == host_cpu) { + # This is not a cross-compile, so build the snapshot with the current + # toolchain. + electron_js2c_toolchain = current_toolchain + } else if (current_os == host_os && current_cpu == "x86" && + host_cpu == "x64") { + # This is an x64 -> x86 cross-compile, but x64 hosts can usually run x86 + # binaries built for the same OS, so build the snapshot with the current + # toolchain here, too. + electron_js2c_toolchain = current_toolchain + } else if (current_os == host_os && host_cpu == "arm64" && + current_cpu == "arm") { + # Trying to compile 32-bit arm on arm64. Good luck! + electron_js2c_toolchain = current_toolchain + } else if (host_cpu == current_cpu) { + # Cross-build from same ISA on one OS to another. For example: + # * targeting win/x64 on a linux/x64 host + # * targeting win/arm64 on a mac/arm64 host + electron_js2c_toolchain = host_toolchain + } else if (host_cpu == "arm64" && current_cpu == "x64") { + # Cross-build from arm64 to intel (likely on an Apple Silicon mac). + electron_js2c_toolchain = + "//build/toolchain/${host_os}:clang_arm64_v8_$current_cpu" + } else if (host_cpu == "x64") { + # This is a cross-compile from an x64 host to either a non-Intel target + # cpu or to 32-bit x86 on a different target OS. + + assert(current_cpu != "x64", "handled by host_cpu == current_cpu branch") + if (current_cpu == "x86") { + _cpus = current_cpu + } else if (current_cpu == "arm64") { + if (is_win) { + # set _cpus to blank for Windows ARM64 so host_toolchain could be + # selected as snapshot toolchain later. + _cpus = "" + } else { + _cpus = "x64_v8_${current_cpu}" + } + } else if (current_cpu == "arm") { + _cpus = "x86_v8_${current_cpu}" + } else { + # This branch should not be reached; leave _cpus blank so the assert + # below will fail. + _cpus = "" + } + + if (_cpus != "") { + electron_js2c_toolchain = "//build/toolchain/${host_os}:clang_${_cpus}" + } else if (is_win && current_cpu == "arm64") { + # cross compile Windows arm64 with host toolchain. + electron_js2c_toolchain = host_toolchain + } + } else if (host_cpu == "arm64" && current_cpu == "arm64" && + host_os == "mac") { + # cross compile iOS arm64 with host_toolchain + electron_js2c_toolchain = host_toolchain + } +} + +assert(electron_js2c_toolchain != "", + "Do not know how to build js2c for $current_toolchain " + + "on $host_os $host_cpu") diff --git a/build/linux/strip_binary.gni b/build/linux/strip_binary.gni new file mode 100644 index 0000000000000..6e10a9da60e04 --- /dev/null +++ b/build/linux/strip_binary.gni @@ -0,0 +1,70 @@ +# Copyright 2021 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# This has been adapted from https://source.chromium.org/chromium/chromium/src/+/main:build/linux/strip_binary.gni;drc=c220a41e0422d45f1657c28146d32e99cc53640b +# The notable difference is it has an option to compress the debug sections + +import("//build/config/clang/clang.gni") +import("//build/toolchain/toolchain.gni") + +# Extracts symbols from a binary into a symbol file. +# +# Args: +# binary_input: Path to the binary containing symbols to extract, e.g.: +# "$root_out_dir/chrome" +# symbol_output: Desired output file for symbols, e.g.: +# "$root_out_dir/chrome.debug" +# stripped_binary_output: Desired output file for stripped file, e.g.: +# "$root_out_dir/chrome.stripped" +# compress_debug_sections: If true, compress the extracted debug sections +template("strip_binary") { + forward_variables_from(invoker, + [ + "deps", + "testonly", + ]) + action("${target_name}") { + llvm_strip_binary = "${clang_base_path}/bin/llvm-strip" + llvm_objcopy_binary = "${clang_base_path}/bin/llvm-objcopy" + script = "//electron/build/linux/strip_binary.py" + + if (defined(invoker.stripped_binary_output)) { + stripped_binary_output = invoker.stripped_binary_output + } else { + stripped_binary_output = invoker.binary_input + ".stripped" + } + if (defined(invoker.symbol_output)) { + symbol_output = invoker.symbol_output + } else { + symbol_output = invoker.binary_input + ".debug" + } + + inputs = [ + invoker.binary_input, + llvm_strip_binary, + llvm_objcopy_binary, + ] + outputs = [ + symbol_output, + stripped_binary_output, + ] + args = [ + "--llvm-strip-binary-path", + rebase_path(llvm_strip_binary, root_build_dir), + "--llvm-objcopy-binary-path", + rebase_path(llvm_objcopy_binary, root_build_dir), + "--symbol-output", + rebase_path(symbol_output, root_build_dir), + "--stripped-binary-output", + rebase_path(stripped_binary_output, root_build_dir), + "--binary-input", + rebase_path(invoker.binary_input, root_build_dir), + ] + + if (defined(invoker.compress_debug_sections) && + invoker.compress_debug_sections) { + args += [ "--compress-debug-sections" ] + } + } +} diff --git a/build/linux/strip_binary.py b/build/linux/strip_binary.py new file mode 100644 index 0000000000000..015295f1f8889 --- /dev/null +++ b/build/linux/strip_binary.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +# +# Copyright 2021 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# This has been adapted from https://source.chromium.org/chromium/chromium/src/+/main:build/linux/strip_binary.py;drc=c220a41e0422d45f1657c28146d32e99cc53640b +# The notable difference is it has an option to compress the debug sections + +import argparse +import subprocess +import sys + + +def main() -> int: + parser = argparse.ArgumentParser(description="Strip binary using LLVM tools.") + parser.add_argument("--llvm-strip-binary-path", + help="Path to llvm-strip executable.") + parser.add_argument("--llvm-objcopy-binary-path", + required=True, + help="Path to llvm-objcopy executable.") + parser.add_argument("--binary-input", help="Input ELF binary.") + parser.add_argument("--symbol-output", + help="File to write extracted debug info (.debug).") + parser.add_argument("--compress-debug-sections", + action="store_true", + help="Compress extracted debug info.") + parser.add_argument("--stripped-binary-output", + help="File to write stripped binary.") + args = parser.parse_args() + + # Replicate the behavior of: + # eu-strip -o -f + + objcopy_args = [ + "--only-keep-debug", + args.binary_input, + args.symbol_output, + ] + + if args.compress_debug_sections: + objcopy_args.insert(0, "--compress-debug-sections") + + subprocess.check_output([args.llvm_objcopy_binary_path] + objcopy_args) + subprocess.check_output([ + args.llvm_strip_binary_path, + "--strip-debug", + "--strip-unneeded", + "-o", + args.stripped_binary_output, + args.binary_input, + ]) + subprocess.check_output([ + args.llvm_objcopy_binary_path, + f"--add-gnu-debuglink={args.symbol_output}", + args.stripped_binary_output, + ]) + + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/build/mac/make_locale_dirs.py b/build/mac/make_locale_dirs.py index a75d0735ad127..47f3a9f1f661f 100644 --- a/build/mac/make_locale_dirs.py +++ b/build/mac/make_locale_dirs.py @@ -4,10 +4,11 @@ # Cocoa .app bundle. The presence of these empty directories is sufficient to # convince Cocoa that the application supports the named localization, even if # an InfoPlist.strings file is not provided. Chrome uses these empty locale -# directoires for its helper executable bundles, which do not otherwise +# directories for its helper executable bundles, which do not otherwise # require any direct Cocoa locale support. import os +import errno import sys @@ -16,7 +17,7 @@ def main(args): try: os.makedirs(dirname) except OSError as e: - if e.errno == os.errno.EEXIST: + if e.errno == errno.EEXIST: # It's OK if it already exists pass else: diff --git a/build/node.gni b/build/node.gni deleted file mode 100644 index a65f718e634ed..0000000000000 --- a/build/node.gni +++ /dev/null @@ -1,21 +0,0 @@ -template("node_action") { - assert(defined(invoker.script), "Need script path to run") - assert(defined(invoker.args), "Need script argumets") - - action(target_name) { - forward_variables_from(invoker, - [ - "deps", - "public_deps", - "sources", - "inputs", - "outputs", - ]) - if (!defined(inputs)) { - inputs = [] - } - inputs += [ invoker.script ] - script = "//electron/build/run-node.py" - args = [ rebase_path(invoker.script) ] + invoker.args - } -} diff --git a/build/npm-run.py b/build/npm-run.py index a786aa5da62d8..2fcf649f10627 100644 --- a/build/npm-run.py +++ b/build/npm-run.py @@ -1,5 +1,5 @@ -#!/usr/bin/env python -from __future__ import print_function +#!/usr/bin/env python3 + import os import subprocess import sys @@ -15,12 +15,6 @@ try: subprocess.check_output(args, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: - print( - "NPM script '" - + sys.argv[2] - + "' failed with code '" - + str(e.returncode) - + "':\n" - + e.output - ) + error_msg = "NPM script '{}' failed with code '{}':\n".format(sys.argv[2], e.returncode) + print(error_msg + e.output.decode('utf8')) sys.exit(e.returncode) diff --git a/build/npm.gni b/build/npm.gni index 1d1c944256b8b..7790dcece157f 100644 --- a/build/npm.gni +++ b/build/npm.gni @@ -1,12 +1,12 @@ template("npm_action") { assert(defined(invoker.script), "Need script name to run (must be defined in package.json)") - assert(defined(invoker.args), "Need script argumets") + assert(defined(invoker.args), "Need script arguments") action("npm_pre_flight_" + target_name) { inputs = [ - "package.json", - "yarn.lock", + "//electron/package.json", + "//electron/yarn.lock", ] script = "//electron/build/npm-run.py" diff --git a/build/profile_toolchain.py b/build/profile_toolchain.py index d8874dded572b..e3da6edd3077e 100755 --- a/build/profile_toolchain.py +++ b/build/profile_toolchain.py @@ -1,4 +1,5 @@ -from __future__ import with_statement +#!/usr/bin/env python3 + import contextlib import sys import os @@ -33,36 +34,10 @@ def calculate_hash(root): return CalculateHash('.', None) def windows_installed_software(): - import win32com.client - strComputer = "." - objWMIService = win32com.client.Dispatch("WbemScripting.SWbemLocator") - objSWbemServices = objWMIService.ConnectServer(strComputer, "root\cimv2") - colItems = objSWbemServices.ExecQuery("Select * from Win32_Product") - items = [] - - for objItem in colItems: - item = {} - if objItem.Caption: - item['caption'] = objItem.Caption - if objItem.Caption: - item['description'] = objItem.Description - if objItem.InstallDate: - item['install_date'] = objItem.InstallDate - if objItem.InstallDate2: - item['install_date_2'] = objItem.InstallDate2 - if objItem.InstallLocation: - item['install_location'] = objItem.InstallLocation - if objItem.Name: - item['name'] = objItem.Name - if objItem.SKUNumber: - item['sku_number'] = objItem.SKUNumber - if objItem.Vendor: - item['vendor'] = objItem.Vendor - if objItem.Version: - item['version'] = objItem.Version - items.append(item) - - return items + # file_path = os.path.join(os.getcwd(), 'installed_software.json') + # return json.loads(open('installed_software.json').read().decode('utf-8')) + f = open('installed_software.json', encoding='utf-8-sig') + return json.load(f) def windows_profile(): @@ -70,7 +45,7 @@ def windows_profile(): win_sdk_dir = SetEnvironmentAndGetSDKDir() path = NormalizePath(os.environ['GYP_MSVS_OVERRIDE_PATH']) - # since current windows executable are symbols path dependant, + # since current windows executable are symbols path dependent, # profile the current directory too return { 'pwd': os.getcwd(), @@ -89,7 +64,7 @@ def windows_profile(): def main(options): if sys.platform == 'win32': - with open(options.output_json, 'wb') as f: + with open(options.output_json, 'w') as f: json.dump(windows_profile(), f) else: raise OSError("Unsupported OS") diff --git a/build/rules.gni b/build/rules.gni index c6c383829b1d0..e085af8b914d6 100644 --- a/build/rules.gni +++ b/build/rules.gni @@ -29,7 +29,7 @@ template("compile_ib_files") { _output_extension = invoker.output_extension - script = "//build/config/ios/compile_ib_files.py" + script = "//build/config/apple/compile_ib_files.py" sources = invoker.sources outputs = [ "$target_gen_dir/$target_name/{{source_name_part}}.$_output_extension", @@ -51,7 +51,7 @@ template("compile_ib_files") { # Template to compile and package Mac XIB files as bundle data. # Arguments # sources: -# list of string, sources to comiple +# list of string, sources to compile # output_path: # (optional) string, the path to use for the outputs list in the # bundle_data step. If unspecified, defaults to bundle_resources_dir. @@ -67,10 +67,6 @@ template("mac_xib_bundle_data") { ibtool_flags = [ "--minimum-deployment-target", mac_deployment_target, - - # TODO(rsesek): Enable this once all the bots are on Xcode 7+. - # "--target-device", - # "mac", ] } diff --git a/build/run-in-dir.py b/build/run-in-dir.py index 25fcb21a03b29..ededac1804b3b 100644 --- a/build/run-in-dir.py +++ b/build/run-in-dir.py @@ -1,10 +1,11 @@ import sys import os +import subprocess def main(argv): - cwd = argv[1] - os.chdir(cwd) - os.execv(sys.executable, [sys.executable] + argv[2:]) + os.chdir(argv[1]) + p = subprocess.Popen(argv[2:]) + return p.wait() if __name__ == '__main__': - main(sys.argv) + sys.exit(main(sys.argv)) diff --git a/build/strip_framework.py b/build/strip_framework.py index 1ba173dfc1c18..73cf424dde488 100755 --- a/build/strip_framework.py +++ b/build/strip_framework.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import os import subprocess import sys diff --git a/build/templates/electron_rc.tmpl b/build/templates/electron_rc.tmpl new file mode 100644 index 0000000000000..2f75d9003b84b --- /dev/null +++ b/build/templates/electron_rc.tmpl @@ -0,0 +1,107 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "windows.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""windows.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION $major,$minor,$patch,$prerelease_number + PRODUCTVERSION $major,$minor,$patch,$prerelease_number + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "GitHub, Inc." + VALUE "FileDescription", "Electron" + VALUE "FileVersion", "$major.$minor.$patch" + VALUE "InternalName", "electron.exe" + VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved." + VALUE "OriginalFilename", "electron.exe" + VALUE "ProductName", "Electron" + VALUE "ProductVersion", "$major.$minor.$patch" + VALUE "SquirrelAwareVersion", "1" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +IDR_MAINFRAME ICON "electron.ico" +///////////////////////////////////////////////////////////////////////////// diff --git a/build/templates/version_string.tmpl b/build/templates/version_string.tmpl new file mode 100644 index 0000000000000..02e5f9c0d4f9f --- /dev/null +++ b/build/templates/version_string.tmpl @@ -0,0 +1 @@ +$full_version \ No newline at end of file diff --git a/build/translations/electron_strings_af.xtb b/build/translations/electron_strings_af.xtb new file mode 100644 index 0000000000000..558dca6d70c9e --- /dev/null +++ b/build/translations/electron_strings_af.xtb @@ -0,0 +1,6 @@ + + + + Antwoord + Wys + diff --git a/build/translations/electron_strings_am.xtb b/build/translations/electron_strings_am.xtb new file mode 100644 index 0000000000000..f77bde16e0f34 --- /dev/null +++ b/build/translations/electron_strings_am.xtb @@ -0,0 +1,6 @@ + + + + ምላሽ ስጥ + አሳይ + diff --git a/build/translations/electron_strings_ar.xtb b/build/translations/electron_strings_ar.xtb new file mode 100644 index 0000000000000..b778d339774cd --- /dev/null +++ b/build/translations/electron_strings_ar.xtb @@ -0,0 +1,6 @@ + + + + الرّد + عرض + diff --git a/build/translations/electron_strings_as.xtb b/build/translations/electron_strings_as.xtb new file mode 100644 index 0000000000000..70bb1acff2225 --- /dev/null +++ b/build/translations/electron_strings_as.xtb @@ -0,0 +1,6 @@ + + + + প্ৰত্যুত্তৰ দিয়ক + দেখুৱাওক + diff --git a/build/translations/electron_strings_az.xtb b/build/translations/electron_strings_az.xtb new file mode 100644 index 0000000000000..e277b9786daf1 --- /dev/null +++ b/build/translations/electron_strings_az.xtb @@ -0,0 +1,6 @@ + + + + Cavablayın + Göstərin + diff --git a/build/translations/electron_strings_be.xtb b/build/translations/electron_strings_be.xtb new file mode 100644 index 0000000000000..60025089e14c5 --- /dev/null +++ b/build/translations/electron_strings_be.xtb @@ -0,0 +1,6 @@ + + + + Адказаць + Паказаць + diff --git a/build/translations/electron_strings_bg.xtb b/build/translations/electron_strings_bg.xtb new file mode 100644 index 0000000000000..e46ce28765eb9 --- /dev/null +++ b/build/translations/electron_strings_bg.xtb @@ -0,0 +1,6 @@ + + + + Отговор + Показване + diff --git a/build/translations/electron_strings_bn.xtb b/build/translations/electron_strings_bn.xtb new file mode 100644 index 0000000000000..710e18e2ce9bf --- /dev/null +++ b/build/translations/electron_strings_bn.xtb @@ -0,0 +1,6 @@ + + + + উত্তর দিন + দেখান + diff --git a/build/translations/electron_strings_bs.xtb b/build/translations/electron_strings_bs.xtb new file mode 100644 index 0000000000000..976bbbdd87d73 --- /dev/null +++ b/build/translations/electron_strings_bs.xtb @@ -0,0 +1,6 @@ + + + + Odgovori + Prikaži + diff --git a/build/translations/electron_strings_ca.xtb b/build/translations/electron_strings_ca.xtb new file mode 100644 index 0000000000000..4c2b5daf1d028 --- /dev/null +++ b/build/translations/electron_strings_ca.xtb @@ -0,0 +1,6 @@ + + + + Respon + Mostra + diff --git a/build/translations/electron_strings_cs.xtb b/build/translations/electron_strings_cs.xtb new file mode 100644 index 0000000000000..e2f116faa262e --- /dev/null +++ b/build/translations/electron_strings_cs.xtb @@ -0,0 +1,6 @@ + + + + Odpovědět + Zobrazit + diff --git a/build/translations/electron_strings_cy.xtb b/build/translations/electron_strings_cy.xtb new file mode 100644 index 0000000000000..3b49a34d1e649 --- /dev/null +++ b/build/translations/electron_strings_cy.xtb @@ -0,0 +1,6 @@ + + + + Ateb + Arddangos + diff --git a/build/translations/electron_strings_da.xtb b/build/translations/electron_strings_da.xtb new file mode 100644 index 0000000000000..63acc104ebf41 --- /dev/null +++ b/build/translations/electron_strings_da.xtb @@ -0,0 +1,6 @@ + + + + Svar + Vis + diff --git a/build/translations/electron_strings_de.xtb b/build/translations/electron_strings_de.xtb new file mode 100644 index 0000000000000..adc952549a516 --- /dev/null +++ b/build/translations/electron_strings_de.xtb @@ -0,0 +1,6 @@ + + + + Antworten + Anzeigen + diff --git a/build/translations/electron_strings_el.xtb b/build/translations/electron_strings_el.xtb new file mode 100644 index 0000000000000..148926fda00e1 --- /dev/null +++ b/build/translations/electron_strings_el.xtb @@ -0,0 +1,6 @@ + + + + Απάντηση + Εμφάνιση + diff --git a/build/translations/electron_strings_en-GB.xtb b/build/translations/electron_strings_en-GB.xtb new file mode 100644 index 0000000000000..0d5dd6356b711 --- /dev/null +++ b/build/translations/electron_strings_en-GB.xtb @@ -0,0 +1,6 @@ + + + + Reply + Show + diff --git a/build/translations/electron_strings_es-419.xtb b/build/translations/electron_strings_es-419.xtb new file mode 100644 index 0000000000000..616732a663bc2 --- /dev/null +++ b/build/translations/electron_strings_es-419.xtb @@ -0,0 +1,6 @@ + + + + Responder + Mostrar + diff --git a/build/translations/electron_strings_es.xtb b/build/translations/electron_strings_es.xtb new file mode 100644 index 0000000000000..d9b6f6d4925a3 --- /dev/null +++ b/build/translations/electron_strings_es.xtb @@ -0,0 +1,6 @@ + + + + Responder + Mostrar + diff --git a/build/translations/electron_strings_et.xtb b/build/translations/electron_strings_et.xtb new file mode 100644 index 0000000000000..ab8d7a5865224 --- /dev/null +++ b/build/translations/electron_strings_et.xtb @@ -0,0 +1,6 @@ + + + + Vasta + Kuva + diff --git a/build/translations/electron_strings_eu.xtb b/build/translations/electron_strings_eu.xtb new file mode 100644 index 0000000000000..eb43381c6986a --- /dev/null +++ b/build/translations/electron_strings_eu.xtb @@ -0,0 +1,6 @@ + + + + Erantzun + Erakutsi + diff --git a/build/translations/electron_strings_fa.xtb b/build/translations/electron_strings_fa.xtb new file mode 100644 index 0000000000000..331b5f54926db --- /dev/null +++ b/build/translations/electron_strings_fa.xtb @@ -0,0 +1,6 @@ + + + + پاسخ دادن + نمایش + diff --git a/build/translations/electron_strings_fi.xtb b/build/translations/electron_strings_fi.xtb new file mode 100644 index 0000000000000..50ef7549cb293 --- /dev/null +++ b/build/translations/electron_strings_fi.xtb @@ -0,0 +1,6 @@ + + + + Vastaa + Näytä + diff --git a/build/translations/electron_strings_fil.xtb b/build/translations/electron_strings_fil.xtb new file mode 100644 index 0000000000000..3c0878e734940 --- /dev/null +++ b/build/translations/electron_strings_fil.xtb @@ -0,0 +1,6 @@ + + + + Sumagot + Ipakita + diff --git a/build/translations/electron_strings_fr-CA.xtb b/build/translations/electron_strings_fr-CA.xtb new file mode 100644 index 0000000000000..f857e6c5f4155 --- /dev/null +++ b/build/translations/electron_strings_fr-CA.xtb @@ -0,0 +1,6 @@ + + + + Répondre + Afficher + diff --git a/build/translations/electron_strings_fr.xtb b/build/translations/electron_strings_fr.xtb new file mode 100644 index 0000000000000..ed8a799a338bc --- /dev/null +++ b/build/translations/electron_strings_fr.xtb @@ -0,0 +1,6 @@ + + + + Répondre + Afficher + diff --git a/build/translations/electron_strings_gl.xtb b/build/translations/electron_strings_gl.xtb new file mode 100644 index 0000000000000..05a32705059f7 --- /dev/null +++ b/build/translations/electron_strings_gl.xtb @@ -0,0 +1,6 @@ + + + + Responder + Mostrar + diff --git a/build/translations/electron_strings_gu.xtb b/build/translations/electron_strings_gu.xtb new file mode 100644 index 0000000000000..00dea4767c5fa --- /dev/null +++ b/build/translations/electron_strings_gu.xtb @@ -0,0 +1,6 @@ + + + + જવાબ આપો + બતાવો + diff --git a/build/translations/electron_strings_hi.xtb b/build/translations/electron_strings_hi.xtb new file mode 100644 index 0000000000000..e3cd973ce31e4 --- /dev/null +++ b/build/translations/electron_strings_hi.xtb @@ -0,0 +1,6 @@ + + + + जवाब दें + दिखाएं + diff --git a/build/translations/electron_strings_hr.xtb b/build/translations/electron_strings_hr.xtb new file mode 100644 index 0000000000000..af012dff18164 --- /dev/null +++ b/build/translations/electron_strings_hr.xtb @@ -0,0 +1,6 @@ + + + + Odgovori + Prikaži + diff --git a/build/translations/electron_strings_hu.xtb b/build/translations/electron_strings_hu.xtb new file mode 100644 index 0000000000000..85e24df0f544e --- /dev/null +++ b/build/translations/electron_strings_hu.xtb @@ -0,0 +1,6 @@ + + + + Válasz + Megjelenítés + diff --git a/build/translations/electron_strings_hy.xtb b/build/translations/electron_strings_hy.xtb new file mode 100644 index 0000000000000..ac258a509d6d7 --- /dev/null +++ b/build/translations/electron_strings_hy.xtb @@ -0,0 +1,6 @@ + + + + Պատասխանել + Ցույց տալ + diff --git a/build/translations/electron_strings_id.xtb b/build/translations/electron_strings_id.xtb new file mode 100644 index 0000000000000..4891ad7c1f1bc --- /dev/null +++ b/build/translations/electron_strings_id.xtb @@ -0,0 +1,6 @@ + + + + Balas + Tampilkan + diff --git a/build/translations/electron_strings_is.xtb b/build/translations/electron_strings_is.xtb new file mode 100644 index 0000000000000..949bc95414c4f --- /dev/null +++ b/build/translations/electron_strings_is.xtb @@ -0,0 +1,6 @@ + + + + Svara + Sýna + diff --git a/build/translations/electron_strings_it.xtb b/build/translations/electron_strings_it.xtb new file mode 100644 index 0000000000000..00e615ddc1565 --- /dev/null +++ b/build/translations/electron_strings_it.xtb @@ -0,0 +1,6 @@ + + + + Rispondi + Mostra + diff --git a/build/translations/electron_strings_iw.xtb b/build/translations/electron_strings_iw.xtb new file mode 100644 index 0000000000000..8b7dfa657465a --- /dev/null +++ b/build/translations/electron_strings_iw.xtb @@ -0,0 +1,6 @@ + + + + מענה + הצגה + diff --git a/build/translations/electron_strings_ja.xtb b/build/translations/electron_strings_ja.xtb new file mode 100644 index 0000000000000..0954d5777d325 --- /dev/null +++ b/build/translations/electron_strings_ja.xtb @@ -0,0 +1,6 @@ + + + + 返信 + 表示 + diff --git a/build/translations/electron_strings_ka.xtb b/build/translations/electron_strings_ka.xtb new file mode 100644 index 0000000000000..8c15c50c419fd --- /dev/null +++ b/build/translations/electron_strings_ka.xtb @@ -0,0 +1,6 @@ + + + + პასუხი + ჩვენება + diff --git a/build/translations/electron_strings_kk.xtb b/build/translations/electron_strings_kk.xtb new file mode 100644 index 0000000000000..1c79cc13dd77f --- /dev/null +++ b/build/translations/electron_strings_kk.xtb @@ -0,0 +1,6 @@ + + + + Жауап беру + Көрсету + diff --git a/build/translations/electron_strings_km.xtb b/build/translations/electron_strings_km.xtb new file mode 100644 index 0000000000000..8cb49ea6fbf6c --- /dev/null +++ b/build/translations/electron_strings_km.xtb @@ -0,0 +1,6 @@ + + + + ឆ្លើយតប + បង្ហាញ + diff --git a/build/translations/electron_strings_kn.xtb b/build/translations/electron_strings_kn.xtb new file mode 100644 index 0000000000000..4c291e880f687 --- /dev/null +++ b/build/translations/electron_strings_kn.xtb @@ -0,0 +1,6 @@ + + + + ಪ್ರತ್ಯುತ್ತರಿಸಿ + ತೋರಿಸಿ + diff --git a/build/translations/electron_strings_ko.xtb b/build/translations/electron_strings_ko.xtb new file mode 100644 index 0000000000000..5b3cb81760fb8 --- /dev/null +++ b/build/translations/electron_strings_ko.xtb @@ -0,0 +1,6 @@ + + + + 답장 + 표시 + diff --git a/build/translations/electron_strings_ky.xtb b/build/translations/electron_strings_ky.xtb new file mode 100644 index 0000000000000..7f71cc56963b9 --- /dev/null +++ b/build/translations/electron_strings_ky.xtb @@ -0,0 +1,6 @@ + + + + Жооп берүү + Көрсөтүү + diff --git a/build/translations/electron_strings_lo.xtb b/build/translations/electron_strings_lo.xtb new file mode 100644 index 0000000000000..9ace2c55f328b --- /dev/null +++ b/build/translations/electron_strings_lo.xtb @@ -0,0 +1,6 @@ + + + + ຕອບກັບ + ສະ​ແດງ​ + diff --git a/build/translations/electron_strings_lt.xtb b/build/translations/electron_strings_lt.xtb new file mode 100644 index 0000000000000..23f4a8a0dc8ee --- /dev/null +++ b/build/translations/electron_strings_lt.xtb @@ -0,0 +1,6 @@ + + + + Atsakyti + Rodyti + diff --git a/build/translations/electron_strings_lv.xtb b/build/translations/electron_strings_lv.xtb new file mode 100644 index 0000000000000..2311bd11943f3 --- /dev/null +++ b/build/translations/electron_strings_lv.xtb @@ -0,0 +1,6 @@ + + + + Atbildēt + Rādīt + diff --git a/build/translations/electron_strings_mk.xtb b/build/translations/electron_strings_mk.xtb new file mode 100644 index 0000000000000..548a5a61a7556 --- /dev/null +++ b/build/translations/electron_strings_mk.xtb @@ -0,0 +1,6 @@ + + + + Одговори + Прикажи + diff --git a/build/translations/electron_strings_ml.xtb b/build/translations/electron_strings_ml.xtb new file mode 100644 index 0000000000000..8be3363d3bd6b --- /dev/null +++ b/build/translations/electron_strings_ml.xtb @@ -0,0 +1,6 @@ + + + + മറുപടി നൽകുക + കാണിക്കുക + diff --git a/build/translations/electron_strings_mn.xtb b/build/translations/electron_strings_mn.xtb new file mode 100644 index 0000000000000..c67b355f70742 --- /dev/null +++ b/build/translations/electron_strings_mn.xtb @@ -0,0 +1,6 @@ + + + + Хариулах + Харуулах + diff --git a/build/translations/electron_strings_mr.xtb b/build/translations/electron_strings_mr.xtb new file mode 100644 index 0000000000000..ee91669696b27 --- /dev/null +++ b/build/translations/electron_strings_mr.xtb @@ -0,0 +1,6 @@ + + + + उत्तर द्या + दर्शवा + diff --git a/build/translations/electron_strings_ms.xtb b/build/translations/electron_strings_ms.xtb new file mode 100644 index 0000000000000..f5f125524ceac --- /dev/null +++ b/build/translations/electron_strings_ms.xtb @@ -0,0 +1,6 @@ + + + + Balas + Paparkan + diff --git a/build/translations/electron_strings_my.xtb b/build/translations/electron_strings_my.xtb new file mode 100644 index 0000000000000..cde987adcccd2 --- /dev/null +++ b/build/translations/electron_strings_my.xtb @@ -0,0 +1,6 @@ + + + + စာပြန်ရန် + ပြရန် + diff --git a/build/translations/electron_strings_ne.xtb b/build/translations/electron_strings_ne.xtb new file mode 100644 index 0000000000000..2a0c93b0cad46 --- /dev/null +++ b/build/translations/electron_strings_ne.xtb @@ -0,0 +1,6 @@ + + + + जवाफ दिनुहोस् + देखाउनुहोस् + diff --git a/build/translations/electron_strings_nl.xtb b/build/translations/electron_strings_nl.xtb new file mode 100644 index 0000000000000..974b81bbfb0f3 --- /dev/null +++ b/build/translations/electron_strings_nl.xtb @@ -0,0 +1,6 @@ + + + + Reageren + Tonen + diff --git a/build/translations/electron_strings_no.xtb b/build/translations/electron_strings_no.xtb new file mode 100644 index 0000000000000..95c10acb5ef04 --- /dev/null +++ b/build/translations/electron_strings_no.xtb @@ -0,0 +1,6 @@ + + + + Svar + Vis + diff --git a/build/translations/electron_strings_or.xtb b/build/translations/electron_strings_or.xtb new file mode 100644 index 0000000000000..db993c0dc24d9 --- /dev/null +++ b/build/translations/electron_strings_or.xtb @@ -0,0 +1,6 @@ + + + + ପ୍ରତ୍ୟୁତ୍ତର ଦିଅନ୍ତୁ + ପ୍ରଦର୍ଶନ କରନ୍ତୁ + diff --git a/build/translations/electron_strings_pa.xtb b/build/translations/electron_strings_pa.xtb new file mode 100644 index 0000000000000..d4578d3df5472 --- /dev/null +++ b/build/translations/electron_strings_pa.xtb @@ -0,0 +1,6 @@ + + + + ਜਵਾਬ ਦਿਓ + ਦਿਖਾਓ + diff --git a/build/translations/electron_strings_pl.xtb b/build/translations/electron_strings_pl.xtb new file mode 100644 index 0000000000000..2e1c685a87685 --- /dev/null +++ b/build/translations/electron_strings_pl.xtb @@ -0,0 +1,6 @@ + + + + Odpowiedz + Pokaż + diff --git a/build/translations/electron_strings_pt-BR.xtb b/build/translations/electron_strings_pt-BR.xtb new file mode 100644 index 0000000000000..19c2579e2e149 --- /dev/null +++ b/build/translations/electron_strings_pt-BR.xtb @@ -0,0 +1,6 @@ + + + + Responder + Mostrar + diff --git a/build/translations/electron_strings_pt-PT.xtb b/build/translations/electron_strings_pt-PT.xtb new file mode 100644 index 0000000000000..2d1f1492eac19 --- /dev/null +++ b/build/translations/electron_strings_pt-PT.xtb @@ -0,0 +1,6 @@ + + + + Responder + Mostrar + diff --git a/build/translations/electron_strings_ro.xtb b/build/translations/electron_strings_ro.xtb new file mode 100644 index 0000000000000..2a7b40c6b42a6 --- /dev/null +++ b/build/translations/electron_strings_ro.xtb @@ -0,0 +1,6 @@ + + + + Răspunde + Afișează + diff --git a/build/translations/electron_strings_ru.xtb b/build/translations/electron_strings_ru.xtb new file mode 100644 index 0000000000000..4894d4cccb42d --- /dev/null +++ b/build/translations/electron_strings_ru.xtb @@ -0,0 +1,6 @@ + + + + Ответить + Показать + diff --git a/build/translations/electron_strings_si.xtb b/build/translations/electron_strings_si.xtb new file mode 100644 index 0000000000000..925e08a4b52ed --- /dev/null +++ b/build/translations/electron_strings_si.xtb @@ -0,0 +1,6 @@ + + + + පිළිතුරු දෙන්න + පෙන්වන්න + diff --git a/build/translations/electron_strings_sk.xtb b/build/translations/electron_strings_sk.xtb new file mode 100644 index 0000000000000..1e335cd59e0a7 --- /dev/null +++ b/build/translations/electron_strings_sk.xtb @@ -0,0 +1,6 @@ + + + + Odpovedať + Zobraziť + diff --git a/build/translations/electron_strings_sl.xtb b/build/translations/electron_strings_sl.xtb new file mode 100644 index 0000000000000..b3825792efba6 --- /dev/null +++ b/build/translations/electron_strings_sl.xtb @@ -0,0 +1,6 @@ + + + + Odgovori + Pokaži + diff --git a/build/translations/electron_strings_sq.xtb b/build/translations/electron_strings_sq.xtb new file mode 100644 index 0000000000000..8e13c70e2d5d1 --- /dev/null +++ b/build/translations/electron_strings_sq.xtb @@ -0,0 +1,6 @@ + + + + Përgjigju + Shfaq + diff --git a/build/translations/electron_strings_sr-Latn.xtb b/build/translations/electron_strings_sr-Latn.xtb new file mode 100644 index 0000000000000..713f08b8c835d --- /dev/null +++ b/build/translations/electron_strings_sr-Latn.xtb @@ -0,0 +1,6 @@ + + + + Odgovori + Prikaži + diff --git a/build/translations/electron_strings_sr.xtb b/build/translations/electron_strings_sr.xtb new file mode 100644 index 0000000000000..21bb345c01c80 --- /dev/null +++ b/build/translations/electron_strings_sr.xtb @@ -0,0 +1,6 @@ + + + + Одговори + Прикажи + diff --git a/build/translations/electron_strings_sv.xtb b/build/translations/electron_strings_sv.xtb new file mode 100644 index 0000000000000..2f79d819e80eb --- /dev/null +++ b/build/translations/electron_strings_sv.xtb @@ -0,0 +1,6 @@ + + + + Svara + Visa + diff --git a/build/translations/electron_strings_sw.xtb b/build/translations/electron_strings_sw.xtb new file mode 100644 index 0000000000000..44e640aa8a666 --- /dev/null +++ b/build/translations/electron_strings_sw.xtb @@ -0,0 +1,6 @@ + + + + Jibu + Onyesha + diff --git a/build/translations/electron_strings_ta.xtb b/build/translations/electron_strings_ta.xtb new file mode 100644 index 0000000000000..91d7b82ab020b --- /dev/null +++ b/build/translations/electron_strings_ta.xtb @@ -0,0 +1,6 @@ + + + + பதிலளி + காண்பி + diff --git a/build/translations/electron_strings_te.xtb b/build/translations/electron_strings_te.xtb new file mode 100644 index 0000000000000..b7110dda0709a --- /dev/null +++ b/build/translations/electron_strings_te.xtb @@ -0,0 +1,6 @@ + + + + రిప్లయి ఇవ్వండి + చూపించు + diff --git a/build/translations/electron_strings_th.xtb b/build/translations/electron_strings_th.xtb new file mode 100644 index 0000000000000..f7b93624be794 --- /dev/null +++ b/build/translations/electron_strings_th.xtb @@ -0,0 +1,6 @@ + + + + ตอบ + แสดง + diff --git a/build/translations/electron_strings_tr.xtb b/build/translations/electron_strings_tr.xtb new file mode 100644 index 0000000000000..771ce922e6613 --- /dev/null +++ b/build/translations/electron_strings_tr.xtb @@ -0,0 +1,6 @@ + + + + Yanıtla + Göster + diff --git a/build/translations/electron_strings_uk.xtb b/build/translations/electron_strings_uk.xtb new file mode 100644 index 0000000000000..5b716903665a1 --- /dev/null +++ b/build/translations/electron_strings_uk.xtb @@ -0,0 +1,6 @@ + + + + Відповісти + Показати + diff --git a/build/translations/electron_strings_ur.xtb b/build/translations/electron_strings_ur.xtb new file mode 100644 index 0000000000000..7089f8bb5da5b --- /dev/null +++ b/build/translations/electron_strings_ur.xtb @@ -0,0 +1,6 @@ + + + + جواب دیں + دکھائیں + diff --git a/build/translations/electron_strings_uz.xtb b/build/translations/electron_strings_uz.xtb new file mode 100644 index 0000000000000..bb98dd5ef8b9e --- /dev/null +++ b/build/translations/electron_strings_uz.xtb @@ -0,0 +1,6 @@ + + + + Javob berish + Ko‘rsatish + diff --git a/build/translations/electron_strings_vi.xtb b/build/translations/electron_strings_vi.xtb new file mode 100644 index 0000000000000..949df0c8252e6 --- /dev/null +++ b/build/translations/electron_strings_vi.xtb @@ -0,0 +1,6 @@ + + + + Trả lời + Hiển thị + diff --git a/build/translations/electron_strings_zh-CN.xtb b/build/translations/electron_strings_zh-CN.xtb new file mode 100644 index 0000000000000..b46a597c78b9f --- /dev/null +++ b/build/translations/electron_strings_zh-CN.xtb @@ -0,0 +1,6 @@ + + + + 回复 + 显示 + diff --git a/build/translations/electron_strings_zh-HK.xtb b/build/translations/electron_strings_zh-HK.xtb new file mode 100644 index 0000000000000..898a9587c2484 --- /dev/null +++ b/build/translations/electron_strings_zh-HK.xtb @@ -0,0 +1,6 @@ + + + + 回覆 + 顯示 + diff --git a/build/translations/electron_strings_zh-TW.xtb b/build/translations/electron_strings_zh-TW.xtb new file mode 100644 index 0000000000000..c48485d8a14f3 --- /dev/null +++ b/build/translations/electron_strings_zh-TW.xtb @@ -0,0 +1,6 @@ + + + + 回覆 + 顯示 + diff --git a/build/translations/electron_strings_zu.xtb b/build/translations/electron_strings_zu.xtb new file mode 100644 index 0000000000000..fd47c5331cdb0 --- /dev/null +++ b/build/translations/electron_strings_zu.xtb @@ -0,0 +1,6 @@ + + + + Phendula + Bonisa + diff --git a/build/webpack/webpack.config.asar.js b/build/webpack/webpack.config.asar.js deleted file mode 100644 index 83443f467cad2..0000000000000 --- a/build/webpack/webpack.config.asar.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = require('./webpack.config.base')({ - target: 'asar', - alwaysHasNode: true, - targetDeletesNodeGlobals: true -}); diff --git a/build/webpack/webpack.config.base.js b/build/webpack/webpack.config.base.js index b23ffb95e7748..6cea23eba8afa 100644 --- a/build/webpack/webpack.config.base.js +++ b/build/webpack/webpack.config.base.js @@ -1,16 +1,20 @@ -const fs = require('fs'); -const path = require('path'); -const webpack = require('webpack'); const TerserPlugin = require('terser-webpack-plugin'); +const webpack = require('webpack'); const WrapperPlugin = require('wrapper-webpack-plugin'); +const fs = require('node:fs'); +const path = require('node:path'); + const electronRoot = path.resolve(__dirname, '../..'); class AccessDependenciesPlugin { - apply (compiler) { - compiler.hooks.compilation.tap('AccessDependenciesPlugin', compilation => { - compilation.hooks.finishModules.tap('AccessDependenciesPlugin', modules => { - const filePaths = modules.map(m => m.resource).filter(p => p).map(p => path.relative(electronRoot, p)); + apply(compiler) { + compiler.hooks.compilation.tap('AccessDependenciesPlugin', (compilation) => { + compilation.hooks.finishModules.tap('AccessDependenciesPlugin', (modules) => { + const filePaths = modules + .map((m) => m.resource) + .filter((p) => p) + .map((p) => path.relative(electronRoot, p)); console.info(JSON.stringify(filePaths)); }); }); @@ -30,7 +34,14 @@ module.exports = ({ entry = path.resolve(electronRoot, 'lib', target, 'init.js'); } - const electronAPIFile = path.resolve(electronRoot, 'lib', loadElectronFromAlternateTarget || target, 'api', 'exports', 'electron.ts'); + const electronAPIFile = path.resolve( + electronRoot, + 'lib', + loadElectronFromAlternateTarget || target, + 'api', + 'exports', + 'electron.ts' + ); return (env = {}, argv = {}) => { const onlyPrintingGraph = !!env.PRINT_WEBPACK_GRAPH; @@ -53,27 +64,6 @@ module.exports = ({ const ignoredModules = []; - if (defines.ENABLE_DESKTOP_CAPTURER === 'false') { - ignoredModules.push( - '@electron/internal/browser/desktop-capturer', - '@electron/internal/browser/api/desktop-capturer', - '@electron/internal/renderer/api/desktop-capturer' - ); - } - - if (defines.ENABLE_REMOTE_MODULE === 'false') { - ignoredModules.push( - '@electron/internal/browser/remote/server', - '@electron/internal/renderer/api/remote' - ); - } - - if (defines.ENABLE_VIEWS_API === 'false') { - ignoredModules.push( - '@electron/internal/browser/api/views/image-view.js' - ); - } - const plugins = []; if (onlyPrintingGraph) { @@ -81,41 +71,59 @@ module.exports = ({ } if (targetDeletesNodeGlobals) { - plugins.push(new webpack.ProvidePlugin({ - process: ['@electron/internal/common/webpack-provider', 'process'], - global: ['@electron/internal/common/webpack-provider', '_global'], - Buffer: ['@electron/internal/common/webpack-provider', 'Buffer'] - })); + plugins.push( + new webpack.ProvidePlugin({ + Buffer: ['@electron/internal/common/webpack-provider', 'Buffer'], + global: ['@electron/internal/common/webpack-provider', '_global'], + process: ['@electron/internal/common/webpack-provider', 'process'] + }) + ); + } + + // Webpack 5 no longer polyfills process or Buffer. + if (!alwaysHasNode) { + plugins.push( + new webpack.ProvidePlugin({ + Buffer: ['buffer', 'Buffer'], + process: 'process/browser' + }) + ); } - plugins.push(new webpack.ProvidePlugin({ - Promise: ['@electron/internal/common/webpack-globals-provider', 'Promise'] - })); + plugins.push( + new webpack.ProvidePlugin({ + Promise: ['@electron/internal/common/webpack-globals-provider', 'Promise'] + }) + ); plugins.push(new webpack.DefinePlugin(defines)); if (wrapInitWithProfilingTimeout) { - plugins.push(new WrapperPlugin({ - header: 'function ___electron_webpack_init__() {', - footer: ` + plugins.push( + new WrapperPlugin({ + header: 'function ___electron_webpack_init__() {', + footer: ` }; if ((globalThis.process || binding.process).argv.includes("--profile-electron-init")) { setTimeout(___electron_webpack_init__, 0); } else { ___electron_webpack_init__(); }` - })); + }) + ); } if (wrapInitWithTryCatch) { - plugins.push(new WrapperPlugin({ - header: 'try {', - footer: ` + plugins.push( + new WrapperPlugin({ + header: 'try {', + footer: ` } catch (err) { console.error('Electron ${outputFilename} script failed to run'); console.error(err); }` - })); + }) + ); } return { @@ -133,37 +141,45 @@ if ((globalThis.process || binding.process).argv.includes("--profile-electron-in 'electron/main$': electronAPIFile, 'electron/renderer$': electronAPIFile, 'electron/common$': electronAPIFile, - // Force timers to resolve to our dependency that doesn't use window.postMessage - timers: path.resolve(electronRoot, 'node_modules', 'timers-browserify', 'main.js') + 'electron/utility$': electronAPIFile, + // Force timers to resolve to our own shim that doesn't use window.postMessage + timers: path.resolve(electronRoot, 'lib', 'common', 'timers-shim.ts') }, - extensions: ['.ts', '.js'] + extensions: ['.ts', '.js'], + fallback: { + // We provide our own "timers" import above, any usage of setImmediate inside + // one of our renderer bundles should import it from the 'timers' package + setImmediate: false + } }, module: { - rules: [{ - test: (moduleName) => !onlyPrintingGraph && ignoredModules.includes(moduleName), - loader: 'null-loader' - }, { - test: /\.ts$/, - loader: 'ts-loader', - options: { - configFile: path.resolve(electronRoot, 'tsconfig.electron.json'), - transpileOnly: onlyPrintingGraph, - ignoreDiagnostics: [ - // File '{0}' is not under 'rootDir' '{1}'. - 6059 - ] + rules: [ + { + test: (moduleName) => !onlyPrintingGraph && ignoredModules.includes(moduleName), + loader: 'null-loader' + }, + { + test: /\.ts$/, + loader: 'ts-loader', + options: { + configFile: path.resolve(electronRoot, 'tsconfig.electron.json'), + transpileOnly: onlyPrintingGraph, + ignoreDiagnostics: [ + // File '{0}' is not under 'rootDir' '{1}'. + 6059, + // Private field '{0}' must be declared in an enclosing class. + 1111 + ] + } } - }] + ] }, node: { __dirname: false, - __filename: false, - // We provide our own "timers" import above, any usage of setImmediate inside - // one of our renderer bundles should import it from the 'timers' package - setImmediate: false + __filename: false }, optimization: { - minimize: true, + minimize: env.mode === 'production', minimizer: [ new TerserPlugin({ terserOptions: { diff --git a/build/webpack/webpack.config.node.js b/build/webpack/webpack.config.node.js new file mode 100644 index 0000000000000..875ec4bacb2be --- /dev/null +++ b/build/webpack/webpack.config.node.js @@ -0,0 +1,4 @@ +module.exports = require('./webpack.config.base')({ + target: 'node', + alwaysHasNode: true +}); diff --git a/build/webpack/webpack.config.preload_realm.js b/build/webpack/webpack.config.preload_realm.js new file mode 100644 index 0000000000000..1a776e540d425 --- /dev/null +++ b/build/webpack/webpack.config.preload_realm.js @@ -0,0 +1,6 @@ +module.exports = require('./webpack.config.base')({ + target: 'preload_realm', + alwaysHasNode: false, + wrapInitWithProfilingTimeout: true, + wrapInitWithTryCatch: true +}); diff --git a/build/webpack/webpack.config.utility.js b/build/webpack/webpack.config.utility.js new file mode 100644 index 0000000000000..a80775d18ebab --- /dev/null +++ b/build/webpack/webpack.config.utility.js @@ -0,0 +1,4 @@ +module.exports = require('./webpack.config.base')({ + target: 'utility', + alwaysHasNode: true +}); diff --git a/build/webpack/webpack.gni b/build/webpack/webpack.gni index f2bddbd5ae2bc..8672bfca4cd79 100644 --- a/build/webpack/webpack.gni +++ b/build/webpack/webpack.gni @@ -22,15 +22,24 @@ template("webpack_build") { "//electron/typings/internal-electron.d.ts", ] + invoker.inputs + mode = "development" + if (is_official_build) { + mode = "production" + } + args = [ "--config", rebase_path(invoker.config_file), - "--output-filename=" + get_path_info(invoker.out_file, "file"), - "--output-path=" + rebase_path(get_path_info(invoker.out_file, "dir")), - "--env.buildflags=" + - rebase_path("$target_gen_dir/buildflags/buildflags.h"), + "--output-filename", + get_path_info(invoker.out_file, "file"), + "--output-path", + rebase_path(get_path_info(invoker.out_file, "dir")), + "--env", + "buildflags=" + rebase_path("$target_gen_dir/buildflags/buildflags.h"), + "--env", + "mode=" + mode, ] - deps += [ "buildflags" ] + deps += [ "//electron/buildflags" ] outputs = [ invoker.out_file ] } diff --git a/build/win/abs_link_wrapper.py b/build/win/abs_link_wrapper.py new file mode 100644 index 0000000000000..ae75bfaa313c1 --- /dev/null +++ b/build/win/abs_link_wrapper.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2026 GitHub, Inc. +# Use of this source code is governed by the MIT license that can be +# found in the LICENSE file. + +"""Wrapper for lld-link that resolves relative paths to absolute. + +Usage: abs_link_wrapper.py + +The first argument is the real linker executable. The script resolves +relative .obj/.rlib/.res/.lib paths in both @rspfile contents and direct +command-line arguments to absolute paths, then invokes the real linker. +""" + +import os +import subprocess +import sys + + +def _is_file_path(token): + """Check if a token looks like a relative file path (not a flag or bare lib name).""" + # Strip surrounding quotes + t = token.strip('"') + # Linker flags start with / or - + if t.startswith('/') or t.startswith('-'): + return False + # Must contain a directory separator to be a relative path. + # Bare names like "advapi32.lib" are system libraries resolved via + # -libpath: or /winsysroot and must not be turned into absolute paths. + if '/' not in t and '\\' not in t: + return False + # File extensions we care about + return t.endswith(('.obj', '.res', '.lib', '.a', '.o', '.rlib')) + + +def _resolve_rsp(rsp_path): + """Rewrite relative file paths in the rsp file to absolute paths.""" + with open(rsp_path, 'r') as f: + content = f.read() + + lines = [] + changed = False + for line in content.splitlines(): + tokens = [] + for token in line.split(): + stripped = token.strip('"') + if _is_file_path(token) and not os.path.isabs(stripped): + abs_path = os.path.abspath(stripped) + tokens.append('"' + abs_path + '"') + changed = True + else: + tokens.append(token) + lines.append(' '.join(tokens)) + + if not changed: + return rsp_path + + abs_rsp = rsp_path + '.abs' + with open(abs_rsp, 'w') as f: + f.write('\n'.join(lines)) + return abs_rsp + + +def _resolve_arg(arg): + """Resolve a single command-line argument if it's a relative file path.""" + stripped = arg.strip('"') + if _is_file_path(arg) and not os.path.isabs(stripped): + return os.path.abspath(stripped) + return arg + + +def main(): + args = [] + for arg in sys.argv[1:]: + if arg.startswith('@'): + rsp_path = arg[1:].strip('"') + resolved = _resolve_rsp(rsp_path) + args.append('@' + resolved) + else: + args.append(_resolve_arg(arg)) + + return subprocess.call(args) + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/build/zip.py b/build/zip.py index 8011bc5f4f293..ff9b834054886 100644 --- a/build/zip.py +++ b/build/zip.py @@ -1,5 +1,5 @@ -#!/usr/bin/env python -from __future__ import print_function +#!/usr/bin/env python3 + import os import subprocess import sys @@ -10,7 +10,13 @@ '.mojom.js', '.mojom-lite.js', '.info', - '.m.js' + '.m.js', + + # These are only needed for Chromium tests we don't run. Listed in + # 'extensions' because the mksnapshot zip has these under a subdirectory, and + # the PATHS_TO_SKIP is checked with |startswith|. + 'dbgcore.dll', + 'dbghelp.dll', ] PATHS_TO_SKIP = [ @@ -31,14 +37,12 @@ # //chrome/browser/resources/ssl/ssl_error_assistant, but we don't need to # ship it. 'pyproto', - # On Windows, this binary doesn't exist (the crashpad handler is built-in). - # On MacOS, the binary is called 'chrome_crashpad_handler' and is inside the - # app bundle. - # On Linux, we don't use crashpad, but this binary is still built for some - # reason. Exclude it from the zip. - './crashpad_handler', # Skip because these are outputs that we don't need. 'resources/inspector', + 'gen/third_party/devtools-frontend/src', + 'gen/ui/webui', + # Skip because these get zipped separately in script/zip-symbols.py + 'debug', ] def skip_path(dep, dist_zip, target_cpu): @@ -57,7 +61,7 @@ def skip_path(dep, dist_zip, target_cpu): and dep == "snapshot_blob.bin" ) ) - if should_skip: + if should_skip and os.environ.get('ELECTRON_DEBUG_ZIP_SKIP') == '1': print("Skipping {}".format(dep)) return should_skip @@ -70,7 +74,7 @@ def execute(argv): raise e def main(argv): - dist_zip, runtime_deps, target_cpu, _, flatten_val = argv + dist_zip, runtime_deps, target_cpu, _, flatten_val, flatten_relative_to = argv should_flatten = flatten_val == "true" dist_files = set() with open(runtime_deps) as f: @@ -78,6 +82,11 @@ def main(argv): dep = dep.strip() if not skip_path(dep, dist_zip, target_cpu): dist_files.add(dep) + # On Linux, filter out any files which have a .stripped companion + if sys.platform == 'linux': + dist_files = { + dep for dep in dist_files if f"{dep.removeprefix('./')}.stripped" not in dist_files + } if sys.platform == 'darwin' and not should_flatten: execute(['zip', '-r', '-y', dist_zip] + list(dist_files)) else: @@ -94,14 +103,24 @@ def main(argv): dirname = os.path.dirname(dep) arcname = ( os.path.join(dirname, 'chrome-sandbox') - if basename == 'chrome_sandbox' + if basename.removesuffix('.stripped') == 'chrome_sandbox' else dep ) + name_to_write = arcname + # On Linux, strip the .stripped suffix from the name before zipping + if sys.platform == 'linux': + name_to_write = name_to_write.removesuffix('.stripped') + if should_flatten: + if flatten_relative_to: + if name_to_write.startswith(flatten_relative_to): + name_to_write = name_to_write[len(flatten_relative_to):] + else: + name_to_write = os.path.basename(arcname) + else: + name_to_write = os.path.basename(arcname) z.write( dep, - os.path.basename(arcname) - if should_flatten - else arcname, + name_to_write, ) if __name__ == '__main__': diff --git a/build/zip_libcxx.py b/build/zip_libcxx.py new file mode 100644 index 0000000000000..77e69e9172a52 --- /dev/null +++ b/build/zip_libcxx.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 + +import os +import subprocess +import sys +import zipfile + +def execute(argv): + try: + output = subprocess.check_output(argv, stderr=subprocess.STDOUT) + return output + except subprocess.CalledProcessError as e: + print(e.output) + raise e + +def get_object_files(base_path, archive_name): + archive_file = os.path.join(base_path, archive_name) + output = execute(['nm', '-g', archive_file]).decode('ascii') + object_files = set() + lines = output.split("\n") + for line in lines: + if line.startswith(base_path): + object_file = line.split(":")[0] + object_files.add(object_file) + if line.startswith('nm: '): + object_file = line.split(":")[1].lstrip() + object_files.add(object_file) + return list(object_files) + [archive_file] + +def main(argv): + dist_zip, = argv + out_dir = os.path.dirname(dist_zip) + base_path_libcxx = os.path.join(out_dir, 'obj/buildtools/third_party/libc++') + base_path_libcxxabi = os.path.join(out_dir, 'obj/buildtools/third_party/libc++abi') + object_files_libcxx = get_object_files(base_path_libcxx, 'libc++.a') + object_files_libcxxabi = get_object_files(base_path_libcxxabi, 'libc++abi.a') + with zipfile.ZipFile( + dist_zip, 'w', zipfile.ZIP_DEFLATED, allowZip64=True + ) as z: + object_files_libcxx.sort() + for object_file in object_files_libcxx: + z.write(object_file, os.path.relpath(object_file, base_path_libcxx)) + for object_file in object_files_libcxxabi: + z.write(object_file, os.path.relpath(object_file, base_path_libcxxabi)) + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/buildflags/BUILD.gn b/buildflags/BUILD.gn index 9bd2aba0036a6..ef00ad27f6085 100644 --- a/buildflags/BUILD.gn +++ b/buildflags/BUILD.gn @@ -9,18 +9,20 @@ buildflag_header("buildflags") { header = "buildflags.h" flags = [ - "ENABLE_DESKTOP_CAPTURER=$enable_desktop_capturer", - "ENABLE_RUN_AS_NODE=$enable_run_as_node", - "ENABLE_OSR=$enable_osr", - "ENABLE_REMOTE_MODULE=$enable_remote_module", - "ENABLE_VIEWS_API=$enable_views_api", "ENABLE_PDF_VIEWER=$enable_pdf_viewer", - "ENABLE_TTS=$enable_tts", - "ENABLE_COLOR_CHOOSER=$enable_color_chooser", "ENABLE_ELECTRON_EXTENSIONS=$enable_electron_extensions", "ENABLE_BUILTIN_SPELLCHECKER=$enable_builtin_spellchecker", - "ENABLE_PICTURE_IN_PICTURE=$enable_picture_in_picture", - "ENABLE_WIN_DARK_MODE_WINDOW_UI=$enable_win_dark_mode_window_ui", "OVERRIDE_LOCATION_PROVIDER=$enable_fake_location_provider", ] + + if (electron_vendor_version != "") { + result = string_split(electron_vendor_version, ":") + flags += [ + "HAS_VENDOR_VERSION=true", + "VENDOR_VERSION_NAME=\"${result[0]}\"", + "VENDOR_VERSION_VALUE=\"${result[1]}\"", + ] + } else { + flags += [ "HAS_VENDOR_VERSION=false" ] + } } diff --git a/buildflags/buildflags.gni b/buildflags/buildflags.gni index 95de99fe0a339..801732cb2595b 100644 --- a/buildflags/buildflags.gni +++ b/buildflags/buildflags.gni @@ -3,25 +3,8 @@ # found in the LICENSE file. declare_args() { - enable_desktop_capturer = true - - # Allow running Electron as a node binary. - enable_run_as_node = true - - enable_osr = true - - enable_remote_module = true - - enable_views_api = true - enable_pdf_viewer = true - enable_tts = true - - enable_color_chooser = true - - enable_picture_in_picture = true - # Provide a fake location provider for mocking # the geolocation responses. Disable it if you # need to test with chromium's location provider. @@ -34,6 +17,14 @@ declare_args() { # Enable Spellchecker support enable_builtin_spellchecker = true - # Undocumented Windows dark mode API - enable_win_dark_mode_window_ui = false + # The version of Electron. + # Packagers and vendor builders should set this in gn args to avoid running + # the script that reads git tag. + override_electron_version = "" + + # Define an extra item that will show in process.versions, the value must + # be in the format of "key:value". + # Packagers and vendor builders can set this in gn args to attach extra info + # about the build in the binary. + electron_vendor_version = "" } diff --git a/chromium_src/BUILD.gn b/chromium_src/BUILD.gn index cfafc95dc224b..f152c56da06cb 100644 --- a/chromium_src/BUILD.gn +++ b/chromium_src/BUILD.gn @@ -2,6 +2,7 @@ # Use of this source code is governed by the MIT license that can be # found in the LICENSE file. +import("//build/config/ozone.gni") import("//build/config/ui.gni") import("//components/spellcheck/spellcheck_build_features.gni") import("//electron/buildflags/buildflags.gni") @@ -12,108 +13,245 @@ import("//third_party/widevine/cdm/widevine.gni") static_library("chrome") { visibility = [ "//electron:electron_lib" ] sources = [ - "//chrome/browser/accessibility/accessibility_ui.cc", - "//chrome/browser/accessibility/accessibility_ui.h", + "//ash/style/rounded_rect_cutout_path_builder.cc", + "//ash/style/rounded_rect_cutout_path_builder.h", + "//chrome/browser/app_mode/app_mode_utils.cc", + "//chrome/browser/app_mode/app_mode_utils.h", + "//chrome/browser/browser_features.cc", + "//chrome/browser/browser_features.h", "//chrome/browser/browser_process.cc", "//chrome/browser/browser_process.h", - "//chrome/browser/crash_upload_list/crash_upload_list_crashpad.cc", - "//chrome/browser/crash_upload_list/crash_upload_list_crashpad.h", + "//chrome/browser/device_notifications/device_connection_tracker.h", + "//chrome/browser/device_notifications/device_system_tray_icon.h", "//chrome/browser/devtools/devtools_contents_resizing_strategy.cc", "//chrome/browser/devtools/devtools_contents_resizing_strategy.h", + "//chrome/browser/devtools/devtools_dispatch_http_request_params.cc", + "//chrome/browser/devtools/devtools_dispatch_http_request_params.h", "//chrome/browser/devtools/devtools_embedder_message_dispatcher.cc", "//chrome/browser/devtools/devtools_embedder_message_dispatcher.h", + "//chrome/browser/devtools/devtools_eye_dropper.cc", + "//chrome/browser/devtools/devtools_eye_dropper.h", "//chrome/browser/devtools/devtools_file_system_indexer.cc", "//chrome/browser/devtools/devtools_file_system_indexer.h", - "//chrome/browser/extensions/global_shortcut_listener.cc", - "//chrome/browser/extensions/global_shortcut_listener.h", + "//chrome/browser/devtools/devtools_settings.h", + "//chrome/browser/devtools/features.cc", + "//chrome/browser/devtools/features.h", + "//chrome/browser/devtools/visual_logging.cc", + "//chrome/browser/devtools/visual_logging.h", + "//chrome/browser/file_system_access/file_system_access_features.cc", + "//chrome/browser/file_system_access/file_system_access_features.h", + "//chrome/browser/hid/hid_system_tray_icon.h", "//chrome/browser/icon_loader.cc", "//chrome/browser/icon_loader.h", "//chrome/browser/icon_manager.cc", "//chrome/browser/icon_manager.h", + "//chrome/browser/media/webrtc/delegated_source_list_capturer.cc", + "//chrome/browser/media/webrtc/delegated_source_list_capturer.h", + "//chrome/browser/media/webrtc/desktop_capturer_wrapper.cc", + "//chrome/browser/media/webrtc/desktop_capturer_wrapper.h", + "//chrome/browser/media/webrtc/desktop_media_list.cc", + "//chrome/browser/media/webrtc/desktop_media_list.h", + "//chrome/browser/media/webrtc/desktop_media_list_base.cc", + "//chrome/browser/media/webrtc/desktop_media_list_base.h", + "//chrome/browser/media/webrtc/desktop_media_list_observer.h", + "//chrome/browser/media/webrtc/native_desktop_media_list.cc", + "//chrome/browser/media/webrtc/native_desktop_media_list.h", + "//chrome/browser/media/webrtc/thumbnail_capturer.cc", + "//chrome/browser/media/webrtc/thumbnail_capturer.h", + "//chrome/browser/media/webrtc/window_icon_util.h", "//chrome/browser/net/chrome_mojo_proxy_resolver_factory.cc", "//chrome/browser/net/chrome_mojo_proxy_resolver_factory.h", "//chrome/browser/net/proxy_config_monitor.cc", "//chrome/browser/net/proxy_config_monitor.h", "//chrome/browser/net/proxy_service_factory.cc", "//chrome/browser/net/proxy_service_factory.h", - "//chrome/browser/predictors/preconnect_manager.cc", - "//chrome/browser/predictors/preconnect_manager.h", + "//chrome/browser/picture_in_picture/picture_in_picture_bounds_cache.cc", + "//chrome/browser/picture_in_picture/picture_in_picture_bounds_cache.h", + "//chrome/browser/picture_in_picture/picture_in_picture_occlusion_tracker.cc", + "//chrome/browser/picture_in_picture/picture_in_picture_occlusion_tracker.h", + "//chrome/browser/picture_in_picture/picture_in_picture_occlusion_tracker_observer.cc", + "//chrome/browser/picture_in_picture/picture_in_picture_occlusion_tracker_observer.h", + "//chrome/browser/picture_in_picture/picture_in_picture_widget_fade_animator.cc", + "//chrome/browser/picture_in_picture/picture_in_picture_widget_fade_animator.h", + "//chrome/browser/picture_in_picture/picture_in_picture_window_manager.cc", + "//chrome/browser/picture_in_picture/picture_in_picture_window_manager.h", + "//chrome/browser/picture_in_picture/picture_in_picture_window_manager_uma_helper.cc", + "//chrome/browser/picture_in_picture/picture_in_picture_window_manager_uma_helper.h", + "//chrome/browser/picture_in_picture/scoped_picture_in_picture_occlusion_observation.cc", + "//chrome/browser/picture_in_picture/scoped_picture_in_picture_occlusion_observation.h", + "//chrome/browser/platform_util.cc", + "//chrome/browser/platform_util.h", "//chrome/browser/predictors/predictors_features.cc", "//chrome/browser/predictors/predictors_features.h", - "//chrome/browser/predictors/proxy_lookup_client_impl.cc", - "//chrome/browser/predictors/proxy_lookup_client_impl.h", - "//chrome/browser/predictors/resolve_host_client_impl.cc", - "//chrome/browser/predictors/resolve_host_client_impl.h", - "//chrome/browser/ssl/security_state_tab_helper.cc", - "//chrome/browser/ssl/security_state_tab_helper.h", - "//chrome/browser/ssl/tls_deprecation_config.cc", - "//chrome/browser/ui/views/autofill/autofill_popup_view_utils.cc", - "//chrome/browser/ui/views/autofill/autofill_popup_view_utils.h", + "//chrome/browser/process_singleton.h", + "//chrome/browser/process_singleton_internal.cc", + "//chrome/browser/process_singleton_internal.h", + "//chrome/browser/serial/serial_blocklist.cc", + "//chrome/browser/serial/serial_blocklist.h", + "//chrome/browser/themes/browser_theme_pack.cc", + "//chrome/browser/themes/browser_theme_pack.h", + "//chrome/browser/themes/custom_theme_supplier.cc", + "//chrome/browser/themes/custom_theme_supplier.h", + "//chrome/browser/themes/theme_properties.cc", + "//chrome/browser/themes/theme_properties.h", + "//chrome/browser/ui/color/chrome_color_mixers.cc", + "//chrome/browser/ui/color/chrome_color_mixers.h", + "//chrome/browser/ui/exclusive_access/exclusive_access_bubble_type.cc", + "//chrome/browser/ui/exclusive_access/exclusive_access_bubble_type.h", + "//chrome/browser/ui/exclusive_access/exclusive_access_controller_base.cc", + "//chrome/browser/ui/exclusive_access/exclusive_access_controller_base.h", + "//chrome/browser/ui/exclusive_access/exclusive_access_manager.cc", + "//chrome/browser/ui/exclusive_access/exclusive_access_manager.h", + "//chrome/browser/ui/exclusive_access/exclusive_access_permission_manager.cc", + "//chrome/browser/ui/exclusive_access/exclusive_access_permission_manager.h", + "//chrome/browser/ui/exclusive_access/fullscreen_controller.cc", + "//chrome/browser/ui/exclusive_access/fullscreen_controller.h", + "//chrome/browser/ui/exclusive_access/fullscreen_within_tab_helper.cc", + "//chrome/browser/ui/exclusive_access/fullscreen_within_tab_helper.h", + "//chrome/browser/ui/exclusive_access/keyboard_lock_controller.cc", + "//chrome/browser/ui/exclusive_access/keyboard_lock_controller.h", + "//chrome/browser/ui/exclusive_access/pointer_lock_controller.cc", + "//chrome/browser/ui/exclusive_access/pointer_lock_controller.h", + "//chrome/browser/ui/frame/window_frame_util.cc", + "//chrome/browser/ui/frame/window_frame_util.h", + "//chrome/browser/ui/ui_features.cc", + "//chrome/browser/ui/ui_features.h", + "//chrome/browser/ui/view_ids.h", + "//chrome/browser/ui/views/eye_dropper/eye_dropper.cc", + "//chrome/browser/ui/views/eye_dropper/eye_dropper.h", + "//chrome/browser/ui/views/overlay/back_to_tab_button.cc", + "//chrome/browser/ui/views/overlay/back_to_tab_button.h", + "//chrome/browser/ui/views/overlay/back_to_tab_label_button.cc", + "//chrome/browser/ui/views/overlay/close_image_button.cc", + "//chrome/browser/ui/views/overlay/close_image_button.h", + "//chrome/browser/ui/views/overlay/constants.h", + "//chrome/browser/ui/views/overlay/hang_up_button.cc", + "//chrome/browser/ui/views/overlay/hang_up_button.h", + "//chrome/browser/ui/views/overlay/minimize_button.cc", + "//chrome/browser/ui/views/overlay/minimize_button.h", + "//chrome/browser/ui/views/overlay/overlay_controls_fade_animation.cc", + "//chrome/browser/ui/views/overlay/overlay_controls_fade_animation.h", + "//chrome/browser/ui/views/overlay/overlay_window_image_button.cc", + "//chrome/browser/ui/views/overlay/overlay_window_image_button.h", + "//chrome/browser/ui/views/overlay/overlay_window_live_caption_button.cc", + "//chrome/browser/ui/views/overlay/overlay_window_live_caption_button.h", + "//chrome/browser/ui/views/overlay/playback_image_button.cc", + "//chrome/browser/ui/views/overlay/playback_image_button.h", + "//chrome/browser/ui/views/overlay/resize_handle_button.cc", + "//chrome/browser/ui/views/overlay/resize_handle_button.h", + "//chrome/browser/ui/views/overlay/simple_overlay_window_image_button.cc", + "//chrome/browser/ui/views/overlay/simple_overlay_window_image_button.h", + "//chrome/browser/ui/views/overlay/skip_ad_label_button.cc", + "//chrome/browser/ui/views/overlay/skip_ad_label_button.h", + "//chrome/browser/ui/views/overlay/toggle_camera_button.cc", + "//chrome/browser/ui/views/overlay/toggle_camera_button.h", + "//chrome/browser/ui/views/overlay/toggle_microphone_button.cc", + "//chrome/browser/ui/views/overlay/toggle_microphone_button.h", + "//chrome/browser/ui/views/overlay/toggle_mute_button.cc", + "//chrome/browser/ui/views/overlay/toggle_mute_button.h", + "//chrome/browser/ui/views/overlay/video_overlay_window_views.cc", + "//chrome/browser/ui/views/overlay/video_overlay_window_views.h", + "//chrome/browser/ui/views/picture_in_picture/picture_in_picture_bounds_change_animation.cc", + "//chrome/browser/ui/views/picture_in_picture/picture_in_picture_bounds_change_animation.h", + "//chrome/browser/ui/views/picture_in_picture/picture_in_picture_tucker.cc", + "//chrome/browser/ui/views/picture_in_picture/picture_in_picture_tucker.h", + "//chrome/browser/ui/webui/accessibility/accessibility_ui.cc", + "//chrome/browser/ui/webui/accessibility/accessibility_ui.h", + "//chrome/browser/usb/usb_blocklist.cc", + "//chrome/browser/usb/usb_blocklist.h", + "//chrome/browser/usb/usb_system_tray_icon.h", "//extensions/browser/app_window/size_constraints.cc", "//extensions/browser/app_window/size_constraints.h", + "//ui/base/accelerators/global_accelerator_listener/global_accelerator_listener.cc", + "//ui/base/accelerators/global_accelerator_listener/global_accelerator_listener.h", + "//ui/views/native_window_tracker.h", ] - if (is_mac) { - sources += [ - "//chrome/browser/extensions/global_shortcut_listener_mac.h", - "//chrome/browser/extensions/global_shortcut_listener_mac.mm", - "//chrome/browser/icon_loader_mac.mm", - "//chrome/browser/media/webrtc/system_media_capture_permissions_mac.h", - "//chrome/browser/media/webrtc/system_media_capture_permissions_mac.mm", - ] + if (is_posix) { + sources += [ "//chrome/browser/process_singleton_posix.cc" ] } if (is_win) { sources += [ - "//chrome/browser/extensions/global_shortcut_listener_win.cc", - "//chrome/browser/extensions/global_shortcut_listener_win.h", "//chrome/browser/icon_loader_win.cc", + "//chrome/browser/media/webrtc/window_icon_util_win.cc", + "//chrome/browser/process_singleton_win.cc", "//chrome/browser/win/chrome_process_finder.cc", "//chrome/browser/win/chrome_process_finder.h", + "//chrome/browser/win/chrome_select_file_dialog_factory.cc", + "//chrome/browser/win/chrome_select_file_dialog_factory.h", + "//chrome/browser/win/titlebar_config.cc", + "//chrome/browser/win/titlebar_config.h", + "//chrome/browser/win/util_win_service.cc", + "//chrome/browser/win/util_win_service.h", "//chrome/child/v8_crashpad_support_win.cc", "//chrome/child/v8_crashpad_support_win.h", ] } + if (is_linux) { + sources += [ "//chrome/browser/media/webrtc/window_icon_util_ozone.cc" ] + } + public_deps = [ + "//chrome/browser/resources/accessibility:resources", + "//chrome/browser/ui/color:color_headers", + "//chrome/browser/ui/color:mixers", "//chrome/common", "//chrome/common:version_header", + "//components/global_media_controls", "//components/keyed_service/content", "//components/paint_preview/buildflags", "//components/proxy_config", - "//components/security_state/content", "//content/public/browser", + "//services/strings", ] deps = [ - "//chrome/browser:resource_prefetch_predictor_proto", - "//chrome/services/speech:buildflags", - "//components/optimization_guide/proto:optimization_guide_proto", + "//chrome/app/vector_icons", + "//chrome/browser/predictors:resource_prefetch_predictor_proto", + "//chrome/browser/resource_coordinator:mojo_bindings", + "//chrome/browser/task_manager/common:impl", + "//chrome/browser/ui/webui/tab_search:mojo_bindings", + "//chrome/browser/web_applications/mojom:mojom_web_apps_enum", + "//components/enterprise/buildflags", + "//components/enterprise/common/proto:browser_events_proto", + "//components/enterprise/common/proto:connectors_proto", + "//components/enterprise/obfuscation/core:enterprise_obfuscation", + "//components/safe_browsing/core/browser/db:safebrowsing_proto", + "//components/vector_icons", + "//ui/base/accelerators/global_accelerator_listener", + "//ui/snapshot", + "//ui/views/controls/webview", ] + if (use_aura) { + sources += [ + "//chrome/browser/platform_util_aura.cc", + "//chrome/browser/ui/views/eye_dropper/eye_dropper_aura.cc", + "//ui/native_window_tracker/native_window_tracker_aura.cc", + "//ui/native_window_tracker/native_window_tracker_aura.h", + ] + deps += [ "//components/eye_dropper" ] + } + if (is_linux) { - sources += [ "//chrome/browser/icon_loader_auralinux.cc" ] - if (use_x11) { - sources += [ - "//chrome/browser/extensions/global_shortcut_listener_x11.cc", - "//chrome/browser/extensions/global_shortcut_listener_x11.h", - ] - } else if (use_ozone) { - sources += [ - "//chrome/browser/extensions/global_shortcut_listener_ozone.cc", - "//chrome/browser/extensions/global_shortcut_listener_ozone.h", - ] - } + sources += [ + "//chrome/browser/icon_loader_auralinux.cc", + "//ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux.cc", + "//ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux.h", + ] sources += [ "//chrome/browser/ui/views/status_icons/concat_menu_model.cc", "//chrome/browser/ui/views/status_icons/concat_menu_model.h", "//chrome/browser/ui/views/status_icons/status_icon_linux_dbus.cc", "//chrome/browser/ui/views/status_icons/status_icon_linux_dbus.h", ] - public_deps += [ - "//components/dbus/menu", - "//components/dbus/thread_linux", + sources += [ + "//chrome/browser/ui/views/dark_mode_manager_linux.cc", + "//chrome/browser/ui/views/dark_mode_manager_linux.h", ] + public_deps += [ "//components/dbus" ] } if (is_win) { @@ -121,67 +259,37 @@ static_library("chrome") { "//chrome/browser/win/icon_reader_service.cc", "//chrome/browser/win/icon_reader_service.h", ] - public_deps += [ "//chrome/services/util_win:lib" ] - } - - if (enable_desktop_capturer) { - sources += [ - "//chrome/browser/media/webrtc/desktop_media_list.h", - "//chrome/browser/media/webrtc/desktop_media_list_base.cc", - "//chrome/browser/media/webrtc/desktop_media_list_base.h", - "//chrome/browser/media/webrtc/desktop_media_list_observer.h", - "//chrome/browser/media/webrtc/native_desktop_media_list.cc", - "//chrome/browser/media/webrtc/native_desktop_media_list.h", - "//chrome/browser/media/webrtc/window_icon_util.h", + public_deps += [ + "//chrome/browser/web_applications/proto", + "//chrome/services/util_win:lib", + "//components/webapps/common:mojo_bindings", + ] + deps += [ + "//chrome/services/util_win/public/mojom", + "//components/compose/core/browser:mojo_bindings", + "//components/segmentation_platform/public/proto", ] - deps += [ "//ui/snapshot" ] } - if (enable_color_chooser) { + if (is_mac) { sources += [ - "//chrome/browser/platform_util.cc", - "//chrome/browser/platform_util.h", - "//chrome/browser/ui/browser_dialogs.h", - "//chrome/browser/ui/color_chooser.h", + "//chrome/browser/icon_loader_mac.mm", + "//chrome/browser/media/webrtc/system_media_capture_permissions_mac.h", + "//chrome/browser/media/webrtc/system_media_capture_permissions_mac.mm", + "//chrome/browser/media/webrtc/system_media_capture_permissions_stats_mac.h", + "//chrome/browser/media/webrtc/system_media_capture_permissions_stats_mac.mm", + "//chrome/browser/media/webrtc/thumbnail_capturer_mac.h", + "//chrome/browser/media/webrtc/thumbnail_capturer_mac.mm", + "//chrome/browser/media/webrtc/window_icon_util_mac.mm", + "//chrome/browser/permissions/system/media_authorization_wrapper_mac.h", + "//chrome/browser/platform_util_mac.mm", + "//chrome/browser/process_singleton_mac.mm", + "//chrome/browser/ui/views/eye_dropper/eye_dropper_view_mac.h", + "//chrome/browser/ui/views/eye_dropper/eye_dropper_view_mac.mm", + "//chrome/browser/ui/views/overlay/video_overlay_window_native_widget_mac.h", + "//chrome/browser/ui/views/overlay/video_overlay_window_native_widget_mac.mm", ] - - if (use_aura) { - sources += [ "//chrome/browser/platform_util_aura.cc" ] - - if (!is_win) { - sources += [ - "//chrome/browser/ui/views/color_chooser_aura.cc", - "//chrome/browser/ui/views/color_chooser_aura.h", - ] - } - - deps += [ "//components/feature_engagement" ] - } - - if (is_mac) { - sources += [ - "//chrome/browser/media/webrtc/window_icon_util_mac.mm", - "//chrome/browser/ui/cocoa/color_chooser_mac.h", - "//chrome/browser/ui/cocoa/color_chooser_mac.mm", - ] - deps += [ - "//components/remote_cocoa/app_shim", - "//components/remote_cocoa/browser", - ] - } - - if (is_win) { - sources += [ - "//chrome/browser/media/webrtc/window_icon_util_win.cc", - "//chrome/browser/ui/views/color_chooser_dialog.cc", - "//chrome/browser/ui/views/color_chooser_dialog.h", - "//chrome/browser/ui/views/color_chooser_win.cc", - ] - } - - if (is_linux) { - sources += [ "//chrome/browser/media/webrtc/window_icon_util_x11.cc" ] - } + deps += [ ":system_media_capture_permissions_mac_conflict" ] } if (enable_widevine) { @@ -194,26 +302,47 @@ static_library("chrome") { deps += [ "//components/cdm/renderer" ] } - if (enable_basic_printing) { + if (enable_printing) { sources += [ + "//chrome/browser/bad_message.cc", + "//chrome/browser/bad_message.h", + "//chrome/browser/printing/prefs_util.cc", + "//chrome/browser/printing/prefs_util.h", + "//chrome/browser/printing/print_compositor_util.cc", + "//chrome/browser/printing/print_compositor_util.h", "//chrome/browser/printing/print_job.cc", "//chrome/browser/printing/print_job.h", "//chrome/browser/printing/print_job_manager.cc", "//chrome/browser/printing/print_job_manager.h", "//chrome/browser/printing/print_job_worker.cc", "//chrome/browser/printing/print_job_worker.h", + "//chrome/browser/printing/print_job_worker_oop.cc", + "//chrome/browser/printing/print_job_worker_oop.h", "//chrome/browser/printing/print_view_manager_base.cc", "//chrome/browser/printing/print_view_manager_base.h", - "//chrome/browser/printing/print_view_manager_basic.cc", - "//chrome/browser/printing/print_view_manager_basic.h", "//chrome/browser/printing/printer_query.cc", "//chrome/browser/printing/printer_query.h", - "//chrome/browser/printing/printing_message_filter.cc", - "//chrome/browser/printing/printing_message_filter.h", + "//chrome/browser/printing/printer_query_oop.cc", + "//chrome/browser/printing/printer_query_oop.h", "//chrome/browser/printing/printing_service.cc", "//chrome/browser/printing/printing_service.h", + "//components/printing/browser/print_to_pdf/pdf_print_job.cc", + "//components/printing/browser/print_to_pdf/pdf_print_job.h", + "//components/printing/browser/print_to_pdf/pdf_print_result.cc", + "//components/printing/browser/print_to_pdf/pdf_print_result.h", + "//components/printing/browser/print_to_pdf/pdf_print_utils.cc", + "//components/printing/browser/print_to_pdf/pdf_print_utils.h", ] + if (enable_oop_printing) { + sources += [ + "//chrome/browser/printing/oop_features.cc", + "//chrome/browser/printing/oop_features.h", + "//chrome/browser/printing/print_backend_service_manager.cc", + "//chrome/browser/printing/print_backend_service_manager.h", + ] + } + public_deps += [ "//chrome/services/printing:lib", "//components/printing/browser", @@ -221,6 +350,7 @@ static_library("chrome") { "//components/services/print_compositor", "//components/services/print_compositor/public/cpp", "//components/services/print_compositor/public/mojom", + "//printing/backend", ] deps += [ @@ -232,58 +362,78 @@ static_library("chrome") { sources += [ "//chrome/browser/printing/pdf_to_emf_converter.cc", "//chrome/browser/printing/pdf_to_emf_converter.h", - "//chrome/utility/printing_handler.cc", - "//chrome/utility/printing_handler.h", + "//chrome/browser/printing/printer_xml_parser_impl.cc", + "//chrome/browser/printing/printer_xml_parser_impl.h", + "//chrome/browser/printing/xps_features.cc", + "//chrome/browser/printing/xps_features.h", ] + deps += [ "//printing:printing_base" ] } } - if (enable_picture_in_picture) { - sources += [ - "//chrome/browser/picture_in_picture/picture_in_picture_window_manager.cc", - "//chrome/browser/picture_in_picture/picture_in_picture_window_manager.h", - "//chrome/browser/ui/views/overlay/back_to_tab_image_button.cc", - "//chrome/browser/ui/views/overlay/back_to_tab_image_button.h", - "//chrome/browser/ui/views/overlay/close_image_button.cc", - "//chrome/browser/ui/views/overlay/close_image_button.h", - "//chrome/browser/ui/views/overlay/overlay_window_views.cc", - "//chrome/browser/ui/views/overlay/overlay_window_views.h", - "//chrome/browser/ui/views/overlay/playback_image_button.cc", - "//chrome/browser/ui/views/overlay/playback_image_button.h", - "//chrome/browser/ui/views/overlay/resize_handle_button.cc", - "//chrome/browser/ui/views/overlay/resize_handle_button.h", - "//chrome/browser/ui/views/overlay/skip_ad_label_button.cc", - "//chrome/browser/ui/views/overlay/skip_ad_label_button.h", - "//chrome/browser/ui/views/overlay/track_image_button.cc", - "//chrome/browser/ui/views/overlay/track_image_button.h", - ] - - deps += [ - "//chrome/app/vector_icons", - "//components/vector_icons:vector_icons", - ] - } - if (enable_electron_extensions) { sources += [ "//chrome/browser/extensions/chrome_url_request_util.cc", "//chrome/browser/extensions/chrome_url_request_util.h", "//chrome/browser/plugins/plugin_response_interceptor_url_loader_throttle.cc", "//chrome/browser/plugins/plugin_response_interceptor_url_loader_throttle.h", - "//chrome/renderer/extensions/extension_hooks_delegate.cc", - "//chrome/renderer/extensions/extension_hooks_delegate.h", - "//chrome/renderer/extensions/tabs_hooks_delegate.cc", - "//chrome/renderer/extensions/tabs_hooks_delegate.h", + "//chrome/renderer/extensions/api/extension_hooks_delegate.cc", + "//chrome/renderer/extensions/api/extension_hooks_delegate.h", + "//chrome/renderer/extensions/api/tabs_hooks_delegate.cc", + "//chrome/renderer/extensions/api/tabs_hooks_delegate.h", ] if (enable_pdf_viewer) { sources += [ + "//chrome/browser/pdf/chrome_pdf_stream_delegate.cc", + "//chrome/browser/pdf/chrome_pdf_stream_delegate.h", + "//chrome/browser/pdf/mime_handler_stream_manager.cc", + "//chrome/browser/pdf/mime_handler_stream_manager.h", "//chrome/browser/pdf/pdf_extension_util.cc", "//chrome/browser/pdf/pdf_extension_util.h", - "//chrome/renderer/pepper/chrome_pdf_print_client.cc", - "//chrome/renderer/pepper/chrome_pdf_print_client.h", + "//chrome/browser/pdf/pdf_handler_stream_delegate.cc", + "//chrome/browser/pdf/pdf_handler_stream_delegate.h", + "//chrome/browser/pdf/pdf_help_bubble_handler_factory.cc", + "//chrome/browser/pdf/pdf_help_bubble_handler_factory.h", + "//chrome/browser/plugins/pdf_iframe_navigation_throttle.cc", + "//chrome/browser/plugins/pdf_iframe_navigation_throttle.h", + ] + deps += [ + "//components/pdf/browser", + "//components/pdf/renderer", + "//components/zoom", + "//ui/base/interaction", + "//ui/webui/resources/cr_components/help_bubble:mojo_bindings", ] } + } else { + # These are required by the webRequest module. + sources += [ + "//extensions/browser/api/declarative_net_request/request_action.cc", + "//extensions/browser/api/declarative_net_request/request_action.h", + "//extensions/browser/api/web_request/form_data_parser.cc", + "//extensions/browser/api/web_request/form_data_parser.h", + "//extensions/browser/api/web_request/upload_data_presenter.cc", + "//extensions/browser/api/web_request/upload_data_presenter.h", + "//extensions/browser/api/web_request/web_request_api_constants.cc", + "//extensions/browser/api/web_request/web_request_api_constants.h", + "//extensions/browser/api/web_request/web_request_info.cc", + "//extensions/browser/api/web_request/web_request_info.h", + "//extensions/browser/api/web_request/web_request_resource_type.cc", + "//extensions/browser/api/web_request/web_request_resource_type.h", + "//extensions/browser/extension_api_frame_id_map.cc", + "//extensions/browser/extension_api_frame_id_map.h", + "//extensions/browser/extension_navigation_ui_data.cc", + "//extensions/browser/extension_navigation_ui_data.h", + "//extensions/browser/extensions_browser_client.cc", + "//extensions/browser/extensions_browser_client.h", + "//extensions/browser/guest_view/web_view/web_view_renderer_state.cc", + "//extensions/browser/guest_view/web_view/web_view_renderer_state.h", + ] + + public_deps += [ + "//extensions/browser/api/declarative_net_request/flat:extension_ruleset", + ] } if (!is_mas_build) { @@ -298,55 +448,6 @@ static_library("chrome") { } } -source_set("plugins") { - sources = [] - deps = [] - frameworks = [] - - # browser side - sources += [ - "//chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.cc", - "//chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h", - "//chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.cc", - "//chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.h", - ] - deps += [ - "//media:media_buildflags", - "//ppapi/buildflags", - "//ppapi/proxy:ipc", - "//services/device/public/mojom", - ] - if (enable_pdf_viewer) { - deps += [ "//components/pdf/browser" ] - } - - # renderer side - sources += [ - "//chrome/renderer/pepper/chrome_renderer_pepper_host_factory.cc", - "//chrome/renderer/pepper/chrome_renderer_pepper_host_factory.h", - "//chrome/renderer/pepper/pepper_shared_memory_message_filter.cc", - "//chrome/renderer/pepper/pepper_shared_memory_message_filter.h", - ] - if (enable_pdf_viewer) { - sources += [ - "//chrome/renderer/pepper/pepper_flash_font_file_host.cc", - "//chrome/renderer/pepper/pepper_flash_font_file_host.h", - ] - if (enable_pdf_viewer) { - deps += [ "//components/pdf/renderer" ] - } - } - deps += [ - "//components/strings", - "//media:media_buildflags", - "//ppapi/host", - "//ppapi/proxy", - "//ppapi/proxy:ipc", - "//ppapi/shared_impl", - "//skia", - ] -} - # This source set is just so we don't have to depend on all of //chrome/browser # You may have to add new files here during the upgrade if //chrome/browser/spellchecker # gets more files @@ -358,22 +459,33 @@ source_set("chrome_spellchecker") { if (enable_builtin_spellchecker) { sources += [ + "//chrome/browser/profiles/profile_keyed_service_factory.cc", + "//chrome/browser/profiles/profile_keyed_service_factory.h", + "//chrome/browser/profiles/profile_selections.cc", + "//chrome/browser/profiles/profile_selections.h", "//chrome/browser/spellchecker/spell_check_host_chrome_impl.cc", "//chrome/browser/spellchecker/spell_check_host_chrome_impl.h", + "//chrome/browser/spellchecker/spell_check_initialization_host_impl.cc", + "//chrome/browser/spellchecker/spell_check_initialization_host_impl.h", "//chrome/browser/spellchecker/spellcheck_custom_dictionary.cc", "//chrome/browser/spellchecker/spellcheck_custom_dictionary.h", "//chrome/browser/spellchecker/spellcheck_factory.cc", "//chrome/browser/spellchecker/spellcheck_factory.h", "//chrome/browser/spellchecker/spellcheck_hunspell_dictionary.cc", "//chrome/browser/spellchecker/spellcheck_hunspell_dictionary.h", - "//chrome/browser/spellchecker/spellcheck_language_blocklist_policy_handler.cc", - "//chrome/browser/spellchecker/spellcheck_language_blocklist_policy_handler.h", - "//chrome/browser/spellchecker/spellcheck_language_policy_handler.cc", - "//chrome/browser/spellchecker/spellcheck_language_policy_handler.h", "//chrome/browser/spellchecker/spellcheck_service.cc", "//chrome/browser/spellchecker/spellcheck_service.h", ] + if (!is_mac) { + sources += [ + "//chrome/browser/spellchecker/spellcheck_language_blocklist_policy_handler.cc", + "//chrome/browser/spellchecker/spellcheck_language_blocklist_policy_handler.h", + "//chrome/browser/spellchecker/spellcheck_language_policy_handler.cc", + "//chrome/browser/spellchecker/spellcheck_language_policy_handler.h", + ] + } + if (has_spellcheck_panel) { sources += [ "//chrome/browser/spellchecker/spell_check_panel_host_impl.cc", @@ -404,3 +516,18 @@ source_set("chrome_spellchecker") { "//components/spellcheck/renderer", ] } + +if (is_mac) { + # These sources create an object file conflict with one in |:chrome|, so they + # must live in a separate target. + # Conflicting sources: + # //chrome/browser/media/webrtc/system_media_capture_permissions_stats_mac.mm + # //chrome/browser/permissions/system/system_media_capture_permissions_mac.mm + source_set("system_media_capture_permissions_mac_conflict") { + sources = [ + "//chrome/browser/permissions/system/system_media_capture_permissions_mac.h", + "//chrome/browser/permissions/system/system_media_capture_permissions_mac.mm", + ] + deps = [ "//chrome/common" ] + } +} diff --git a/chromium_src/chrome/browser/certificate_manager_model.cc b/chromium_src/chrome/browser/certificate_manager_model.cc deleted file mode 100644 index 8a38b5370853a..0000000000000 --- a/chromium_src/chrome/browser/certificate_manager_model.cc +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/certificate_manager_model.h" - -#include - -#include "base/bind.h" -#include "base/logging.h" -#include "base/strings/utf_string_conversions.h" -#include "base/task/post_task.h" -#include "content/public/browser/browser_context.h" -#include "content/public/browser/browser_task_traits.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/resource_context.h" -#include "crypto/nss_util.h" -#include "crypto/nss_util_internal.h" -#include "net/base/net_errors.h" -#include "net/cert/nss_cert_database.h" -#include "net/cert/x509_certificate.h" - -using content::BrowserThread; - -namespace { - -net::NSSCertDatabase* g_nss_cert_database = nullptr; - -net::NSSCertDatabase* GetNSSCertDatabaseForResourceContext( - content::ResourceContext* context, - base::OnceCallback callback) { - // This initialization is not thread safe. This CHECK ensures that this code - // is only run on a single thread. - CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); - if (!g_nss_cert_database) { - // Linux has only a single persistent slot compared to ChromeOS's separate - // public and private slot. - // Redirect any slot usage to this persistent slot on Linux. - crypto::EnsureNSSInit(); - g_nss_cert_database = new net::NSSCertDatabase( - crypto::ScopedPK11Slot(PK11_GetInternalKeySlot()) /* public slot */, - crypto::ScopedPK11Slot(PK11_GetInternalKeySlot()) /* private slot */); - } - return g_nss_cert_database; -} - -} // namespace - -// CertificateManagerModel is created on the UI thread. It needs a -// NSSCertDatabase handle (and on ChromeOS it needs to get the TPM status) which -// needs to be done on the IO thread. -// -// The initialization flow is roughly: -// -// UI thread IO Thread -// -// CertificateManagerModel::Create -// \--------------------------------------v -// CertificateManagerModel::GetCertDBOnIOThread -// | -// GetNSSCertDatabaseForResourceContext -// | -// CertificateManagerModel::DidGetCertDBOnIOThread -// v--------------------------------------/ -// CertificateManagerModel::DidGetCertDBOnUIThread -// | -// new CertificateManagerModel -// | -// callback - -// static -void CertificateManagerModel::Create(content::BrowserContext* browser_context, - CreationCallback callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - base::PostTask(FROM_HERE, {BrowserThread::IO}, - base::BindOnce(&CertificateManagerModel::GetCertDBOnIOThread, - browser_context->GetResourceContext(), - std::move(callback))); -} - -CertificateManagerModel::CertificateManagerModel( - net::NSSCertDatabase* nss_cert_database, - bool is_user_db_available) - : cert_db_(nss_cert_database), is_user_db_available_(is_user_db_available) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -CertificateManagerModel::~CertificateManagerModel() = default; - -int CertificateManagerModel::ImportFromPKCS12( - PK11SlotInfo* slot_info, - const std::string& data, - const base::string16& password, - bool is_extractable, - net::ScopedCERTCertificateList* imported_certs) { - return cert_db_->ImportFromPKCS12(slot_info, data, password, is_extractable, - imported_certs); -} - -int CertificateManagerModel::ImportUserCert(const std::string& data) { - return cert_db_->ImportUserCert(data); -} - -bool CertificateManagerModel::ImportCACerts( - const net::ScopedCERTCertificateList& certificates, - net::NSSCertDatabase::TrustBits trust_bits, - net::NSSCertDatabase::ImportCertFailureList* not_imported) { - return cert_db_->ImportCACerts(certificates, trust_bits, not_imported); -} - -bool CertificateManagerModel::ImportServerCert( - const net::ScopedCERTCertificateList& certificates, - net::NSSCertDatabase::TrustBits trust_bits, - net::NSSCertDatabase::ImportCertFailureList* not_imported) { - return cert_db_->ImportServerCert(certificates, trust_bits, not_imported); -} - -bool CertificateManagerModel::SetCertTrust( - CERTCertificate* cert, - net::CertType type, - net::NSSCertDatabase::TrustBits trust_bits) { - return cert_db_->SetCertTrust(cert, type, trust_bits); -} - -bool CertificateManagerModel::Delete(CERTCertificate* cert) { - return cert_db_->DeleteCertAndKey(cert); -} - -// static -void CertificateManagerModel::DidGetCertDBOnUIThread( - net::NSSCertDatabase* cert_db, - bool is_user_db_available, - CreationCallback callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - std::unique_ptr model( - new CertificateManagerModel(cert_db, is_user_db_available)); - std::move(callback).Run(std::move(model)); -} - -// static -void CertificateManagerModel::DidGetCertDBOnIOThread( - CreationCallback callback, - net::NSSCertDatabase* cert_db) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - - bool is_user_db_available = !!cert_db->GetPublicSlot(); - base::PostTask( - FROM_HERE, {BrowserThread::UI}, - base::BindOnce(&CertificateManagerModel::DidGetCertDBOnUIThread, cert_db, - is_user_db_available, std::move(callback))); -} - -// static -void CertificateManagerModel::GetCertDBOnIOThread( - content::ResourceContext* context, - CreationCallback callback) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - - auto did_get_cert_db_callback = base::AdaptCallbackForRepeating( - base::BindOnce(&CertificateManagerModel::DidGetCertDBOnIOThread, - std::move(callback))); - - net::NSSCertDatabase* cert_db = - GetNSSCertDatabaseForResourceContext(context, did_get_cert_db_callback); - - // If the NSS database was already available, |cert_db| is non-null and - // |did_get_cert_db_callback| has not been called. Call it explicitly. - if (cert_db) - did_get_cert_db_callback.Run(cert_db); -} diff --git a/chromium_src/chrome/browser/certificate_manager_model.h b/chromium_src/chrome/browser/certificate_manager_model.h deleted file mode 100644 index b68a650e24b1e..0000000000000 --- a/chromium_src/chrome/browser/certificate_manager_model.h +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_CERTIFICATE_MANAGER_MODEL_H_ -#define CHROME_BROWSER_CERTIFICATE_MANAGER_MODEL_H_ - -#include -#include -#include - -#include "base/callback.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/strings/string16.h" -#include "net/cert/nss_cert_database.h" - -namespace content { -class BrowserContext; -class ResourceContext; -} // namespace content - -// CertificateManagerModel provides the data to be displayed in the certificate -// manager dialog, and processes changes from the view. -class CertificateManagerModel { - public: - using CreationCallback = - base::OnceCallback)>; - - // Creates a CertificateManagerModel. The model will be passed to the callback - // when it is ready. The caller must ensure the model does not outlive the - // |browser_context|. - static void Create(content::BrowserContext* browser_context, - CreationCallback callback); - - ~CertificateManagerModel(); - - bool is_user_db_available() const { return is_user_db_available_; } - - // Accessor for read-only access to the underlying NSSCertDatabase. - const net::NSSCertDatabase* cert_db() const { return cert_db_; } - - // Import private keys and certificates from PKCS #12 encoded - // |data|, using the given |password|. If |is_extractable| is false, - // mark the private key as unextractable from the module. - // Returns a net error code on failure. - int ImportFromPKCS12(PK11SlotInfo* slot_info, - const std::string& data, - const base::string16& password, - bool is_extractable, - net::ScopedCERTCertificateList* imported_certs); - - // Import user certificate from DER encoded |data|. - // Returns a net error code on failure. - int ImportUserCert(const std::string& data); - - // Import CA certificates. - // Tries to import all the certificates given. The root will be trusted - // according to |trust_bits|. Any certificates that could not be imported - // will be listed in |not_imported|. - // |trust_bits| should be a bit field of TRUST* values from NSSCertDatabase. - // Returns false if there is an internal error, otherwise true is returned and - // |not_imported| should be checked for any certificates that were not - // imported. - bool ImportCACerts(const net::ScopedCERTCertificateList& certificates, - net::NSSCertDatabase::TrustBits trust_bits, - net::NSSCertDatabase::ImportCertFailureList* not_imported); - - // Import server certificate. The first cert should be the server cert. Any - // additional certs should be intermediate/CA certs and will be imported but - // not given any trust. - // Any certificates that could not be imported will be listed in - // |not_imported|. - // |trust_bits| can be set to explicitly trust or distrust the certificate, or - // use TRUST_DEFAULT to inherit trust as normal. - // Returns false if there is an internal error, otherwise true is returned and - // |not_imported| should be checked for any certificates that were not - // imported. - bool ImportServerCert( - const net::ScopedCERTCertificateList& certificates, - net::NSSCertDatabase::TrustBits trust_bits, - net::NSSCertDatabase::ImportCertFailureList* not_imported); - - // Set trust values for certificate. - // |trust_bits| should be a bit field of TRUST* values from NSSCertDatabase. - // Returns true on success or false on failure. - bool SetCertTrust(CERTCertificate* cert, - net::CertType type, - net::NSSCertDatabase::TrustBits trust_bits); - - // Delete the cert. Returns true on success. |cert| is still valid when this - // function returns. - bool Delete(CERTCertificate* cert); - - private: - CertificateManagerModel(net::NSSCertDatabase* nss_cert_database, - bool is_user_db_available); - - // Methods used during initialization, see the comment at the top of the .cc - // file for details. - static void DidGetCertDBOnUIThread(net::NSSCertDatabase* cert_db, - bool is_user_db_available, - CreationCallback callback); - static void DidGetCertDBOnIOThread(CreationCallback callback, - net::NSSCertDatabase* cert_db); - static void GetCertDBOnIOThread(content::ResourceContext* context, - CreationCallback callback); - - net::NSSCertDatabase* cert_db_; - // Whether the certificate database has a public slot associated with the - // profile. If not set, importing certificates is not allowed with this model. - bool is_user_db_available_; - - DISALLOW_COPY_AND_ASSIGN(CertificateManagerModel); -}; - -#endif // CHROME_BROWSER_CERTIFICATE_MANAGER_MODEL_H_ diff --git a/chromium_src/chrome/browser/process_singleton.h b/chromium_src/chrome/browser/process_singleton.h deleted file mode 100644 index 2e1436846421a..0000000000000 --- a/chromium_src/chrome/browser/process_singleton.h +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_PROCESS_SINGLETON_H_ -#define CHROME_BROWSER_PROCESS_SINGLETON_H_ - -#if defined(OS_WIN) -#include -#endif // defined(OS_WIN) - -#include -#include - -#include "base/callback.h" -#include "base/command_line.h" -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/memory/ref_counted.h" -#include "base/process/process.h" -#include "base/sequence_checker.h" -#include "ui/gfx/native_widget_types.h" - -#if defined(OS_POSIX) && !defined(OS_ANDROID) -#include "base/files/scoped_temp_dir.h" -#endif - -#if defined(OS_WIN) -#include "base/win/message_window.h" -#endif // defined(OS_WIN) - -namespace base { -class CommandLine; -} - -// ProcessSingleton ---------------------------------------------------------- -// -// This class allows different browser processes to communicate with -// each other. It is named according to the user data directory, so -// we can be sure that no more than one copy of the application can be -// running at once with a given data directory. -// -// Implementation notes: -// - the Windows implementation uses an invisible global message window; -// - the Linux implementation uses a Unix domain socket in the user data dir. - -class ProcessSingleton { - public: - enum NotifyResult { - PROCESS_NONE, - PROCESS_NOTIFIED, - PROFILE_IN_USE, - LOCK_ERROR, - }; - - // Implement this callback to handle notifications from other processes. The - // callback will receive the command line and directory with which the other - // Chrome process was launched. Return true if the command line will be - // handled within the current browser instance or false if the remote process - // should handle it (i.e., because the current process is shutting down). - using NotificationCallback = base::RepeatingCallback; - - ProcessSingleton(const base::FilePath& user_data_dir, - const NotificationCallback& notification_callback); - ~ProcessSingleton(); - - // Notify another process, if available. Otherwise sets ourselves as the - // singleton instance. Returns PROCESS_NONE if we became the singleton - // instance. Callers are guaranteed to either have notified an existing - // process or have grabbed the singleton (unless the profile is locked by an - // unreachable process). - // TODO(brettw): Make the implementation of this method non-platform-specific - // by making Linux re-use the Windows implementation. - NotifyResult NotifyOtherProcessOrCreate(); - void StartListeningOnSocket(); - void OnBrowserReady(); - - // Sets ourself up as the singleton instance. Returns true on success. If - // false is returned, we are not the singleton instance and the caller must - // exit. - // NOTE: Most callers should generally prefer NotifyOtherProcessOrCreate() to - // this method, only callers for whom failure is preferred to notifying - // another process should call this directly. - bool Create(); - - // Clear any lock state during shutdown. - void Cleanup(); - -#if defined(OS_POSIX) && !defined(OS_ANDROID) - static void DisablePromptForTesting(); -#endif -#if defined(OS_WIN) - // Called to query whether to kill a hung browser process that has visible - // windows. Return true to allow killing the hung process. - using ShouldKillRemoteProcessCallback = base::RepeatingCallback; - void OverrideShouldKillRemoteProcessCallbackForTesting( - const ShouldKillRemoteProcessCallback& display_dialog_callback); -#endif - - protected: - // Notify another process, if available. - // Returns true if another process was found and notified, false if we should - // continue with the current process. - // On Windows, Create() has to be called before this. - NotifyResult NotifyOtherProcess(); - -#if defined(OS_POSIX) && !defined(OS_ANDROID) - // Exposed for testing. We use a timeout on Linux, and in tests we want - // this timeout to be short. - NotifyResult NotifyOtherProcessWithTimeout( - const base::CommandLine& command_line, - int retry_attempts, - const base::TimeDelta& timeout, - bool kill_unresponsive); - NotifyResult NotifyOtherProcessWithTimeoutOrCreate( - const base::CommandLine& command_line, - int retry_attempts, - const base::TimeDelta& timeout); - void OverrideCurrentPidForTesting(base::ProcessId pid); - void OverrideKillCallbackForTesting( - const base::RepeatingCallback& callback); -#endif - - private: - NotificationCallback notification_callback_; // Handler for notifications. - -#if defined(OS_WIN) - HWND remote_window_; // The HWND_MESSAGE of another browser. - base::win::MessageWindow window_; // The message-only window. - bool is_virtualized_; // Stuck inside Microsoft Softricity VM environment. - HANDLE lock_file_; - base::FilePath user_data_dir_; - ShouldKillRemoteProcessCallback should_kill_remote_process_callback_; -#elif defined(OS_POSIX) && !defined(OS_ANDROID) - // Start listening to the socket. - void StartListening(int sock); - - // Return true if the given pid is one of our child processes. - // Assumes that the current pid is the root of all pids of the current - // instance. - bool IsSameChromeInstance(pid_t pid); - - // Extract the process's pid from a symbol link path and if it is on - // the same host, kill the process, unlink the lock file and return true. - // If the process is part of the same chrome instance, unlink the lock file - // and return true without killing it. - // If the process is on a different host, return false. - bool KillProcessByLockPath(); - - // Default function to kill a process, overridable by tests. - void KillProcess(int pid); - - // Allow overriding for tests. - base::ProcessId current_pid_; - - // Function to call when the other process is hung and needs to be killed. - // Allows overriding for tests. - base::Callback kill_callback_; - - // Path in file system to the socket. - base::FilePath socket_path_; - - // Path in file system to the lock. - base::FilePath lock_path_; - - // Path in file system to the cookie file. - base::FilePath cookie_path_; - - // Temporary directory to hold the socket. - base::ScopedTempDir socket_dir_; - - // Helper class for linux specific messages. LinuxWatcher is ref counted - // because it posts messages between threads. - class LinuxWatcher; - scoped_refptr watcher_; - int sock_; - bool listen_on_ready_ = false; -#endif - - SEQUENCE_CHECKER(sequence_checker_); - - DISALLOW_COPY_AND_ASSIGN(ProcessSingleton); -}; - -#endif // CHROME_BROWSER_PROCESS_SINGLETON_H_ diff --git a/chromium_src/chrome/browser/process_singleton_posix.cc b/chromium_src/chrome/browser/process_singleton_posix.cc deleted file mode 100644 index ab74dcc6e1989..0000000000000 --- a/chromium_src/chrome/browser/process_singleton_posix.cc +++ /dev/null @@ -1,1103 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// On Linux, when the user tries to launch a second copy of chrome, we check -// for a socket in the user's profile directory. If the socket file is open we -// send a message to the first chrome browser process with the current -// directory and second process command line flags. The second process then -// exits. -// -// Because many networked filesystem implementations do not support unix domain -// sockets, we create the socket in a temporary directory and create a symlink -// in the profile. This temporary directory is no longer bound to the profile, -// and may disappear across a reboot or login to a separate session. To bind -// them, we store a unique cookie in the profile directory, which must also be -// present in the remote directory to connect. The cookie is checked both before -// and after the connection. /tmp is sticky, and different Chrome sessions use -// different cookies. Thus, a matching cookie before and after means the -// connection was to a directory with a valid cookie. -// -// We also have a lock file, which is a symlink to a non-existent destination. -// The destination is a string containing the hostname and process id of -// chrome's browser process, eg. "SingletonLock -> example.com-9156". When the -// first copy of chrome exits it will delete the lock file on shutdown, so that -// a different instance on a different host may then use the profile directory. -// -// If writing to the socket fails, the hostname in the lock is checked to see if -// another instance is running a different host using a shared filesystem (nfs, -// etc.) If the hostname differs an error is displayed and the second process -// exits. Otherwise the first process (if any) is killed and the second process -// starts as normal. -// -// When the second process sends the current directory and command line flags to -// the first process, it waits for an ACK message back from the first process -// for a certain time. If there is no ACK message back in time, then the first -// process will be considered as hung for some reason. The second process then -// retrieves the process id from the symbol link and kills it by sending -// SIGKILL. Then the second process starts as normal. - -#include "chrome/browser/process_singleton.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include "shell/browser/browser.h" -#include "shell/common/electron_command_line.h" - -#include "base/base_paths.h" -#include "base/bind.h" -#include "base/command_line.h" -#include "base/files/file_descriptor_watcher_posix.h" -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/location.h" -#include "base/logging.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/metrics/histogram_macros.h" -#include "base/path_service.h" -#include "base/posix/eintr_wrapper.h" -#include "base/posix/safe_strerror.h" -#include "base/rand_util.h" -#include "base/sequenced_task_runner_helpers.h" -#include "base/single_thread_task_runner.h" -#include "base/stl_util.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_split.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" -#include "base/strings/sys_string_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "base/task/post_task.h" -#include "base/threading/platform_thread.h" -#include "base/threading/thread_restrictions.h" -#include "base/threading/thread_task_runner_handle.h" -#include "base/time/time.h" -#include "base/timer/timer.h" -#include "build/build_config.h" -#include "content/public/browser/browser_task_traits.h" -#include "content/public/browser/browser_thread.h" -#include "net/base/network_interfaces.h" - -#if defined(TOOLKIT_VIEWS) && defined(OS_LINUX) && !defined(OS_CHROMEOS) -#include "ui/views/linux_ui/linux_ui.h" -#endif - -using content::BrowserThread; - -namespace { - -// Timeout for the current browser process to respond. 20 seconds should be -// enough. -const int kTimeoutInSeconds = 20; -// Number of retries to notify the browser. 20 retries over 20 seconds = 1 try -// per second. -const int kRetryAttempts = 20; -static bool g_disable_prompt; -const char kStartToken[] = "START"; -const char kACKToken[] = "ACK"; -const char kShutdownToken[] = "SHUTDOWN"; -const char kTokenDelimiter = '\0'; -const int kMaxMessageLength = 32 * 1024; -const int kMaxACKMessageLength = base::size(kShutdownToken) - 1; - -const char kLockDelimiter = '-'; - -const base::FilePath::CharType kSingletonCookieFilename[] = - FILE_PATH_LITERAL("SingletonCookie"); - -const base::FilePath::CharType kSingletonLockFilename[] = - FILE_PATH_LITERAL("SingletonLock"); -const base::FilePath::CharType kSingletonSocketFilename[] = - FILE_PATH_LITERAL("SS"); - -// Set the close-on-exec bit on a file descriptor. -// Returns 0 on success, -1 on failure. -int SetCloseOnExec(int fd) { - int flags = fcntl(fd, F_GETFD, 0); - if (-1 == flags) - return flags; - if (flags & FD_CLOEXEC) - return 0; - return fcntl(fd, F_SETFD, flags | FD_CLOEXEC); -} - -// Close a socket and check return value. -void CloseSocket(int fd) { - int rv = IGNORE_EINTR(close(fd)); - DCHECK_EQ(0, rv) << "Error closing socket: " << base::safe_strerror(errno); -} - -// Write a message to a socket fd. -bool WriteToSocket(int fd, const char* message, size_t length) { - DCHECK(message); - DCHECK(length); - size_t bytes_written = 0; - do { - ssize_t rv = HANDLE_EINTR( - write(fd, message + bytes_written, length - bytes_written)); - if (rv < 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK) { - // The socket shouldn't block, we're sending so little data. Just give - // up here, since NotifyOtherProcess() doesn't have an asynchronous api. - LOG(ERROR) << "ProcessSingleton would block on write(), so it gave up."; - return false; - } - PLOG(ERROR) << "write() failed"; - return false; - } - bytes_written += rv; - } while (bytes_written < length); - - return true; -} - -struct timeval TimeDeltaToTimeVal(const base::TimeDelta& delta) { - struct timeval result; - result.tv_sec = delta.InSeconds(); - result.tv_usec = delta.InMicroseconds() % base::Time::kMicrosecondsPerSecond; - return result; -} - -// Wait a socket for read for a certain timeout. -// Returns -1 if error occurred, 0 if timeout reached, > 0 if the socket is -// ready for read. -int WaitSocketForRead(int fd, const base::TimeDelta& timeout) { - fd_set read_fds; - struct timeval tv = TimeDeltaToTimeVal(timeout); - - FD_ZERO(&read_fds); - FD_SET(fd, &read_fds); - - return HANDLE_EINTR(select(fd + 1, &read_fds, nullptr, nullptr, &tv)); -} - -// Read a message from a socket fd, with an optional timeout. -// If |timeout| <= 0 then read immediately. -// Return number of bytes actually read, or -1 on error. -ssize_t ReadFromSocket(int fd, - char* buf, - size_t bufsize, - const base::TimeDelta& timeout) { - if (timeout > base::TimeDelta()) { - int rv = WaitSocketForRead(fd, timeout); - if (rv <= 0) - return rv; - } - - size_t bytes_read = 0; - do { - ssize_t rv = HANDLE_EINTR(read(fd, buf + bytes_read, bufsize - bytes_read)); - if (rv < 0) { - if (errno != EAGAIN && errno != EWOULDBLOCK) { - PLOG(ERROR) << "read() failed"; - return rv; - } else { - // It would block, so we just return what has been read. - return bytes_read; - } - } else if (!rv) { - // No more data to read. - return bytes_read; - } else { - bytes_read += rv; - } - } while (bytes_read < bufsize); - - return bytes_read; -} - -// Set up a sockaddr appropriate for messaging. -void SetupSockAddr(const std::string& path, struct sockaddr_un* addr) { - addr->sun_family = AF_UNIX; - CHECK(path.length() < base::size(addr->sun_path)) - << "Socket path too long: " << path; - base::strlcpy(addr->sun_path, path.c_str(), base::size(addr->sun_path)); -} - -// Set up a socket appropriate for messaging. -int SetupSocketOnly() { - int sock = socket(PF_UNIX, SOCK_STREAM, 0); - PCHECK(sock >= 0) << "socket() failed"; - - DCHECK(base::SetNonBlocking(sock)) << "Failed to make non-blocking socket."; - int rv = SetCloseOnExec(sock); - DCHECK_EQ(0, rv) << "Failed to set CLOEXEC on socket."; - - return sock; -} - -// Set up a socket and sockaddr appropriate for messaging. -void SetupSocket(const std::string& path, int* sock, struct sockaddr_un* addr) { - *sock = SetupSocketOnly(); - SetupSockAddr(path, addr); -} - -// Read a symbolic link, return empty string if given path is not a symbol link. -base::FilePath ReadLink(const base::FilePath& path) { - base::FilePath target; - if (!base::ReadSymbolicLink(path, &target)) { - // The only errno that should occur is ENOENT. - if (errno != 0 && errno != ENOENT) - PLOG(ERROR) << "readlink(" << path.value() << ") failed"; - } - return target; -} - -// Unlink a path. Return true on success. -bool UnlinkPath(const base::FilePath& path) { - int rv = unlink(path.value().c_str()); - if (rv < 0 && errno != ENOENT) - PLOG(ERROR) << "Failed to unlink " << path.value(); - - return rv == 0; -} - -// Create a symlink. Returns true on success. -bool SymlinkPath(const base::FilePath& target, const base::FilePath& path) { - if (!base::CreateSymbolicLink(target, path)) { - // Double check the value in case symlink suceeded but we got an incorrect - // failure due to NFS packet loss & retry. - int saved_errno = errno; - if (ReadLink(path) != target) { - // If we failed to create the lock, most likely another instance won the - // startup race. - errno = saved_errno; - PLOG(ERROR) << "Failed to create " << path.value(); - return false; - } - } - return true; -} - -// Extract the hostname and pid from the lock symlink. -// Returns true if the lock existed. -bool ParseLockPath(const base::FilePath& path, - std::string* hostname, - int* pid) { - std::string real_path = ReadLink(path).value(); - if (real_path.empty()) - return false; - - std::string::size_type pos = real_path.rfind(kLockDelimiter); - - // If the path is not a symbolic link, or doesn't contain what we expect, - // bail. - if (pos == std::string::npos) { - *hostname = ""; - *pid = -1; - return true; - } - - *hostname = real_path.substr(0, pos); - - const std::string& pid_str = real_path.substr(pos + 1); - if (!base::StringToInt(pid_str, pid)) - *pid = -1; - - return true; -} - -// Returns true if the user opted to unlock the profile. -bool DisplayProfileInUseError(const base::FilePath& lock_path, - const std::string& hostname, - int pid) { - return true; -} - -bool IsChromeProcess(pid_t pid) { - base::FilePath other_chrome_path(base::GetProcessExecutablePath(pid)); - - auto* command_line = base::CommandLine::ForCurrentProcess(); - base::FilePath exec_path(command_line->GetProgram()); - base::PathService::Get(base::FILE_EXE, &exec_path); - - return (!other_chrome_path.empty() && - other_chrome_path.BaseName() == exec_path.BaseName()); -} - -// A helper class to hold onto a socket. -class ScopedSocket { - public: - ScopedSocket() : fd_(-1) { Reset(); } - ~ScopedSocket() { Close(); } - int fd() { return fd_; } - void Reset() { - Close(); - fd_ = SetupSocketOnly(); - } - void Close() { - if (fd_ >= 0) - CloseSocket(fd_); - fd_ = -1; - } - - private: - int fd_; -}; - -// Returns a random string for uniquifying profile connections. -std::string GenerateCookie() { - return base::NumberToString(base::RandUint64()); -} - -bool CheckCookie(const base::FilePath& path, const base::FilePath& cookie) { - return (cookie == ReadLink(path)); -} - -bool IsAppSandboxed() { -#if defined(OS_MAC) - // NB: There is no sane API for this, we have to just guess by - // reading tea leaves - base::FilePath home_dir; - if (!base::PathService::Get(base::DIR_HOME, &home_dir)) { - return false; - } - - return home_dir.value().find("Library/Containers") != std::string::npos; -#else - return false; -#endif // defined(OS_MAC) -} - -bool ConnectSocket(ScopedSocket* socket, - const base::FilePath& socket_path, - const base::FilePath& cookie_path) { - base::FilePath socket_target; - if (base::ReadSymbolicLink(socket_path, &socket_target)) { - // It's a symlink. Read the cookie. - base::FilePath cookie = ReadLink(cookie_path); - if (cookie.empty()) - return false; - base::FilePath remote_cookie = - socket_target.DirName().Append(kSingletonCookieFilename); - // Verify the cookie before connecting. - if (!CheckCookie(remote_cookie, cookie)) - return false; - // Now we know the directory was (at that point) created by the profile - // owner. Try to connect. - sockaddr_un addr; - SetupSockAddr(socket_target.value(), &addr); - int ret = HANDLE_EINTR(connect( - socket->fd(), reinterpret_cast(&addr), sizeof(addr))); - if (ret != 0) - return false; - // Check the cookie again. We only link in /tmp, which is sticky, so, if the - // directory is still correct, it must have been correct in-between when we - // connected. POSIX, sadly, lacks a connectat(). - if (!CheckCookie(remote_cookie, cookie)) { - socket->Reset(); - return false; - } - // Success! - return true; - } else if (errno == EINVAL) { - // It exists, but is not a symlink (or some other error we detect - // later). Just connect to it directly; this is an older version of Chrome. - sockaddr_un addr; - SetupSockAddr(socket_path.value(), &addr); - int ret = HANDLE_EINTR(connect( - socket->fd(), reinterpret_cast(&addr), sizeof(addr))); - return (ret == 0); - } else { - // File is missing, or other error. - if (errno != ENOENT) - PLOG(ERROR) << "readlink failed"; - return false; - } -} - -#if defined(OS_MAC) -bool ReplaceOldSingletonLock(const base::FilePath& symlink_content, - const base::FilePath& lock_path) { - // Try taking an flock(2) on the file. Failure means the lock is taken so we - // should quit. - base::ScopedFD lock_fd(HANDLE_EINTR( - open(lock_path.value().c_str(), O_RDWR | O_CREAT | O_SYMLINK, 0644))); - if (!lock_fd.is_valid()) { - PLOG(ERROR) << "Could not open singleton lock"; - return false; - } - - int rc = HANDLE_EINTR(flock(lock_fd.get(), LOCK_EX | LOCK_NB)); - if (rc == -1) { - if (errno == EWOULDBLOCK) { - LOG(ERROR) << "Singleton lock held by old process."; - } else { - PLOG(ERROR) << "Error locking singleton lock"; - } - return false; - } - - // Successfully taking the lock means we can replace it with the a new symlink - // lock. We never flock() the lock file from now on. I.e. we assume that an - // old version of Chrome will not run with the same user data dir after this - // version has run. - if (!base::DeleteFile(lock_path)) { - PLOG(ERROR) << "Could not delete old singleton lock."; - return false; - } - - return SymlinkPath(symlink_content, lock_path); -} -#endif // defined(OS_MAC) - -} // namespace - -/////////////////////////////////////////////////////////////////////////////// -// ProcessSingleton::LinuxWatcher -// A helper class for a Linux specific implementation of the process singleton. -// This class sets up a listener on the singleton socket and handles parsing -// messages that come in on the singleton socket. -class ProcessSingleton::LinuxWatcher - : public base::RefCountedThreadSafe { - public: - // A helper class to read message from an established socket. - class SocketReader { - public: - SocketReader(ProcessSingleton::LinuxWatcher* parent, - scoped_refptr ui_task_runner, - int fd) - : parent_(parent), - ui_task_runner_(ui_task_runner), - fd_(fd), - bytes_read_(0) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - // Wait for reads. - fd_watch_controller_ = base::FileDescriptorWatcher::WatchReadable( - fd, base::BindRepeating(&SocketReader::OnSocketCanReadWithoutBlocking, - base::Unretained(this))); - // If we haven't completed in a reasonable amount of time, give up. - timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(kTimeoutInSeconds), - this, &SocketReader::CleanupAndDeleteSelf); - } - - ~SocketReader() { CloseSocket(fd_); } - - // Finish handling the incoming message by optionally sending back an ACK - // message and removing this SocketReader. - void FinishWithACK(const char* message, size_t length); - - private: - void OnSocketCanReadWithoutBlocking(); - - void CleanupAndDeleteSelf() { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - - parent_->RemoveSocketReader(this); - // We're deleted beyond this point. - } - - // Controls watching |fd_|. - std::unique_ptr - fd_watch_controller_; - - // The ProcessSingleton::LinuxWatcher that owns us. - ProcessSingleton::LinuxWatcher* const parent_; - - // A reference to the UI task runner. - scoped_refptr ui_task_runner_; - - // The file descriptor we're reading. - const int fd_; - - // Store the message in this buffer. - char buf_[kMaxMessageLength]; - - // Tracks the number of bytes we've read in case we're getting partial - // reads. - size_t bytes_read_; - - base::OneShotTimer timer_; - - DISALLOW_COPY_AND_ASSIGN(SocketReader); - }; - - // We expect to only be constructed on the UI thread. - explicit LinuxWatcher(ProcessSingleton* parent) - : ui_task_runner_(base::ThreadTaskRunnerHandle::Get()), parent_(parent) {} - - // Start listening for connections on the socket. This method should be - // called from the IO thread. - void StartListening(int socket); - - // This method determines if we should use the same process and if we should, - // opens a new browser tab. This runs on the UI thread. - // |reader| is for sending back ACK message. - void HandleMessage(const std::string& current_dir, - const std::vector& argv, - SocketReader* reader); - - private: - friend struct BrowserThread::DeleteOnThread; - friend class base::DeleteHelper; - - ~LinuxWatcher() { DCHECK_CURRENTLY_ON(BrowserThread::IO); } - - void OnSocketCanReadWithoutBlocking(int socket); - - // Removes and deletes the SocketReader. - void RemoveSocketReader(SocketReader* reader); - - std::unique_ptr socket_watcher_; - - // A reference to the UI message loop (i.e., the message loop we were - // constructed on). - scoped_refptr ui_task_runner_; - - // The ProcessSingleton that owns us. - ProcessSingleton* const parent_; - - std::set> readers_; - - DISALLOW_COPY_AND_ASSIGN(LinuxWatcher); -}; - -void ProcessSingleton::LinuxWatcher::OnSocketCanReadWithoutBlocking( - int socket) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - // Accepting incoming client. - sockaddr_un from; - socklen_t from_len = sizeof(from); - int connection_socket = HANDLE_EINTR( - accept(socket, reinterpret_cast(&from), &from_len)); - if (-1 == connection_socket) { - PLOG(ERROR) << "accept() failed"; - return; - } - DCHECK(base::SetNonBlocking(connection_socket)) - << "Failed to make non-blocking socket."; - readers_.insert( - std::make_unique(this, ui_task_runner_, connection_socket)); -} - -void ProcessSingleton::LinuxWatcher::StartListening(int socket) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - // Watch for client connections on this socket. - socket_watcher_ = base::FileDescriptorWatcher::WatchReadable( - socket, base::BindRepeating(&LinuxWatcher::OnSocketCanReadWithoutBlocking, - base::Unretained(this), socket)); -} - -void ProcessSingleton::LinuxWatcher::HandleMessage( - const std::string& current_dir, - const std::vector& argv, - SocketReader* reader) { - DCHECK(ui_task_runner_->BelongsToCurrentThread()); - DCHECK(reader); - - if (parent_->notification_callback_.Run(argv, base::FilePath(current_dir))) { - // Send back "ACK" message to prevent the client process from starting up. - reader->FinishWithACK(kACKToken, base::size(kACKToken) - 1); - } else { - LOG(WARNING) << "Not handling interprocess notification as browser" - " is shutting down"; - // Send back "SHUTDOWN" message, so that the client process can start up - // without killing this process. - reader->FinishWithACK(kShutdownToken, base::size(kShutdownToken) - 1); - return; - } -} - -void ProcessSingleton::LinuxWatcher::RemoveSocketReader(SocketReader* reader) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - DCHECK(reader); - auto it = std::find_if(readers_.begin(), readers_.end(), - [reader](const std::unique_ptr& ptr) { - return ptr.get() == reader; - }); - readers_.erase(it); -} - -/////////////////////////////////////////////////////////////////////////////// -// ProcessSingleton::LinuxWatcher::SocketReader -// - -void ProcessSingleton::LinuxWatcher::SocketReader:: - OnSocketCanReadWithoutBlocking() { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - while (bytes_read_ < sizeof(buf_)) { - ssize_t rv = - HANDLE_EINTR(read(fd_, buf_ + bytes_read_, sizeof(buf_) - bytes_read_)); - if (rv < 0) { - if (errno != EAGAIN && errno != EWOULDBLOCK) { - PLOG(ERROR) << "read() failed"; - CloseSocket(fd_); - return; - } else { - // It would block, so we just return and continue to watch for the next - // opportunity to read. - return; - } - } else if (!rv) { - // No more data to read. It's time to process the message. - break; - } else { - bytes_read_ += rv; - } - } - - // Validate the message. The shortest message is kStartToken\0x\0x - const size_t kMinMessageLength = base::size(kStartToken) + 4; - if (bytes_read_ < kMinMessageLength) { - buf_[bytes_read_] = 0; - LOG(ERROR) << "Invalid socket message (wrong length):" << buf_; - CleanupAndDeleteSelf(); - return; - } - - std::string str(buf_, bytes_read_); - std::vector tokens = - base::SplitString(str, std::string(1, kTokenDelimiter), - base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); - - if (tokens.size() < 3 || tokens[0] != kStartToken) { - LOG(ERROR) << "Wrong message format: " << str; - CleanupAndDeleteSelf(); - return; - } - - // Stop the expiration timer to prevent this SocketReader object from being - // terminated unexpectly. - timer_.Stop(); - - std::string current_dir = tokens[1]; - // Remove the first two tokens. The remaining tokens should be the command - // line argv array. - tokens.erase(tokens.begin()); - tokens.erase(tokens.begin()); - - // Return to the UI thread to handle opening a new browser tab. - ui_task_runner_->PostTask( - FROM_HERE, base::BindOnce(&ProcessSingleton::LinuxWatcher::HandleMessage, - parent_, current_dir, tokens, this)); - fd_watch_controller_.reset(); - - // LinuxWatcher::HandleMessage() is in charge of destroying this SocketReader - // object by invoking SocketReader::FinishWithACK(). -} - -void ProcessSingleton::LinuxWatcher::SocketReader::FinishWithACK( - const char* message, - size_t length) { - if (message && length) { - // Not necessary to care about the return value. - WriteToSocket(fd_, message, length); - } - - if (shutdown(fd_, SHUT_WR) < 0) - PLOG(ERROR) << "shutdown() failed"; - - base::PostTask( - FROM_HERE, {BrowserThread::IO}, - base::BindOnce(&ProcessSingleton::LinuxWatcher::RemoveSocketReader, - parent_, this)); - // We will be deleted once the posted RemoveSocketReader task runs. -} - -/////////////////////////////////////////////////////////////////////////////// -// ProcessSingleton -// -ProcessSingleton::ProcessSingleton( - const base::FilePath& user_data_dir, - const NotificationCallback& notification_callback) - : notification_callback_(notification_callback), - current_pid_(base::GetCurrentProcId()) { - // The user_data_dir may have not been created yet. - base::ThreadRestrictions::ScopedAllowIO allow_io; - base::CreateDirectoryAndGetError(user_data_dir, nullptr); - - socket_path_ = user_data_dir.Append(kSingletonSocketFilename); - lock_path_ = user_data_dir.Append(kSingletonLockFilename); - cookie_path_ = user_data_dir.Append(kSingletonCookieFilename); - - kill_callback_ = base::BindRepeating(&ProcessSingleton::KillProcess, - base::Unretained(this)); -} - -ProcessSingleton::~ProcessSingleton() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - // Manually free resources with IO explicitly allowed. - base::ThreadRestrictions::ScopedAllowIO allow_io; - watcher_ = nullptr; - ignore_result(socket_dir_.Delete()); -} - -ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() { - return NotifyOtherProcessWithTimeout( - *base::CommandLine::ForCurrentProcess(), kRetryAttempts, - base::TimeDelta::FromSeconds(kTimeoutInSeconds), true); -} - -ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout( - const base::CommandLine& cmd_line, - int retry_attempts, - const base::TimeDelta& timeout, - bool kill_unresponsive) { - DCHECK_GE(retry_attempts, 0); - DCHECK_GE(timeout.InMicroseconds(), 0); - - base::TimeDelta sleep_interval = timeout / retry_attempts; - - ScopedSocket socket; - for (int retries = 0; retries <= retry_attempts; ++retries) { - // Try to connect to the socket. - if (ConnectSocket(&socket, socket_path_, cookie_path_)) - break; - - // If we're in a race with another process, they may be in Create() and have - // created the lock but not attached to the socket. So we check if the - // process with the pid from the lockfile is currently running and is a - // chrome browser. If so, we loop and try again for |timeout|. - - std::string hostname; - int pid; - if (!ParseLockPath(lock_path_, &hostname, &pid)) { - // No lockfile exists. - return PROCESS_NONE; - } - - if (hostname.empty()) { - // Invalid lockfile. - UnlinkPath(lock_path_); - return PROCESS_NONE; - } - - if (hostname != net::GetHostName() && !IsChromeProcess(pid)) { - // Locked by process on another host. If the user selected to unlock - // the profile, try to continue; otherwise quit. - if (DisplayProfileInUseError(lock_path_, hostname, pid)) { - UnlinkPath(lock_path_); - return PROCESS_NONE; - } - return PROFILE_IN_USE; - } - - if (!IsChromeProcess(pid)) { - // Orphaned lockfile (no process with pid, or non-chrome process.) - UnlinkPath(lock_path_); - return PROCESS_NONE; - } - - if (IsSameChromeInstance(pid)) { - // Orphaned lockfile (pid is part of same chrome instance we are, even - // though we haven't tried to create a lockfile yet). - UnlinkPath(lock_path_); - return PROCESS_NONE; - } - - if (retries == retry_attempts) { - // Retries failed. Kill the unresponsive chrome process and continue. - if (!kill_unresponsive || !KillProcessByLockPath()) - return PROFILE_IN_USE; - return PROCESS_NONE; - } - - base::PlatformThread::Sleep(sleep_interval); - } - - timeval socket_timeout = TimeDeltaToTimeVal(timeout); - setsockopt(socket.fd(), SOL_SOCKET, SO_SNDTIMEO, &socket_timeout, - sizeof(socket_timeout)); - - // Found another process, prepare our command line - // format is "START\0\0\0...\0". - std::string to_send(kStartToken); - to_send.push_back(kTokenDelimiter); - - base::FilePath current_dir; - if (!base::PathService::Get(base::DIR_CURRENT, ¤t_dir)) - return PROCESS_NONE; - to_send.append(current_dir.value()); - - const std::vector& argv = electron::ElectronCommandLine::argv(); - for (const auto& arg : argv) { - to_send.push_back(kTokenDelimiter); - to_send.append(arg); - } - - // Send the message - if (!WriteToSocket(socket.fd(), to_send.data(), to_send.length())) { - // Try to kill the other process, because it might have been dead. - if (!kill_unresponsive || !KillProcessByLockPath()) - return PROFILE_IN_USE; - return PROCESS_NONE; - } - - if (shutdown(socket.fd(), SHUT_WR) < 0) - PLOG(ERROR) << "shutdown() failed"; - - // Read ACK message from the other process. It might be blocked for a certain - // timeout, to make sure the other process has enough time to return ACK. - char buf[kMaxACKMessageLength + 1]; - ssize_t len = ReadFromSocket(socket.fd(), buf, kMaxACKMessageLength, timeout); - - // Failed to read ACK, the other process might have been frozen. - if (len <= 0) { - if (!kill_unresponsive || !KillProcessByLockPath()) - return PROFILE_IN_USE; - return PROCESS_NONE; - } - - buf[len] = '\0'; - if (strncmp(buf, kShutdownToken, base::size(kShutdownToken) - 1) == 0) { - // The other process is shutting down, it's safe to start a new process. - return PROCESS_NONE; - } else if (strncmp(buf, kACKToken, base::size(kACKToken) - 1) == 0) { -#if defined(TOOLKIT_VIEWS) && defined(OS_LINUX) && !defined(OS_CHROMEOS) - // Likely NULL in unit tests. - views::LinuxUI* linux_ui = views::LinuxUI::instance(); - if (linux_ui) - linux_ui->NotifyWindowManagerStartupComplete(); -#endif - - // Assume the other process is handling the request. - return PROCESS_NOTIFIED; - } - - NOTREACHED() << "The other process returned unknown message: " << buf; - return PROCESS_NOTIFIED; -} - -ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessOrCreate() { - return NotifyOtherProcessWithTimeoutOrCreate( - *base::CommandLine::ForCurrentProcess(), kRetryAttempts, - base::TimeDelta::FromSeconds(kTimeoutInSeconds)); -} - -void ProcessSingleton::StartListeningOnSocket() { - watcher_ = new LinuxWatcher(this); - base::PostTask(FROM_HERE, {BrowserThread::IO}, - base::BindOnce(&ProcessSingleton::LinuxWatcher::StartListening, - watcher_, sock_)); -} - -void ProcessSingleton::OnBrowserReady() { - if (listen_on_ready_) { - StartListeningOnSocket(); - listen_on_ready_ = false; - } -} - -ProcessSingleton::NotifyResult -ProcessSingleton::NotifyOtherProcessWithTimeoutOrCreate( - const base::CommandLine& command_line, - int retry_attempts, - const base::TimeDelta& timeout) { - const base::TimeTicks begin_ticks = base::TimeTicks::Now(); - NotifyResult result = NotifyOtherProcessWithTimeout( - command_line, retry_attempts, timeout, true); - if (result != PROCESS_NONE) { - if (result == PROCESS_NOTIFIED) { - UMA_HISTOGRAM_MEDIUM_TIMES("Chrome.ProcessSingleton.TimeToNotify", - base::TimeTicks::Now() - begin_ticks); - } else { - UMA_HISTOGRAM_MEDIUM_TIMES("Chrome.ProcessSingleton.TimeToFailure", - base::TimeTicks::Now() - begin_ticks); - } - return result; - } - - if (Create()) { - UMA_HISTOGRAM_MEDIUM_TIMES("Chrome.ProcessSingleton.TimeToCreate", - base::TimeTicks::Now() - begin_ticks); - return PROCESS_NONE; - } - - // If the Create() failed, try again to notify. (It could be that another - // instance was starting at the same time and managed to grab the lock before - // we did.) - // This time, we don't want to kill anything if we aren't successful, since we - // aren't going to try to take over the lock ourselves. - result = NotifyOtherProcessWithTimeout(command_line, retry_attempts, timeout, - false); - - if (result == PROCESS_NOTIFIED) { - UMA_HISTOGRAM_MEDIUM_TIMES("Chrome.ProcessSingleton.TimeToNotify", - base::TimeTicks::Now() - begin_ticks); - } else { - UMA_HISTOGRAM_MEDIUM_TIMES("Chrome.ProcessSingleton.TimeToFailure", - base::TimeTicks::Now() - begin_ticks); - } - - if (result != PROCESS_NONE) - return result; - - return LOCK_ERROR; -} - -void ProcessSingleton::OverrideCurrentPidForTesting(base::ProcessId pid) { - current_pid_ = pid; -} - -void ProcessSingleton::OverrideKillCallbackForTesting( - const base::RepeatingCallback& callback) { - kill_callback_ = callback; -} - -void ProcessSingleton::DisablePromptForTesting() { - g_disable_prompt = true; -} - -bool ProcessSingleton::Create() { - base::ThreadRestrictions::ScopedAllowIO allow_io; - int sock; - sockaddr_un addr; - - // The symlink lock is pointed to the hostname and process id, so other - // processes can find it out. - base::FilePath symlink_content(base::StringPrintf( - "%s%c%u", net::GetHostName().c_str(), kLockDelimiter, current_pid_)); - - // Create symbol link before binding the socket, to ensure only one instance - // can have the socket open. - if (!SymlinkPath(symlink_content, lock_path_)) { - // TODO(jackhou): Remove this case once this code is stable on Mac. - // http://crbug.com/367612 -#if defined(OS_MAC) - // On Mac, an existing non-symlink lock file means the lock could be held by - // the old process singleton code. If we can successfully replace the lock, - // continue as normal. - if (base::IsLink(lock_path_) || - !ReplaceOldSingletonLock(symlink_content, lock_path_)) { - return false; - } -#else - // If we failed to create the lock, most likely another instance won the - // startup race. - return false; -#endif - } - - if (IsAppSandboxed()) { - // For sandboxed applications, the tmp dir could be too long to fit - // addr->sun_path, so we need to make it as short as possible. - base::FilePath tmp_dir; - if (!base::GetTempDir(&tmp_dir)) { - LOG(ERROR) << "Failed to get temporary directory."; - return false; - } - if (!socket_dir_.Set(tmp_dir.Append("S"))) { - LOG(ERROR) << "Failed to set socket directory."; - return false; - } - } else { - // Create the socket file somewhere in /tmp which is usually mounted as a - // normal filesystem. Some network filesystems (notably AFS) are screwy and - // do not support Unix domain sockets. - if (!socket_dir_.CreateUniqueTempDir()) { - LOG(ERROR) << "Failed to create socket directory."; - return false; - } - } - - // Check that the directory was created with the correct permissions. - int dir_mode = 0; - CHECK(base::GetPosixFilePermissions(socket_dir_.GetPath(), &dir_mode) && - dir_mode == base::FILE_PERMISSION_USER_MASK) - << "Temp directory mode is not 700: " << std::oct << dir_mode; - - // Setup the socket symlink and the two cookies. - base::FilePath socket_target_path = - socket_dir_.GetPath().Append(kSingletonSocketFilename); - base::FilePath cookie(GenerateCookie()); - base::FilePath remote_cookie_path = - socket_dir_.GetPath().Append(kSingletonCookieFilename); - UnlinkPath(socket_path_); - UnlinkPath(cookie_path_); - if (!SymlinkPath(socket_target_path, socket_path_) || - !SymlinkPath(cookie, cookie_path_) || - !SymlinkPath(cookie, remote_cookie_path)) { - // We've already locked things, so we can't have lost the startup race, - // but something doesn't like us. - LOG(ERROR) << "Failed to create symlinks."; - if (!socket_dir_.Delete()) - LOG(ERROR) << "Encountered a problem when deleting socket directory."; - return false; - } - - SetupSocket(socket_target_path.value(), &sock, &addr); - - if (bind(sock, reinterpret_cast(&addr), sizeof(addr)) < 0) { - PLOG(ERROR) << "Failed to bind() " << socket_target_path.value(); - CloseSocket(sock); - return false; - } - - if (listen(sock, 5) < 0) - NOTREACHED() << "listen failed: " << base::safe_strerror(errno); - - sock_ = sock; - - if (BrowserThread::IsThreadInitialized(BrowserThread::IO)) { - StartListeningOnSocket(); - } else { - listen_on_ready_ = true; - } - - return true; -} - -void ProcessSingleton::Cleanup() { - UnlinkPath(socket_path_); - UnlinkPath(cookie_path_); - UnlinkPath(lock_path_); -} - -bool ProcessSingleton::IsSameChromeInstance(pid_t pid) { - pid_t cur_pid = current_pid_; - while (pid != cur_pid) { - pid = base::GetParentProcessId(pid); - if (pid < 0) - return false; - if (!IsChromeProcess(pid)) - return false; - } - return true; -} - -bool ProcessSingleton::KillProcessByLockPath() { - std::string hostname; - int pid; - ParseLockPath(lock_path_, &hostname, &pid); - - if (!hostname.empty() && hostname != net::GetHostName()) { - return DisplayProfileInUseError(lock_path_, hostname, pid); - } - UnlinkPath(lock_path_); - - if (IsSameChromeInstance(pid)) - return true; - - if (pid > 0) { - kill_callback_.Run(pid); - return true; - } - - LOG(ERROR) << "Failed to extract pid from path: " << lock_path_.value(); - return true; -} - -void ProcessSingleton::KillProcess(int pid) { - // TODO(james.su@gmail.com): Is SIGKILL ok? - int rv = kill(static_cast(pid), SIGKILL); - // ESRCH = No Such Process (can happen if the other process is already in - // progress of shutting down and finishes before we try to kill it). - DCHECK(rv == 0 || errno == ESRCH) - << "Error killing process: " << base::safe_strerror(errno); -} diff --git a/chromium_src/chrome/browser/process_singleton_win.cc b/chromium_src/chrome/browser/process_singleton_win.cc deleted file mode 100644 index 62bc6136665eb..0000000000000 --- a/chromium_src/chrome/browser/process_singleton_win.cc +++ /dev/null @@ -1,316 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/process_singleton.h" - -#include - -#include "base/base_paths.h" -#include "base/bind.h" -#include "base/command_line.h" -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/process/process.h" -#include "base/process/process_info.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" -#include "base/time/time.h" -#include "base/win/registry.h" -#include "base/win/scoped_handle.h" -#include "base/win/windows_version.h" -#include "chrome/browser/win/chrome_process_finder.h" -#include "content/public/common/result_codes.h" -#include "net/base/escape.h" -#include "ui/gfx/win/hwnd_util.h" - -namespace { - -const char kLockfile[] = "lockfile"; - -// A helper class that acquires the given |mutex| while the AutoLockMutex is in -// scope. -class AutoLockMutex { - public: - explicit AutoLockMutex(HANDLE mutex) : mutex_(mutex) { - DWORD result = ::WaitForSingleObject(mutex_, INFINITE); - DPCHECK(result == WAIT_OBJECT_0) << "Result = " << result; - } - - ~AutoLockMutex() { - BOOL released = ::ReleaseMutex(mutex_); - DPCHECK(released); - } - - private: - HANDLE mutex_; - DISALLOW_COPY_AND_ASSIGN(AutoLockMutex); -}; - -// A helper class that releases the given |mutex| while the AutoUnlockMutex is -// in scope and immediately re-acquires it when going out of scope. -class AutoUnlockMutex { - public: - explicit AutoUnlockMutex(HANDLE mutex) : mutex_(mutex) { - BOOL released = ::ReleaseMutex(mutex_); - DPCHECK(released); - } - - ~AutoUnlockMutex() { - DWORD result = ::WaitForSingleObject(mutex_, INFINITE); - DPCHECK(result == WAIT_OBJECT_0) << "Result = " << result; - } - - private: - HANDLE mutex_; - DISALLOW_COPY_AND_ASSIGN(AutoUnlockMutex); -}; - -// Checks the visibility of the enumerated window and signals once a visible -// window has been found. -BOOL CALLBACK BrowserWindowEnumeration(HWND window, LPARAM param) { - bool* result = reinterpret_cast(param); - *result = ::IsWindowVisible(window) != 0; - // Stops enumeration if a visible window has been found. - return !*result; -} - -bool ParseCommandLine(const COPYDATASTRUCT* cds, - base::CommandLine::StringVector* parsed_command_line, - base::FilePath* current_directory) { - // We should have enough room for the shortest command (min_message_size) - // and also be a multiple of wchar_t bytes. The shortest command - // possible is L"START\0\0" (empty current directory and command line). - static const int min_message_size = 7; - if (cds->cbData < min_message_size * sizeof(wchar_t) || - cds->cbData % sizeof(wchar_t) != 0) { - LOG(WARNING) << "Invalid WM_COPYDATA, length = " << cds->cbData; - return false; - } - - // We split the string into 4 parts on NULLs. - DCHECK(cds->lpData); - const std::wstring msg(static_cast(cds->lpData), - cds->cbData / sizeof(wchar_t)); - const std::wstring::size_type first_null = msg.find_first_of(L'\0'); - if (first_null == 0 || first_null == std::wstring::npos) { - // no NULL byte, don't know what to do - LOG(WARNING) << "Invalid WM_COPYDATA, length = " << msg.length() - << ", first null = " << first_null; - return false; - } - - // Decode the command, which is everything until the first NULL. - if (msg.substr(0, first_null) == L"START") { - // Another instance is starting parse the command line & do what it would - // have done. - VLOG(1) << "Handling STARTUP request from another process"; - const std::wstring::size_type second_null = - msg.find_first_of(L'\0', first_null + 1); - if (second_null == std::wstring::npos || first_null == msg.length() - 1 || - second_null == msg.length()) { - LOG(WARNING) << "Invalid format for start command, we need a string in 4 " - "parts separated by NULLs"; - return false; - } - - // Get current directory. - *current_directory = - base::FilePath(msg.substr(first_null + 1, second_null - first_null)); - - const std::wstring::size_type third_null = - msg.find_first_of(L'\0', second_null + 1); - if (third_null == std::wstring::npos || third_null == msg.length()) { - LOG(WARNING) << "Invalid format for start command, we need a string in 4 " - "parts separated by NULLs"; - } - - // Get command line. - const std::wstring cmd_line = - msg.substr(second_null + 1, third_null - second_null); - *parsed_command_line = base::CommandLine::FromString(cmd_line).argv(); - return true; - } - return false; -} - -bool ProcessLaunchNotification( - const ProcessSingleton::NotificationCallback& notification_callback, - UINT message, - WPARAM wparam, - LPARAM lparam, - LRESULT* result) { - if (message != WM_COPYDATA) - return false; - - // Handle the WM_COPYDATA message from another process. - const COPYDATASTRUCT* cds = reinterpret_cast(lparam); - - base::CommandLine::StringVector parsed_command_line; - base::FilePath current_directory; - if (!ParseCommandLine(cds, &parsed_command_line, ¤t_directory)) { - *result = TRUE; - return true; - } - - *result = notification_callback.Run(parsed_command_line, current_directory) - ? TRUE - : FALSE; - return true; -} - -bool TerminateAppWithError() { - // TODO: This is called when the secondary process can't ping the primary - // process. Need to find out what to do here. - return false; -} - -} // namespace - -ProcessSingleton::ProcessSingleton( - const base::FilePath& user_data_dir, - const NotificationCallback& notification_callback) - : notification_callback_(notification_callback), - is_virtualized_(false), - lock_file_(INVALID_HANDLE_VALUE), - user_data_dir_(user_data_dir), - should_kill_remote_process_callback_( - base::BindRepeating(&TerminateAppWithError)) { - // The user_data_dir may have not been created yet. - base::CreateDirectoryAndGetError(user_data_dir, nullptr); -} - -ProcessSingleton::~ProcessSingleton() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (lock_file_ != INVALID_HANDLE_VALUE) - ::CloseHandle(lock_file_); -} - -// Code roughly based on Mozilla. -ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() { - if (is_virtualized_) - return PROCESS_NOTIFIED; // We already spawned the process in this case. - if (lock_file_ == INVALID_HANDLE_VALUE && !remote_window_) { - return LOCK_ERROR; - } else if (!remote_window_) { - return PROCESS_NONE; - } - - switch (chrome::AttemptToNotifyRunningChrome(remote_window_)) { - case chrome::NOTIFY_SUCCESS: - return PROCESS_NOTIFIED; - case chrome::NOTIFY_FAILED: - remote_window_ = NULL; - return PROCESS_NONE; - case chrome::NOTIFY_WINDOW_HUNG: - // Fall through and potentially terminate the hung browser. - break; - } - - DWORD process_id = 0; - DWORD thread_id = ::GetWindowThreadProcessId(remote_window_, &process_id); - if (!thread_id || !process_id) { - remote_window_ = NULL; - return PROCESS_NONE; - } - base::Process process = base::Process::Open(process_id); - - // The window is hung. Scan for every window to find a visible one. - bool visible_window = false; - ::EnumThreadWindows(thread_id, &BrowserWindowEnumeration, - reinterpret_cast(&visible_window)); - - // If there is a visible browser window, ask the user before killing it. - if (visible_window && !should_kill_remote_process_callback_.Run()) { - // The user denied. Quit silently. - return PROCESS_NOTIFIED; - } - - // Time to take action. Kill the browser process. - process.Terminate(content::RESULT_CODE_HUNG, true); - remote_window_ = NULL; - return PROCESS_NONE; -} - -ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessOrCreate() { - ProcessSingleton::NotifyResult result = PROCESS_NONE; - if (!Create()) { - result = NotifyOtherProcess(); - if (result == PROCESS_NONE) - result = PROFILE_IN_USE; - } - return result; -} - -void ProcessSingleton::StartListeningOnSocket() {} -void ProcessSingleton::OnBrowserReady() {} - -// Look for a Chrome instance that uses the same profile directory. If there -// isn't one, create a message window with its title set to the profile -// directory path. -bool ProcessSingleton::Create() { - static const wchar_t kMutexName[] = L"Local\\AtomProcessSingletonStartup!"; - - remote_window_ = chrome::FindRunningChromeWindow(user_data_dir_); - if (!remote_window_) { - // Make sure we will be the one and only process creating the window. - // We use a named Mutex since we are protecting against multi-process - // access. As documented, it's clearer to NOT request ownership on creation - // since it isn't guaranteed we will get it. It is better to create it - // without ownership and explicitly get the ownership afterward. - base::win::ScopedHandle only_me(::CreateMutex(NULL, FALSE, kMutexName)); - if (!only_me.IsValid()) { - DPLOG(FATAL) << "CreateMutex failed"; - return false; - } - - AutoLockMutex auto_lock_only_me(only_me.Get()); - - // We now own the mutex so we are the only process that can create the - // window at this time, but we must still check if someone created it - // between the time where we looked for it above and the time the mutex - // was given to us. - remote_window_ = chrome::FindRunningChromeWindow(user_data_dir_); - if (!remote_window_) { - // We have to make sure there is no Chrome instance running on another - // machine that uses the same profile. - base::FilePath lock_file_path = user_data_dir_.AppendASCII(kLockfile); - lock_file_ = - ::CreateFile(lock_file_path.value().c_str(), GENERIC_WRITE, - FILE_SHARE_READ, NULL, CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL); - DWORD error = ::GetLastError(); - LOG_IF(WARNING, lock_file_ != INVALID_HANDLE_VALUE && - error == ERROR_ALREADY_EXISTS) - << "Lock file exists but is writable."; - LOG_IF(ERROR, lock_file_ == INVALID_HANDLE_VALUE) - << "Lock file can not be created! Error code: " << error; - - if (lock_file_ != INVALID_HANDLE_VALUE) { - // Set the window's title to the path of our user data directory so - // other Chrome instances can decide if they should forward to us. - bool result = - window_.CreateNamed(base::BindRepeating(&ProcessLaunchNotification, - notification_callback_), - user_data_dir_.value()); - - // NB: Ensure that if the primary app gets started as elevated - // admin inadvertently, secondary windows running not as elevated - // will still be able to send messages - ::ChangeWindowMessageFilterEx(window_.hwnd(), WM_COPYDATA, MSGFLT_ALLOW, - NULL); - CHECK(result && window_.hwnd()); - } - } - } - - return window_.hwnd() != NULL; -} - -void ProcessSingleton::Cleanup() {} - -void ProcessSingleton::OverrideShouldKillRemoteProcessCallbackForTesting( - const ShouldKillRemoteProcessCallback& display_dialog_callback) { - should_kill_remote_process_callback_ = display_dialog_callback; -} diff --git a/chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h b/chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h deleted file mode 100644 index e04bf0bb2b9c8..0000000000000 --- a/chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_VIEWS_FRAME_GLOBAL_MENU_BAR_REGISTRAR_X11_H_ -#define CHROME_BROWSER_UI_VIEWS_FRAME_GLOBAL_MENU_BAR_REGISTRAR_X11_H_ - -#include - -#include - -#include "base/memory/ref_counted.h" -#include "base/memory/singleton.h" -#include "ui/base/glib/glib_signal.h" -#include "ui/gfx/x/xproto.h" - -// Advertises our menu bars to Unity. -// -// GlobalMenuBarX11 is responsible for managing the DbusmenuServer for each -// x11::Window. We need a separate object to own the dbus channel to -// com.canonical.AppMenu.Registrar and to register/unregister the mapping -// between a x11::Window and the DbusmenuServer instance we are offering. -class GlobalMenuBarRegistrarX11 { - public: - static GlobalMenuBarRegistrarX11* GetInstance(); - - void OnWindowMapped(x11::Window window); - void OnWindowUnmapped(x11::Window window); - - private: - friend struct base::DefaultSingletonTraits; - - GlobalMenuBarRegistrarX11(); - ~GlobalMenuBarRegistrarX11(); - - // Sends the actual message. - void RegisterXWindow(x11::Window window); - void UnregisterXWindow(x11::Window window); - - CHROMEG_CALLBACK_1(GlobalMenuBarRegistrarX11, - void, - OnProxyCreated, - GObject*, - GAsyncResult*); - CHROMEG_CALLBACK_1(GlobalMenuBarRegistrarX11, - void, - OnNameOwnerChanged, - GObject*, - GParamSpec*); - - GDBusProxy* registrar_proxy_; - - // x11::Window which want to be registered, but haven't yet been because - // we're waiting for the proxy to become available. - std::set live_windows_; - - DISALLOW_COPY_AND_ASSIGN(GlobalMenuBarRegistrarX11); -}; - -#endif // CHROME_BROWSER_UI_VIEWS_FRAME_GLOBAL_MENU_BAR_REGISTRAR_X11_H_ diff --git a/default_app/default_app.ts b/default_app/default_app.ts index 7c2d8a3b9eecb..3f4b60b06c242 100644 --- a/default_app/default_app.ts +++ b/default_app/default_app.ts @@ -1,6 +1,8 @@ -import { app, dialog, BrowserWindow, shell, ipcMain } from 'electron'; -import * as path from 'path'; -import * as url from 'url'; +import { shell } from 'electron/common'; +import { app, dialog, BrowserWindow, ipcMain, Menu } from 'electron/main'; + +import * as path from 'node:path'; +import * as url from 'node:url'; let mainWindow: BrowserWindow | null = null; @@ -9,23 +11,62 @@ app.on('window-all-closed', () => { app.quit(); }); -function decorateURL (url: string) { - // safely add `?utm_source=default_app - const parsedUrl = new URL(url); - parsedUrl.searchParams.append('utm_source', 'default_app'); - return parsedUrl.toString(); -} +const isMac = process.platform === 'darwin'; + +app.whenReady().then(() => { + const helpMenu: Electron.MenuItemConstructorOptions = { + role: 'help', + submenu: [ + { + label: 'Learn More', + click: async () => { + await shell.openExternal('https://electronjs.org'); + } + }, + { + label: 'Documentation', + click: async () => { + const version = process.versions.electron; + await shell.openExternal(`https://github.com/electron/electron/tree/v${version}/docs#readme`); + } + }, + { + label: 'Community Discussions', + click: async () => { + await shell.openExternal('https://discord.gg/electronjs'); + } + }, + { + label: 'Search Issues', + click: async () => { + await shell.openExternal('https://github.com/electron/electron/issues'); + } + } + ] + }; + + const macAppMenu: Electron.MenuItemConstructorOptions = { role: 'appMenu' }; + const template: Electron.MenuItemConstructorOptions[] = [ + ...(isMac ? [macAppMenu] : []), + { role: 'fileMenu' }, + { role: 'editMenu' }, + { role: 'viewMenu' }, + { role: 'windowMenu' }, + helpMenu + ]; + + Menu.setApplicationMenu(Menu.buildFromTemplate(template)); +}); // Find the shortest path to the electron binary const absoluteElectronPath = process.execPath; const relativeElectronPath = path.relative(process.cwd(), absoluteElectronPath); -const electronPath = absoluteElectronPath.length < relativeElectronPath.length - ? absoluteElectronPath - : relativeElectronPath; +const electronPath = + absoluteElectronPath.length < relativeElectronPath.length ? absoluteElectronPath : relativeElectronPath; const indexPath = path.resolve(app.getAppPath(), 'index.html'); -function isTrustedSender (webContents: Electron.WebContents) { +function isTrustedSender(webContents: Electron.WebContents) { if (webContents !== (mainWindow && mainWindow.webContents)) { return false; } @@ -41,34 +82,34 @@ ipcMain.handle('bootstrap', (event) => { return isTrustedSender(event.sender) ? electronPath : null; }); -async function createWindow () { +async function createWindow(backgroundColor?: string) { await app.whenReady(); const options: Electron.BrowserWindowConstructorOptions = { width: 960, height: 620, autoHideMenuBar: true, - backgroundColor: '#2f3241', + backgroundColor, webPreferences: { - preload: path.resolve(__dirname, 'preload.js'), + preload: url.fileURLToPath(new URL('preload.js', import.meta.url)), contextIsolation: true, sandbox: true, - enableRemoteModule: false + nodeIntegration: false }, useContentSize: true, show: false }; if (process.platform === 'linux') { - options.icon = path.join(__dirname, 'icon.png'); + options.icon = url.fileURLToPath(new URL('icon.png', import.meta.url)); } mainWindow = new BrowserWindow(options); mainWindow.on('ready-to-show', () => mainWindow!.show()); - mainWindow.webContents.on('new-window', (event, url) => { - event.preventDefault(); - shell.openExternal(decorateURL(url)); + mainWindow.webContents.setWindowOpenHandler((details) => { + shell.openExternal(details.url); + return { action: 'deny' }; }); mainWindow.webContents.session.setPermissionRequestHandler((webContents, permission, done) => { @@ -96,7 +137,7 @@ export const loadURL = async (appUrl: string) => { }; export const loadFile = async (appPath: string) => { - mainWindow = await createWindow(); + mainWindow = await createWindow(appPath === 'index.html' ? '#2f3241' : undefined); mainWindow.loadFile(appPath); mainWindow.focus(); }; diff --git a/default_app/index.html b/default_app/index.html index a4edefea906f5..5ac92e4fb8f17 100644 --- a/default_app/index.html +++ b/default_app/index.html @@ -2,6 +2,7 @@ Electron + diff --git a/default_app/main.ts b/default_app/main.ts index 1f2611d06002d..bf88442de65d4 100644 --- a/default_app/main.ts +++ b/default_app/main.ts @@ -1,8 +1,10 @@ -import * as electron from 'electron'; +import * as electron from 'electron/main'; + +import * as fs from 'node:fs'; +import { Module } from 'node:module'; +import * as path from 'node:path'; +import * as url from 'node:url'; -import * as fs from 'fs'; -import * as path from 'path'; -import * as url from 'url'; const { app, dialog } = electron; type DefaultAppOptions = { @@ -13,9 +15,7 @@ type DefaultAppOptions = { interactive: boolean; abi: boolean; modules: string[]; -} - -const Module = require('module'); +}; // Parse command line options. const argv = process.argv.slice(1); @@ -71,10 +71,10 @@ if (nextArgIsRequire) { // Set up preload modules if (option.modules.length > 0) { - Module._preloadModules(option.modules); + (Module as any)._preloadModules(option.modules); } -function loadApplicationPackage (packagePath: string) { +async function loadApplicationPackage(packagePath: string) { // Add a flag indicating app is started from default app. Object.defineProperty(process, 'defaultApp', { configurable: false, @@ -83,17 +83,25 @@ function loadApplicationPackage (packagePath: string) { }); try { - // Override app name and version. + // Override app's package.json data. packagePath = path.resolve(packagePath); const packageJsonPath = path.join(packagePath, 'package.json'); let appPath; if (fs.existsSync(packageJsonPath)) { let packageJson; + const emitWarning = process.emitWarning; try { - packageJson = require(packageJsonPath); + process.emitWarning = () => {}; + packageJson = ( + await import(url.pathToFileURL(packageJsonPath).toString(), { + with: { type: 'json' } + }) + ).default; } catch (e) { - showErrorMessage(`Unable to parse ${packageJsonPath}\n\n${e.message}`); + showErrorMessage(`Unable to parse ${packageJsonPath}\n\n${(e as Error).message}`); return; + } finally { + process.emitWarning = emitWarning; } if (packageJson.version) { @@ -104,43 +112,56 @@ function loadApplicationPackage (packagePath: string) { } else if (packageJson.name) { app.name = packageJson.name; } + + // Set application's desktop name (Linux). These usually match the executable name, + // so use it as the default to ensure the app gets the correct icon in the taskbar and application switcher. + const desktopName = packageJson.desktopName || `${path.basename(process.execPath)}.desktop`; + app.setDesktopName(desktopName); + + // Set v8 flags, deliberately lazy load so that apps that do not use this + // feature do not pay the price + if (packageJson.v8Flags) { + (await import('node:v8')).setFlagsFromString(packageJson.v8Flags); + } appPath = packagePath; } + let filePath: string; + try { - const filePath = Module._resolveFilename(packagePath, module, true); - app._setDefaultAppPaths(appPath || path.dirname(filePath)); + filePath = (Module as any)._resolveFilename(packagePath, null, true); + app.setAppPath(appPath || path.dirname(filePath)); } catch (e) { - showErrorMessage(`Unable to find Electron app at ${packagePath}\n\n${e.message}`); + showErrorMessage(`Unable to find Electron app at ${packagePath}\n\n${(e as Error).message}`); return; } // Run the app. - Module._load(packagePath, module, true); + await import(url.pathToFileURL(filePath).toString()); } catch (e) { console.error('App threw an error during load'); - console.error(e.stack || e); + console.error((e as Error).stack || e); throw e; } } -function showErrorMessage (message: string) { +function showErrorMessage(message: string) { app.focus(); dialog.showErrorBox('Error launching app', message); process.exit(1); } -async function loadApplicationByURL (appUrl: string) { - const { loadURL } = await import('./default_app'); +async function loadApplicationByURL(appUrl: string) { + const { loadURL } = await import('./default_app.js'); loadURL(appUrl); } -async function loadApplicationByFile (appPath: string) { - const { loadFile } = await import('./default_app'); +async function loadApplicationByFile(appPath: string) { + const { loadFile } = await import('./default_app.js'); loadFile(appPath); } -function startRepl () { +async function startRepl() { if (process.platform === 'win32') { console.error('Electron REPL not currently supported on Windows'); process.exit(1); @@ -161,14 +182,14 @@ function startRepl () { Using: Node.js ${nodeVersion} and Electron.js ${electronVersion} `); - const { REPLServer } = require('repl'); - const repl = new REPLServer({ + const { start } = await import('node:repl'); + const repl = start({ prompt: '> ' }).on('exit', () => { process.exit(0); }); - function defineBuiltin (context: any, name: string, getter: Function) { + function defineBuiltin(context: any, name: string, getter: Function) { const setReal = (val: any) => { // Deleting the property before re-assigning it disables the // getter/setter mechanism. @@ -206,17 +227,48 @@ function startRepl () { // we only trigger custom tab-completion when no common words are // potentially matches. const commonWords = [ - 'async', 'await', 'break', 'case', 'catch', 'const', 'continue', - 'debugger', 'default', 'delete', 'do', 'else', 'export', 'false', - 'finally', 'for', 'function', 'if', 'import', 'in', 'instanceof', 'let', - 'new', 'null', 'return', 'switch', 'this', 'throw', 'true', 'try', - 'typeof', 'var', 'void', 'while', 'with', 'yield' + 'async', + 'await', + 'break', + 'case', + 'catch', + 'const', + 'continue', + 'debugger', + 'default', + 'delete', + 'do', + 'else', + 'export', + 'false', + 'finally', + 'for', + 'function', + 'if', + 'import', + 'in', + 'instanceof', + 'let', + 'new', + 'null', + 'return', + 'switch', + 'this', + 'throw', + 'true', + 'try', + 'typeof', + 'var', + 'void', + 'while', + 'with', + 'yield' ]; const electronBuiltins = [...Object.keys(electron), 'original-fs', 'electron']; - const defaultComplete = repl.completer; - repl.completer = (line: string, callback: Function) => { + const defaultComplete: Function = repl.completer; + (repl as any).completer = (line: string, callback: Function) => { const lastSpace = line.lastIndexOf(' '); const currentSymbol = line.substring(lastSpace + 1, repl.cursor); @@ -236,14 +288,15 @@ function startRepl () { // start the default app. if (option.file && !option.webdriver) { const file = option.file; - const protocol = url.parse(file).protocol; + // eslint-disable-next-line n/no-deprecated-api + const protocol = URL.canParse(file) ? new URL(file).protocol : null; const extension = path.extname(file); if (protocol === 'http:' || protocol === 'https:' || protocol === 'file:' || protocol === 'chrome:') { - loadApplicationByURL(file); + await loadApplicationByURL(file); } else if (extension === '.html' || extension === '.htm') { - loadApplicationByFile(path.resolve(file)); + await loadApplicationByFile(path.resolve(file)); } else { - loadApplicationPackage(file); + await loadApplicationPackage(file); } } else if (option.version) { console.log('v' + process.versions.electron); @@ -252,7 +305,7 @@ if (option.file && !option.webdriver) { console.log(process.versions.modules); process.exit(0); } else if (option.interactive) { - startRepl(); + await startRepl(); } else { if (!option.noHelp) { const welcomeMessage = ` @@ -275,5 +328,5 @@ Options: console.log(welcomeMessage); } - loadApplicationByFile('index.html'); + await loadApplicationByFile('index.html'); } diff --git a/default_app/package.json b/default_app/package.json index d6c736cbc5253..65fee98c59eb3 100644 --- a/default_app/package.json +++ b/default_app/package.json @@ -1,5 +1,6 @@ { "name": "electron", "productName": "Electron", - "main": "main.js" + "main": "main.js", + "type": "module" } diff --git a/default_app/preload.ts b/default_app/preload.ts index b18130a1d0f73..ed5b0d009872b 100644 --- a/default_app/preload.ts +++ b/default_app/preload.ts @@ -1,17 +1,22 @@ -import { ipcRenderer, contextBridge } from 'electron'; +const { ipcRenderer, contextBridge } = require('electron/renderer'); -async function getOcticonSvg (name: string) { +const policy = window.trustedTypes.createPolicy('electron-default-app', { + // we trust the SVG contents + createHTML: (input) => input +}); + +async function getOcticonSvg(name: string) { try { const response = await fetch(`octicon/${name}.svg`); const div = document.createElement('div'); - div.innerHTML = await response.text(); + div.innerHTML = policy.createHTML(await response.text()); return div; } catch { return null; } } -async function loadSVG (element: HTMLSpanElement) { +async function loadSVG(element: HTMLSpanElement) { for (const cssClass of element.classList) { if (cssClass.startsWith('octicon-')) { const icon = await getOcticonSvg(cssClass.substr(8)); @@ -27,20 +32,31 @@ async function loadSVG (element: HTMLSpanElement) { } } -async function initialize () { +async function initialize() { const electronPath = await ipcRenderer.invoke('bootstrap'); - - function replaceText (selector: string, text: string) { + function replaceText(selector: string, text: string, link?: string) { const element = document.querySelector(selector); if (element) { - element.innerText = text; + if (link) { + const anchor = document.createElement('a'); + anchor.textContent = text; + anchor.href = link; + anchor.target = '_blank'; + element.appendChild(anchor); + } else { + element.innerText = text; + } } } - replaceText('.electron-version', `Electron v${process.versions.electron}`); - replaceText('.chrome-version', `Chromium v${process.versions.chrome}`); - replaceText('.node-version', `Node v${process.versions.node}`); - replaceText('.v8-version', `v8 v${process.versions.v8}`); + replaceText('.electron-version', `Electron v${process.versions.electron}`, 'https://electronjs.org/docs'); + replaceText('.chrome-version', `Chromium v${process.versions.chrome}`, 'https://developer.chrome.com/docs/chromium'); + replaceText( + '.node-version', + `Node v${process.versions.node}`, + `https://nodejs.org/docs/v${process.versions.node}/api` + ); + replaceText('.v8-version', `v8 v${process.versions.v8}`, 'https://v8.dev/docs'); replaceText('.command-example', `${electronPath} path-to-app`); for (const element of document.querySelectorAll('.octicon')) { diff --git a/default_app/styles.css b/default_app/styles.css index 4f37de3509b14..ffbf55a577cc2 100644 --- a/default_app/styles.css +++ b/default_app/styles.css @@ -41,7 +41,7 @@ h4 { transform-origin: 50% 50%; } -hero-icon.loop-3 { +.hero-icon.loop-3 { transform: translate(79px, 21px); opacity: 1; } diff --git a/docs/CLAUDE.md b/docs/CLAUDE.md new file mode 100644 index 0000000000000..f57dd2d41349f --- /dev/null +++ b/docs/CLAUDE.md @@ -0,0 +1,58 @@ +# Electron Documentation Guide + +## API History Migration + +Guide: `docs/development/api-history-migration-guide.md` +Style rules: `docs/development/style-guide.md` (see "API History" section) +Schema: `docs/api-history.schema.json` +Lint: `npm run lint:api-history` + +### Format + +Place YAML history block directly after the Markdown header, before parameters: + +````md +### `module.method(args)` + + + +* `arg` type - Description. +```` + +### Finding when an API was added + +- `git log --all --reverse --oneline -S "methodName" -- docs/api/file.md` — find first commit adding a method name +- `git log --reverse -L :FunctionName:path/to/source.cc` — trace C++ implementation history +- `git log --grep="keyword" --oneline` — find merge commits referencing PRs +- `gh pr view --repo electron/electron --json baseRefName` — verify PR targets main (not a backport) +- Always use the main-branch PR URL in history blocks, not backport PRs + +### Cross-referencing breaking changes + +- Search `docs/breaking-changes.md` for the API name to find deprecations/removals +- Use `git blame` on the breaking-changes entry to find the associated PR +- Add `breaking-changes-header` field using the heading ID from breaking-changes.md + +### Placement rules + +- Only add blocks to actual API entries (methods, events, properties with backtick signatures) +- Do NOT add blocks to section headers like `## Methods`, `### Instance Methods`, `## Events` +- Module-level blocks go after the `# moduleName` heading, before the module description quote +- For changes affecting multiple APIs, add a block under each affected top-level heading (see style guide "Change affecting multiple APIs") + +### Key details + +- `added` and `deprecated` arrays have `maxItems: 1`; `changes` can have multiple items +- `changes` entries require a `description` field; `added`/`deprecated` do not +- Wrap descriptions in double quotes to avoid YAML parsing issues with special characters +- Early Electron APIs (pre-2015) use merge-commit PRs (e.g., `Merge pull request #534`) +- Very early APIs (2013-2014, e.g., `ipcMain.on`, `ipcRenderer.send`) predate GitHub PRs — skip history blocks for these +- When multiple APIs were added in the same PR, they all reference the same PR URL +- Promisification PRs (e.g., #17355) count as `changes` entries with a description + - These PRs are breaking changes and should have their notes as "This method now returns a Promise instead of using a callback function." +- APIs that were deprecated and then removed from docs don't need history blocks (the removal is in `breaking-changes.md`) diff --git a/docs/README.md b/docs/README.md index 7fb1fb9afc86e..02d5d1331ca29 100644 --- a/docs/README.md +++ b/docs/README.md @@ -18,20 +18,13 @@ an issue: ## Guides and Tutorials -### Quickstart +### Getting started -* [Quick Start Guide](tutorial/quick-start.md) - * [Prerequisites](tutorial/quick-start.md#prerequisites) - * [Create a basic application](tutorial/quick-start.md#create-a-basic-application) - * [Run your application](tutorial/quick-start.md#run-your-application) - * [Package and distribute the application](tutorial/quick-start.md#package-and-distribute-the-application) +* [Introduction](tutorial/introduction.md) +* [Process Model](tutorial/process-model.md) ### Learning the basics -* [Electron's Process Model](tutorial/quick-start.md#application-architecture) - * [Main and Renderer Processes](tutorial/quick-start.md#main-and-renderer-processes) - * [Electron API](tutorial/quick-start.md#electron-api) - * [Node.js API](tutorial/quick-start.md#nodejs-api) * Adding Features to Your App * [Notifications](tutorial/notifications.md) * [Recent Documents](tutorial/recent-documents.md) @@ -43,12 +36,13 @@ an issue: * [Offline/Online Detection](tutorial/online-offline-events.md) * [Represented File for macOS BrowserWindows](tutorial/represented-file.md) * [Native File Drag & Drop](tutorial/native-file-drag-drop.md) + * [Navigation History](tutorial/navigation-history.md) * [Offscreen Rendering](tutorial/offscreen-rendering.md) * [Dark Mode](tutorial/dark-mode.md) * [Web embeds in Electron](tutorial/web-embeds.md) * [Boilerplates and CLIs](tutorial/boilerplates-and-clis.md) * [Boilerplate vs CLI](tutorial/boilerplates-and-clis.md#boilerplate-vs-cli) - * [electron-forge](tutorial/boilerplates-and-clis.md#electron-forge) + * [Electron Forge](tutorial/boilerplates-and-clis.md#electron-forge) * [electron-builder](tutorial/boilerplates-and-clis.md#electron-builder) * [electron-react-boilerplate](tutorial/boilerplates-and-clis.md#electron-react-boilerplate) * [Other Tools and Boilerplates](tutorial/boilerplates-and-clis.md#other-tools-and-boilerplates) @@ -59,25 +53,23 @@ an issue: * [Using Native Node.js Modules](tutorial/using-native-node-modules.md) * [Performance Strategies](tutorial/performance.md) * [Security Strategies](tutorial/security.md) + * [Process Sandboxing](tutorial/sandbox.md) * [Accessibility](tutorial/accessibility.md) * [Manually Enabling Accessibility Features](tutorial/accessibility.md#manually-enabling-accessibility-features) * [Testing and Debugging](tutorial/application-debugging.md) * [Debugging the Main Process](tutorial/debugging-main-process.md) * [Debugging with Visual Studio Code](tutorial/debugging-vscode.md) - * [Using Selenium and WebDriver](tutorial/using-selenium-and-webdriver.md) * [Testing on Headless CI Systems (Travis, Jenkins)](tutorial/testing-on-headless-ci.md) * [DevTools Extension](tutorial/devtools-extension.md) - * [Automated Testing with a Custom Driver](tutorial/automated-testing-with-a-custom-driver.md) + * [Automated Testing](tutorial/automated-testing.md) + * [REPL](tutorial/repl.md) * [Distribution](tutorial/application-distribution.md) - * [Supported Platforms](tutorial/support.md#supported-platforms) * [Code Signing](tutorial/code-signing.md) * [Mac App Store](tutorial/mac-app-store-submission-guide.md) * [Windows Store](tutorial/windows-store-guide.md) * [Snapcraft](tutorial/snapcraft.md) + * [ASAR Archives](tutorial/asar-archives.md) * [Updates](tutorial/updates.md) - * [Deploying an Update Server](tutorial/updates.md#deploying-an-update-server) - * [Implementing Updates in Your App](tutorial/updates.md#implementing-updates-in-your-app) - * [Applying Updates](tutorial/updates.md#applying-updates) * [Getting Support](tutorial/support.md) ## Detailed Tutorials @@ -91,12 +83,6 @@ These individual tutorials expand on topics discussed in the guide above. * Electron Releases & Developer Feedback * [Versioning Policy](tutorial/electron-versioning.md) * [Release Timelines](tutorial/electron-timelines.md) -* [Packaging App Source Code with asar](tutorial/application-packaging.md) - * [Generating asar Archives](tutorial/application-packaging.md#generating-asar-archives) - * [Using asar Archives](tutorial/application-packaging.md#using-asar-archives) - * [Limitations](tutorial/application-packaging.md#limitations-of-the-node-api) - * [Adding Unpacked Files to asar Archives](tutorial/application-packaging.md#adding-unpacked-files-to-asar-archives) -* [Testing Widevine CDM](tutorial/testing-widevine-cdm.md) --- @@ -104,61 +90,69 @@ These individual tutorials expand on topics discussed in the guide above. ## API References -* [Synopsis](api/synopsis.md) * [Process Object](api/process.md) * [Supported Command Line Switches](api/command-line-switches.md) * [Environment Variables](api/environment-variables.md) * [Chrome Extensions Support](api/extensions.md) * [Breaking API Changes](breaking-changes.md) -### Custom DOM Elements: +### Custom Web Features: -* [`File` Object](api/file-object.md) +* [`-electron-corner-smoothing` CSS Rule](api/corner-smoothing-css.md) * [`` Tag](api/webview-tag.md) * [`window.open` Function](api/window-open.md) -* [`BrowserWindowProxy` Object](api/browser-window-proxy.md) ### Modules for the Main Process: * [app](api/app.md) * [autoUpdater](api/auto-updater.md) -* [BrowserView](api/browser-view.md) +* [BaseWindow](api/base-window.md) * [BrowserWindow](api/browser-window.md) * [contentTracing](api/content-tracing.md) +* [desktopCapturer](api/desktop-capturer.md) * [dialog](api/dialog.md) * [globalShortcut](api/global-shortcut.md) * [inAppPurchase](api/in-app-purchase.md) +* [ImageView](api/image-view.md) * [ipcMain](api/ipc-main.md) * [Menu](api/menu.md) * [MenuItem](api/menu-item.md) +* [MessageChannelMain](api/message-channel-main.md) +* [MessagePortMain](api/message-port-main.md) +* [nativeTheme](api/native-theme.md) * [net](api/net.md) * [netLog](api/net-log.md) -* [nativeTheme](api/native-theme.md) * [Notification](api/notification.md) * [powerMonitor](api/power-monitor.md) * [powerSaveBlocker](api/power-save-blocker.md) * [protocol](api/protocol.md) +* [pushNotifications](api/push-notifications.md) +* [safeStorage](api/safe-storage.md) * [screen](api/screen.md) +* [ServiceWorkerMain](api/service-worker-main.md) * [session](api/session.md) +* [ShareMenu](api/share-menu.md) * [systemPreferences](api/system-preferences.md) * [TouchBar](api/touch-bar.md) * [Tray](api/tray.md) +* [utilityProcess](api/utility-process.md) +* [View](api/view.md) * [webContents](api/web-contents.md) * [webFrameMain](api/web-frame-main.md) +* [WebContentsView](api/web-contents-view.md) ### Modules for the Renderer Process (Web Page): -* [desktopCapturer](api/desktop-capturer.md) +* [contextBridge](api/context-bridge.md) * [ipcRenderer](api/ipc-renderer.md) -* [remote](api/remote.md) * [webFrame](api/web-frame.md) ### Modules for Both Processes: -* [clipboard](api/clipboard.md) +* [clipboard](api/clipboard.md) (non-sandboxed renderers only) * [crashReporter](api/crash-reporter.md) * [nativeImage](api/native-image.md) -* [shell](api/shell.md) +* [shell](api/shell.md) (non-sandboxed renderers only) ## Development diff --git a/docs/api-history.schema.json b/docs/api-history.schema.json new file mode 100644 index 0000000000000..137cb02bbb805 --- /dev/null +++ b/docs/api-history.schema.json @@ -0,0 +1,47 @@ +{ + "title": "JSON schema for API history blocks in Electron documentation", + "$schema": "http://json-schema.org/draft-07/schema#", + "$comment": "If you change this schema, remember to edit the TypeScript interfaces in the linting script.", + "definitions": { + "baseChangeSchema": { + "type": "object", + "properties": { + "pr-url": { + "description": "URL to the 'main' GitHub Pull Request for the change (i.e. not a backport PR)", + "type": "string", "pattern": "^https://github.com/electron/electron/pull/\\d+$", + "examples": [ "https://github.com/electron/electron/pull/26789" ] + }, + "breaking-changes-header": { + "description": "Heading ID for the change in `electron/docs/breaking-changes.md`", + "type": "string", "minLength": 3, + "examples": [ "deprecated-browserwindowsettrafficlightpositionposition" ] + }, + "description": { + "description": "Short description of the change", + "type": "string", "minLength": 3, "maxLength": 120, + "examples": [ "Made `trafficLightPosition` option work for `customButtonOnHover`." ] + } + }, + "required": [ "pr-url" ], + "additionalProperties": false + }, + "addedChangeSchema": { + "allOf": [ { "$ref": "#/definitions/baseChangeSchema" } ] + }, + "deprecatedChangeSchema": { + "$comment": "TODO: Make 'breaking-changes-header' required in the future.", + "allOf": [ { "$ref": "#/definitions/baseChangeSchema" } ] + }, + "changesChangeSchema": { + "$comment": "Unlike RFC, added `'type': 'object'` to appease AJV strict mode", + "allOf": [ { "$ref": "#/definitions/baseChangeSchema" }, { "type": "object", "required": [ "description" ] } ] + } + }, + "type": "object", + "properties": { + "added": { "type": "array", "minItems": 1, "maxItems": 1, "items": { "$ref": "#/definitions/addedChangeSchema" } }, + "deprecated": { "type": "array", "minItems": 1, "maxItems": 1, "items": { "$ref": "#/definitions/deprecatedChangeSchema" } }, + "changes": { "type": "array", "minItems": 1, "items": { "$ref": "#/definitions/changesChangeSchema" } } + }, + "additionalProperties": false +} diff --git a/docs/api/accelerator.md b/docs/api/accelerator.md deleted file mode 100644 index 6c5dfd1a4bfe6..0000000000000 --- a/docs/api/accelerator.md +++ /dev/null @@ -1,81 +0,0 @@ -# Accelerator - -> Define keyboard shortcuts. - -Accelerators are Strings that can contain multiple modifiers and a single key code, -combined by the `+` character, and are used to define keyboard shortcuts -throughout your application. - -Examples: - -* `CommandOrControl+A` -* `CommandOrControl+Shift+Z` - -Shortcuts are registered with the [`globalShortcut`](global-shortcut.md) module -using the [`register`](global-shortcut.md#globalshortcutregisteraccelerator-callback) -method, i.e. - -```javascript -const { app, globalShortcut } = require('electron') - -app.whenReady().then(() => { - // Register a 'CommandOrControl+Y' shortcut listener. - globalShortcut.register('CommandOrControl+Y', () => { - // Do stuff when Y and either Command/Control is pressed. - }) -}) -``` - -## Platform notice - -On Linux and Windows, the `Command` key does not have any effect so -use `CommandOrControl` which represents `Command` on macOS and `Control` on -Linux and Windows to define some accelerators. - -Use `Alt` instead of `Option`. The `Option` key only exists on macOS, whereas -the `Alt` key is available on all platforms. - -The `Super` key is mapped to the `Windows` key on Windows and Linux and -`Cmd` on macOS. - -## Available modifiers - -* `Command` (or `Cmd` for short) -* `Control` (or `Ctrl` for short) -* `CommandOrControl` (or `CmdOrCtrl` for short) -* `Alt` -* `Option` -* `AltGr` -* `Shift` -* `Super` - -## Available key codes - -* `0` to `9` -* `A` to `Z` -* `F1` to `F24` -* Punctuation like `~`, `!`, `@`, `#`, `$`, etc. -* `Plus` -* `Space` -* `Tab` -* `Capslock` -* `Numlock` -* `Scrolllock` -* `Backspace` -* `Delete` -* `Insert` -* `Return` (or `Enter` as alias) -* `Up`, `Down`, `Left` and `Right` -* `Home` and `End` -* `PageUp` and `PageDown` -* `Escape` (or `Esc` for short) -* `VolumeUp`, `VolumeDown` and `VolumeMute` -* `MediaNextTrack`, `MediaPreviousTrack`, `MediaStop` and `MediaPlayPause` -* `PrintScreen` -* NumPad Keys - * `num0` - `num9` - * `numdec` - decimal key - * `numadd` - numpad `+` key - * `numsub` - numpad `-` key - * `nummult` - numpad `*` key - * `numdiv` - numpad `÷` key diff --git a/docs/api/app.md b/docs/api/app.md index b485b339683ca..e3b967c32807a 100644 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -7,8 +7,9 @@ Process: [Main](../glossary.md#main-process) The following example shows how to quit the application when the last window is closed: -```javascript +```js const { app } = require('electron') + app.on('window-all-closed', () => { app.quit() }) @@ -23,8 +24,7 @@ The `app` object emits the following events: Emitted when the application has finished basic startup. On Windows and Linux, the `will-finish-launching` event is the same as the `ready` event; on macOS, this event represents the `applicationWillFinishLaunching` notification of -`NSApplication`. You would usually set up listeners for the `open-file` and -`open-url` events here, and start the crash reporter and auto updater. +`NSApplication`. In most cases, you should do everything in the `ready` event handler. @@ -33,15 +33,20 @@ In most cases, you should do everything in the `ready` event handler. Returns: * `event` Event -* `launchInfo` Record | [NotificationResponse](structures/notification-response.md) _macOS_ +* `launchInfo` Record\ | [NotificationResponse](structures/notification-response.md) _macOS_ Emitted once, when Electron has finished initializing. On macOS, `launchInfo` -holds the `userInfo` of the `NSUserNotification` or information from -[`UNNotificationResponse`](structures/notification-response.md) that was used to open the -application, if it was launched from Notification Center. You can also call -`app.isReady()` to check if this event has already fired and `app.whenReady()` +holds the `userInfo` of the [`NSUserNotification`](https://developer.apple.com/documentation/foundation/nsusernotification) +or information from [`UNNotificationResponse`](https://developer.apple.com/documentation/usernotifications/unnotificationresponse) +that was used to open the application, if it was launched from Notification Center. +You can also call `app.isReady()` to check if this event has already fired and `app.whenReady()` to get a Promise that is fulfilled when Electron is initialized. +> [!NOTE] +> The `ready` event is only fired after the main process has finished running the first +> tick of the event loop. If an Electron API needs to be called before the `ready` event, ensure +> that it is called synchronously in the top-level context of the main process. + ### Event: 'window-all-closed' Emitted when all windows have been closed. @@ -63,12 +68,14 @@ Emitted before the application starts closing its windows. Calling `event.preventDefault()` will prevent the default behavior, which is terminating the application. -**Note:** If application quit was initiated by `autoUpdater.quitAndInstall()`, -then `before-quit` is emitted *after* emitting `close` event on all windows and -closing them. +> [!NOTE] +> If application quit was initiated by `autoUpdater.quitAndInstall()`, +> then `before-quit` is emitted _after_ emitting `close` event on all windows and +> closing them. -**Note:** On Windows, this event will not be emitted if the app is closed due -to a shutdown/restart of the system or a user logout. +> [!NOTE] +> On Windows, this event will not be emitted if the app is closed due +> to a shutdown/restart of the system or a user logout. ### Event: 'will-quit' @@ -83,8 +90,9 @@ terminating the application. See the description of the `window-all-closed` event for the differences between the `will-quit` and `window-all-closed` events. -**Note:** On Windows, this event will not be emitted if the app is closed due -to a shutdown/restart of the system or a user logout. +> [!NOTE] +> On Windows, this event will not be emitted if the app is closed due +> to a shutdown/restart of the system or a user logout. ### Event: 'quit' @@ -95,15 +103,16 @@ Returns: Emitted when the application is quitting. -**Note:** On Windows, this event will not be emitted if the app is closed due -to a shutdown/restart of the system or a user logout. +> [!NOTE] +> On Windows, this event will not be emitted if the app is closed due +> to a shutdown/restart of the system or a user logout. ### Event: 'open-file' _macOS_ Returns: * `event` Event -* `path` String +* `path` string Emitted when the user wants to open a file with the application. The `open-file` event is usually emitted when the application is already open and the OS wants @@ -122,20 +131,22 @@ filepath. Returns: * `event` Event -* `url` String +* `url` string Emitted when the user wants to open a URL with the application. Your application's `Info.plist` file must define the URL scheme within the `CFBundleURLTypes` key, and set `NSPrincipalClass` to `AtomApplication`. -You should call `event.preventDefault()` if you want to handle this event. +As with the `open-file` event, be sure to register a listener for the `open-url` +event early in your application startup to detect if the application is being opened to handle a URL. +If you register the listener in response to a `ready` event, you'll miss URLs that trigger the launch of your application. ### Event: 'activate' _macOS_ Returns: * `event` Event -* `hasVisibleWindows` Boolean +* `hasVisibleWindows` boolean Emitted when the application is activated. Various actions can trigger this event, such as launching the application for the first time, attempting @@ -148,19 +159,32 @@ Returns: * `event` Event -Emitted when mac application become active. Difference from `activate` event is +Emitted when the application becomes active. This differs from the `activate` event in that `did-become-active` is emitted every time the app becomes active, not only -when Dock icon is clicked or application is re-launched. +when Dock icon is clicked or application is re-launched. It is also emitted when a user +switches to the app via the macOS App Switcher. + +### Event: 'did-resign-active' _macOS_ + +Returns: + +* `event` Event + +Emitted when the app is no longer active and doesn’t have focus. This can be triggered, +for example, by clicking on another application or by using the macOS App Switcher to +switch to another application. ### Event: 'continue-activity' _macOS_ Returns: * `event` Event -* `type` String - A string identifying the activity. Maps to +* `type` string - A string identifying the activity. Maps to [`NSUserActivity.activityType`][activity-type]. * `userInfo` unknown - Contains app-specific state stored by the activity on another device. +* `details` Object + * `webpageURL` string (optional) - A string identifying the URL of the webpage accessed by the activity on another device, if available. Emitted during [Handoff][handoff] when an activity from a different device wants to be resumed. You should call `event.preventDefault()` if you want to handle @@ -176,7 +200,7 @@ Supported activity types are specified in the app's `Info.plist` under the Returns: * `event` Event -* `type` String - A string identifying the activity. Maps to +* `type` string - A string identifying the activity. Maps to [`NSUserActivity.activityType`][activity-type]. Emitted during [Handoff][handoff] before an activity from a different device wants @@ -188,9 +212,9 @@ this event. Returns: * `event` Event -* `type` String - A string identifying the activity. Maps to +* `type` string - A string identifying the activity. Maps to [`NSUserActivity.activityType`][activity-type]. -* `error` String - A string with the error's localized description. +* `error` string - A string with the error's localized description. Emitted during [Handoff][handoff] when an activity from a different device fails to be resumed. @@ -200,7 +224,7 @@ fails to be resumed. Returns: * `event` Event -* `type` String - A string identifying the activity. Maps to +* `type` string - A string identifying the activity. Maps to [`NSUserActivity.activityType`][activity-type]. * `userInfo` unknown - Contains app-specific state stored by the activity. @@ -212,7 +236,7 @@ resumed on another one. Returns: * `event` Event -* `type` String - A string identifying the activity. Maps to +* `type` string - A string identifying the activity. Maps to [`NSUserActivity.activityType`][activity-type]. * `userInfo` unknown - Contains app-specific state stored by the activity. @@ -226,7 +250,9 @@ Returns: Emitted when the user clicks the native macOS new tab button. The new tab button is only visible if the current `BrowserWindow` has a -`tabbingIdentifier` +`tabbingIdentifier`. + +You must create a window in this handler in order for macOS tabbing to work as expected. ### Event: 'browser-window-blur' @@ -270,17 +296,18 @@ Returns: * `event` Event * `webContents` [WebContents](web-contents.md) -* `url` String -* `error` String - The error code +* `url` string +* `error` string - The error code * `certificate` [Certificate](structures/certificate.md) * `callback` Function - * `isTrusted` Boolean - Whether to consider the certificate as trusted + * `isTrusted` boolean - Whether to consider the certificate as trusted +* `isMainFrame` boolean Emitted when failed to verify the `certificate` for `url`, to trust the certificate you should prevent the default behavior with `event.preventDefault()` and call `callback(true)`. -```javascript +```js const { app } = require('electron') app.on('certificate-error', (event, webContents, url, error, certificate, callback) => { @@ -312,7 +339,7 @@ and `callback` can be called with an entry filtered from the list. Using `event.preventDefault()` prevents the application from using the first certificate from the store. -```javascript +```js const { app } = require('electron') app.on('select-client-certificate', (event, webContents, url, list, callback) => { @@ -326,26 +353,27 @@ app.on('select-client-certificate', (event, webContents, url, list, callback) => Returns: * `event` Event -* `webContents` [WebContents](web-contents.md) +* `webContents` [WebContents](web-contents.md) (optional) * `authenticationResponseDetails` Object * `url` URL + * `pid` number * `authInfo` Object - * `isProxy` Boolean - * `scheme` String - * `host` String + * `isProxy` boolean + * `scheme` string + * `host` string * `port` Integer - * `realm` String + * `realm` string * `callback` Function - * `username` String (optional) - * `password` String (optional) + * `username` string (optional) + * `password` string (optional) -Emitted when `webContents` wants to do basic auth. +Emitted when `webContents` or [Utility process](../glossary.md#utility-process) wants to do basic auth. The default behavior is to cancel all authentications. To override this you should prevent the default behavior with `event.preventDefault()` and call `callback(username, password)` with the credentials. -```javascript +```js const { app } = require('electron') app.on('login', (event, webContents, details, authInfo, callback) => { @@ -362,61 +390,24 @@ page. Emitted whenever there is a GPU info update. -### Event: 'gpu-process-crashed' _Deprecated_ - -Returns: - -* `event` Event -* `killed` Boolean - -Emitted when the GPU process crashes or is killed. - -**Deprecated:** This event is superceded by the `child-process-gone` event -which contains more information about why the child process disappeared. It -isn't always because it crashed. The `killed` boolean can be replaced by -checking `reason === 'killed'` when you switch to that event. - -### Event: 'renderer-process-crashed' _Deprecated_ +### Event: 'render-process-gone' Returns: * `event` Event * `webContents` [WebContents](web-contents.md) -* `killed` Boolean - -Emitted when the renderer process of `webContents` crashes or is killed. - -**Deprecated:** This event is superceded by the `render-process-gone` event -which contains more information about why the render process disappeared. It -isn't always because it crashed. The `killed` boolean can be replaced by -checking `reason === 'killed'` when you switch to that event. - -#### Event: 'render-process-gone' - -Returns: - -* `event` Event -* `webContents` [WebContents](web-contents.md) -* `details` Object - * `reason` String - The reason the render process is gone. Possible values: - * `clean-exit` - Process exited with an exit code of zero - * `abnormal-exit` - Process exited with a non-zero exit code - * `killed` - Process was sent a SIGTERM or otherwise killed externally - * `crashed` - Process crashed - * `oom` - Process ran out of memory - * `launch-failed` - Process never successfully launched - * `integrity-failure` - Windows code integrity checks failed +* `details` [RenderProcessGoneDetails](structures/render-process-gone-details.md) Emitted when the renderer process unexpectedly disappears. This is normally because it was crashed or killed. -#### Event: 'child-process-gone' +### Event: 'child-process-gone' Returns: * `event` Event * `details` Object - * `type` String - Process type. One of the following values: + * `type` string - Process type. One of the following values: * `Utility` * `Zygote` * `Sandbox helper` @@ -424,7 +415,7 @@ Returns: * `Pepper Plugin` * `Pepper Plugin Broker` * `Unknown` - * `reason` String - The reason the child process is gone. Possible values: + * `reason` string - The reason the child process is gone. Possible values: * `clean-exit` - Process exited with an exit code of zero * `abnormal-exit` - Process exited with a non-zero exit code * `killed` - Process was sent a SIGTERM or otherwise killed externally @@ -432,10 +423,11 @@ Returns: * `oom` - Process ran out of memory * `launch-failed` - Process never successfully launched * `integrity-failure` - Windows code integrity checks failed - * `exitCode` Number - The exit code for the process - (e.g. status from waitpid if on posix, from GetExitCodeProcess on Windows). - * `serviceName` String (optional) - The non-localized name of the process. - * `name` String (optional) - The name of the process. + * `memory-eviction` - Process proactively terminated to prevent a future out-of-memory (OOM) situation + * `exitCode` number - The exit code for the process + (e.g. status from waitpid if on POSIX, from GetExitCodeProcess on Windows). + * `serviceName` string (optional) - The non-localized name of the process. + * `name` string (optional) - The name of the process. Examples for utility: `Audio Service`, `Content Decryption Module Service`, `Network Service`, `Video Capture`, etc. Emitted when the child process unexpectedly disappears. This is normally @@ -446,7 +438,7 @@ because it was crashed or killed. It does not include renderer processes. Returns: * `event` Event -* `accessibilitySupportEnabled` Boolean - `true` when Chrome's accessibility +* `accessibilitySupportEnabled` boolean - `true` when Chrome's accessibility support is enabled, `false` otherwise. Emitted when Chrome's accessibility support changes. This event fires when @@ -462,7 +454,7 @@ Returns: Emitted when Electron has created a new `session`. -```javascript +```js const { app } = require('electron') app.on('session-created', (session) => { @@ -475,8 +467,9 @@ app.on('session-created', (session) => { Returns: * `event` Event -* `argv` String[] - An array of the second instance's command line arguments -* `workingDirectory` String - The second instance's working directory +* `argv` string[] - An array of the second instance's command line arguments +* `workingDirectory` string - The second instance's working directory +* `additionalData` unknown - A JSON object of additional data passed from the second instance This event will be emitted inside the primary instance of your application when a second instance has been executed and calls `app.requestSingleInstanceLock()`. @@ -486,88 +479,28 @@ and `workingDirectory` is its current working directory. Usually applications respond to this by making their primary window focused and non-minimized. -**Note:** If the second instance is started by a different user than the first, the `argv` array will not include the arguments. +> [!NOTE] +> `argv` will not be exactly the same list of arguments as those passed +> to the second instance. The order might change and additional arguments might be appended. +> If you need to maintain the exact same arguments, it's advised to use `additionalData` instead. + +> [!NOTE] +> If the second instance is started by a different user than the first, the `argv` array will not include the arguments. This event is guaranteed to be emitted after the `ready` event of `app` gets emitted. -**Note:** Extra command line arguments might be added by Chromium, -such as `--original-process-start-time`. - -### Event: 'desktop-capturer-get-sources' - -Returns: - -* `event` Event -* `webContents` [WebContents](web-contents.md) - -Emitted when `desktopCapturer.getSources()` is called in the renderer process of `webContents`. -Calling `event.preventDefault()` will make it return empty sources. - -### Event: 'remote-require' _Deprecated_ - -Returns: - -* `event` Event -* `webContents` [WebContents](web-contents.md) -* `moduleName` String - -Emitted when `remote.require()` is called in the renderer process of `webContents`. -Calling `event.preventDefault()` will prevent the module from being returned. -Custom value can be returned by setting `event.returnValue`. - -### Event: 'remote-get-global' _Deprecated_ - -Returns: - -* `event` Event -* `webContents` [WebContents](web-contents.md) -* `globalName` String - -Emitted when `remote.getGlobal()` is called in the renderer process of `webContents`. -Calling `event.preventDefault()` will prevent the global from being returned. -Custom value can be returned by setting `event.returnValue`. - -### Event: 'remote-get-builtin' _Deprecated_ - -Returns: - -* `event` Event -* `webContents` [WebContents](web-contents.md) -* `moduleName` String - -Emitted when `remote.getBuiltin()` is called in the renderer process of `webContents`. -Calling `event.preventDefault()` will prevent the module from being returned. -Custom value can be returned by setting `event.returnValue`. - -### Event: 'remote-get-current-window' _Deprecated_ - -Returns: - -* `event` Event -* `webContents` [WebContents](web-contents.md) - -Emitted when `remote.getCurrentWindow()` is called in the renderer process of `webContents`. -Calling `event.preventDefault()` will prevent the object from being returned. -Custom value can be returned by setting `event.returnValue`. - -### Event: 'remote-get-current-web-contents' _Deprecated_ - -Returns: - -* `event` Event -* `webContents` [WebContents](web-contents.md) - -Emitted when `remote.getCurrentWebContents()` is called in the renderer process of `webContents`. -Calling `event.preventDefault()` will prevent the object from being returned. -Custom value can be returned by setting `event.returnValue`. +> [!NOTE] +> Extra command line arguments might be added by Chromium, +> such as `--original-process-start-time`. ## Methods The `app` object has the following methods: -**Note:** Some methods are only available on specific operating systems and are -labeled as such. +> [!NOTE] +> Some methods are only available on specific operating systems and are +> labeled as such. ### `app.quit()` @@ -591,26 +524,26 @@ and `will-quit` events will not be emitted. ### `app.relaunch([options])` * `options` Object (optional) - * `args` String[] (optional) - * `execPath` String (optional) + * `args` string[] (optional) + * `execPath` string (optional) -Relaunches the app when current instance exits. +Relaunches the app when the current instance exits. By default, the new instance will use the same working directory and command line -arguments with current instance. When `args` is specified, the `args` will be -passed as command line arguments instead. When `execPath` is specified, the -`execPath` will be executed for relaunch instead of current app. +arguments as the current instance. When `args` is specified, the `args` will be +passed as the command line arguments instead. When `execPath` is specified, the +`execPath` will be executed for the relaunch instead of the current app. -Note that this method does not quit the app when executed, you have to call +Note that this method does not quit the app when executed. You have to call `app.quit` or `app.exit` after calling `app.relaunch` to make the app restart. -When `app.relaunch` is called for multiple times, multiple instances will be -started after current instance exited. +When `app.relaunch` is called multiple times, multiple instances will be +started after the current instance exits. -An example of restarting current instance immediately and adding a new command +An example of restarting the current instance immediately and adding a new command line argument to the new instance: -```javascript +```js const { app } = require('electron') app.relaunch({ args: process.argv.slice(1).concat(['--relaunch']) }) @@ -619,7 +552,7 @@ app.exit(0) ### `app.isReady()` -Returns `Boolean` - `true` if Electron has finished initializing, `false` otherwise. +Returns `boolean` - `true` if Electron has finished initializing, `false` otherwise. See also `app.whenReady()`. ### `app.whenReady()` @@ -631,18 +564,27 @@ and subscribing to the `ready` event if the app is not ready yet. ### `app.focus([options])` * `options` Object (optional) - * `steal` Boolean _macOS_ - Make the receiver the active app even if another app is + * `steal` boolean _macOS_ - Make the receiver the active app even if another app is currently active. -On Linux, focuses on the first visible window. On macOS, makes the application -the active app. On Windows, focuses on the application's first window. +On macOS, makes the application the active app. On Windows, focuses on the application's +first window. On Linux, either focuses on the first visible window (X11) or requests +focus but may instead show a notification or flash the app icon (Wayland). You should seek to use the `steal` option as sparingly as possible. +### `app.isActive()` _macOS_ + +Returns `boolean` - `true` if the application is active (i.e. focused). + ### `app.hide()` _macOS_ Hides all application windows without minimizing them. +### `app.isHidden()` _macOS_ + +Returns `boolean` - `true` if the application—including all of its windows—is hidden (e.g. with `Command-H`), `false` otherwise. + ### `app.show()` _macOS_ Shows application windows after they were hidden. Does not automatically focus @@ -650,7 +592,7 @@ them. ### `app.setAppLogsPath([path])` -* `path` String (optional) - A custom path for your logs. Must be absolute. +* `path` string (optional) - A custom path for your logs. Must be absolute. Sets or creates a directory your app's logs which can then be manipulated with `app.getPath()` or `app.setPath(pathName, newPath)`. @@ -658,22 +600,36 @@ Calling `app.setAppLogsPath()` without a `path` parameter will result in this di ### `app.getAppPath()` -Returns `String` - The current application directory. +Returns `string` - The current application directory. ### `app.getPath(name)` -* `name` String - You can request the following paths by the name: +* `name` string - You can request the following paths by the name: * `home` User's home directory. * `appData` Per-user application data directory, which by default points to: * `%APPDATA%` on Windows * `$XDG_CONFIG_HOME` or `~/.config` on Linux * `~/Library/Application Support` on macOS - * `userData` The directory for storing your app's configuration files, which by - default it is the `appData` directory appended with your app's name. - * `cache` + * `assets` The directory where app assets such as `resources.pak` are stored. By default this is the same as the folder containing the `exe` path. Available on Windows and Linux only. + * `userData` The directory for storing your app's configuration files, which + by default is the `appData` directory appended with your app's name. By + convention files storing user data should be written to this directory, and + it is not recommended to write large files here because some environments + may backup this directory to cloud storage. It is recommended to store + app-specific files within a subdirectory of `userData` (e.g., + `path.join(app.getPath('userData'), 'my-app-data')`) rather than directly + in `userData` itself, to avoid naming conflicts with Chromium's own + subdirectories (such as `Cache`, `GPUCache`, and `Local Storage`). + * `sessionData` The directory for storing data generated by `Session`, such + as localStorage, cookies, disk cache, downloaded dictionaries, network + state, DevTools files. By default this points to `userData`. Chromium may + write very large disk cache here, so if your app does not rely on browser + storage like localStorage or cookies to save user data, it is recommended + to set this directory to other locations to avoid polluting the `userData` + directory. * `temp` Temporary directory. * `exe` The current executable file. - * `module` The `libchromiumcontent` library. + * `module` The location of the Chromium module. By default this is synonymous with `exe`. * `desktop` The current user's Desktop directory. * `documents` Directory for a user's "My Documents". * `downloads` Directory for a user's downloads. @@ -684,16 +640,16 @@ Returns `String` - The current application directory. * `logs` Directory for your app's log folder. * `crashDumps` Directory where crash dumps are stored. -Returns `String` - A path to a special directory or file associated with `name`. On +Returns `string` - A path to a special directory or file associated with `name`. On failure, an `Error` is thrown. -If `app.getPath('logs')` is called without called `app.setAppLogsPath()` being called first, a default log directory will be created equivalent to calling `app.setAppLogsPath()` without a `path` parameter. +If `app.getPath('logs')` is called without calling `app.setAppLogsPath()` being called first, a default log directory will be created equivalent to calling `app.setAppLogsPath()` without a `path` parameter. ### `app.getFileIcon(path[, options])` -* `path` String +* `path` string * `options` Object (optional) - * `size` String + * `size` string * `small` - 16x16 * `normal` - 32x32 * `large` - 48x48 on _Linux_, 32x32 on _Windows_, unsupported on _macOS_. @@ -702,7 +658,7 @@ Returns `Promise` - fulfilled with the app's icon, which is a [Nati Fetches a path's associated icon. -On _Windows_, there a 2 kinds of icons: +On _Windows_, there are 2 kinds of icons: * Icons associated with certain file extensions, like `.mp3`, `.png`, etc. * Icons inside the file itself, like `.exe`, `.dll`, `.ico`. @@ -711,8 +667,8 @@ On _Linux_ and _macOS_, icons depend on the application associated with file mim ### `app.setPath(name, path)` -* `name` String -* `path` String +* `name` string +* `path` string Overrides the `path` to a special directory or file associated with `name`. If the path specifies a directory that does not exist, an `Error` is thrown. @@ -720,19 +676,19 @@ In that case, the directory should be created with `fs.mkdirSync` or similar. You can only override paths of a `name` defined in `app.getPath`. -By default, web pages' cookies and caches will be stored under the `userData` +By default, web pages' cookies and caches will be stored under the `sessionData` directory. If you want to change this location, you have to override the -`userData` path before the `ready` event of the `app` module is emitted. +`sessionData` path before the `ready` event of the `app` module is emitted. ### `app.getVersion()` -Returns `String` - The version of the loaded application. If no version is found in the +Returns `string` - The version of the loaded application. If no version is found in the application's `package.json` file, the version of the current bundle or executable is returned. ### `app.getName()` -Returns `String` - The current application's name, which is the name in the application's +Returns `string` - The current application's name, which is the name in the application's `package.json` file. Usually the `name` field of `package.json` is a short lowercase name, according @@ -742,32 +698,87 @@ preferred over `name` by Electron. ### `app.setName(name)` -* `name` String +* `name` string Overrides the current application's name. -**Note:** This function overrides the name used internally by Electron; it does not affect the name that the OS uses. +> [!NOTE] +> This function overrides the name used internally by Electron; it does not affect the name that the OS uses. ### `app.getLocale()` -Returns `String` - The current application locale. Possible return values are documented [here](locales.md). +Returns `string` - The current application locale, fetched using Chromium's `l10n_util` library. +Possible return values are documented [here](https://source.chromium.org/chromium/chromium/src/+/main:ui/base/l10n/l10n_util.cc). + +To set the locale, you'll want to use a command line switch at app startup, which may be found [here](command-line-switches.md). -To set the locale, you'll want to use a command line switch at app startup, which may be found [here](https://github.com/electron/electron/blob/master/docs/api/command-line-switches.md). +> [!NOTE] +> When distributing your packaged app, you have to also ship the +> `locales` folder. -**Note:** When distributing your packaged app, you have to also ship the -`locales` folder. +> [!NOTE] +> This API must be called after the `ready` event is emitted. -**Note:** On Windows, you have to call it after the `ready` events gets emitted. +> [!NOTE] +> To see example return values of this API compared to other locale and language APIs, see [`app.getPreferredSystemLanguages()`](#appgetpreferredsystemlanguages). ### `app.getLocaleCountryCode()` -Returns `String` - User operating system's locale two-letter [ISO 3166](https://www.iso.org/iso-3166-country-codes.html) country code. The value is taken from native OS APIs. +Returns `string` - User operating system's locale two-letter [ISO 3166](https://www.iso.org/iso-3166-country-codes.html) country code. The value is taken from native OS APIs. + +> [!NOTE] +> When unable to detect locale country code, it returns empty string. + +### `app.getSystemLocale()` + +Returns `string` - The current system locale. On Windows and Linux, it is fetched using Chromium's `i18n` library. On macOS, `[NSLocale currentLocale]` is used instead. To get the user's current system language, which is not always the same as the locale, it is better to use [`app.getPreferredSystemLanguages()`](#appgetpreferredsystemlanguages). + +Different operating systems also use the regional data differently: + +* Windows 11 uses the regional format for numbers, dates, and times. +* macOS Monterey uses the region for formatting numbers, dates, times, and for selecting the currency symbol to use. + +Therefore, this API can be used for purposes such as choosing a format for rendering dates and times in a calendar app, especially when the developer wants the format to be consistent with the OS. + +> [!NOTE] +> This API must be called after the `ready` event is emitted. + +> [!NOTE] +> To see example return values of this API compared to other locale and language APIs, see [`app.getPreferredSystemLanguages()`](#appgetpreferredsystemlanguages). + +### `app.getPreferredSystemLanguages()` + +Returns `string[]` - The user's preferred system languages from most preferred to least preferred, including the country codes if applicable. A user can modify and add to this list on Windows or macOS through the Language and Region settings. + +The API uses `GlobalizationPreferences` (with a fallback to `GetSystemPreferredUILanguages`) on Windows, `\[NSLocale preferredLanguages\]` on macOS, and `g_get_language_names` on Linux. + +This API can be used for purposes such as deciding what language to present the application in. + +Here are some examples of return values of the various language and locale APIs with different configurations: + +On Windows, given application locale is German, the regional format is Finnish (Finland), and the preferred system languages from most to least preferred are French (Canada), English (US), Simplified Chinese (China), Finnish, and Spanish (Latin America): + +```js +app.getLocale() // 'de' +app.getSystemLocale() // 'fi-FI' +app.getPreferredSystemLanguages() // ['fr-CA', 'en-US', 'zh-Hans-CN', 'fi', 'es-419'] +``` + +On macOS, given the application locale is German, the region is Finland, and the preferred system languages from most to least preferred are French (Canada), English (US), Simplified Chinese, and Spanish (Latin America): + +```js +app.getLocale() // 'de' +app.getSystemLocale() // 'fr-FI' +app.getPreferredSystemLanguages() // ['fr-CA', 'en-US', 'zh-Hans-FI', 'es-419'] +``` -**Note:** When unable to detect locale country code, it returns empty string. +Both the available languages and regions and the possible return values differ between the two operating systems. + +As can be seen with the example above, on Windows, it is possible that a preferred system language has no country code, and that one of the preferred system languages corresponds with the language used for the regional format. On macOS, the region serves more as a default country code: the user doesn't need to have Finnish as a preferred language to use Finland as the region, and the country code `FI` is used as the country code for preferred system languages that do not have associated countries in the language name. ### `app.addRecentDocument(path)` _macOS_ _Windows_ -* `path` String +* `path` string Adds `path` to the recent documents list. @@ -778,17 +789,33 @@ bar, and on macOS, you can visit it from dock menu. Clears the recent documents list. +### `app.getRecentDocuments()` _macOS_ _Windows_ + +Returns `string[]` - An array containing documents in the most recent documents list. + +```js +const { app } = require('electron') + +const path = require('node:path') + +const file = path.join(app.getPath('desktop'), 'foo.txt') +app.addRecentDocument(file) + +const recents = app.getRecentDocuments() +console.log(recents) // ['/path/to/desktop/foo.txt'} +``` + ### `app.setAsDefaultProtocolClient(protocol[, path, args])` -* `protocol` String - The name of your protocol, without `://`. For example, +* `protocol` string - The name of your protocol, without `://`. For example, if you want your app to handle `electron://` links, call this method with `electron` as the parameter. -* `path` String (optional) _Windows_ - The path to the Electron executable. +* `path` string (optional) _Windows_ - The path to the Electron executable. Defaults to `process.execPath` -* `args` String[] (optional) _Windows_ - Arguments passed to the executable. +* `args` string[] (optional) _Windows_ - Arguments passed to the executable. Defaults to an empty array -Returns `Boolean` - Whether the call succeeded. +Returns `boolean` - Whether the call succeeded. Sets the current executable as the default handler for a protocol (aka URI scheme). It allows you to integrate your app deeper into the operating system. @@ -796,54 +823,57 @@ Once registered, all links with `your-protocol://` will be opened with the current executable. The whole link, including protocol, will be passed to your application as a parameter. -**Note:** On macOS, you can only register protocols that have been added to -your app's `info.plist`, which cannot be modified at runtime. However, you can -change the file during build time via [Electron Forge][electron-forge], -[Electron Packager][electron-packager], or by editing `info.plist` with a text -editor. Please refer to [Apple's documentation][CFBundleURLTypes] for details. +> [!NOTE] +> On macOS, you can only register protocols that have been added to +> your app's `info.plist`, which cannot be modified at runtime. However, you can +> change the file during build time via [Electron Forge][electron-forge], +> [Electron Packager][electron-packager], or by editing `info.plist` with a text +> editor. Please refer to [Apple's documentation][CFBundleURLTypes] for details. -**Note:** In a Windows Store environment (when packaged as an `appx`) this API -will return `true` for all calls but the registry key it sets won't be accessible -by other applications. In order to register your Windows Store application -as a default protocol handler you must [declare the protocol in your manifest](https://docs.microsoft.com/en-us/uwp/schemas/appxpackage/uapmanifestschema/element-uap-protocol). +> [!NOTE] +> In a Windows Store environment (when packaged as an `appx`) this API +> will return `true` for all calls but the registry key it sets won't be accessible +> by other applications. In order to register your Windows Store application +> as a default protocol handler you must [declare the protocol in your manifest](https://learn.microsoft.com/en-us/uwp/schemas/appxpackage/uapmanifestschema/element-uap-protocol). The API uses the Windows Registry and `LSSetDefaultHandlerForURLScheme` internally. ### `app.removeAsDefaultProtocolClient(protocol[, path, args])` _macOS_ _Windows_ -* `protocol` String - The name of your protocol, without `://`. -* `path` String (optional) _Windows_ - Defaults to `process.execPath` -* `args` String[] (optional) _Windows_ - Defaults to an empty array +* `protocol` string - The name of your protocol, without `://`. +* `path` string (optional) _Windows_ - Defaults to `process.execPath` +* `args` string[] (optional) _Windows_ - Defaults to an empty array -Returns `Boolean` - Whether the call succeeded. +Returns `boolean` - Whether the call succeeded. This method checks if the current executable as the default handler for a protocol (aka URI scheme). If so, it will remove the app as the default handler. ### `app.isDefaultProtocolClient(protocol[, path, args])` -* `protocol` String - The name of your protocol, without `://`. -* `path` String (optional) _Windows_ - Defaults to `process.execPath` -* `args` String[] (optional) _Windows_ - Defaults to an empty array +* `protocol` string - The name of your protocol, without `://`. +* `path` string (optional) _Windows_ - Defaults to `process.execPath` +* `args` string[] (optional) _Windows_ - Defaults to an empty array -Returns `Boolean` - Whether the current executable is the default handler for a +Returns `boolean` - Whether the current executable is the default handler for a protocol (aka URI scheme). -**Note:** On macOS, you can use this method to check if the app has been -registered as the default protocol handler for a protocol. You can also verify -this by checking `~/Library/Preferences/com.apple.LaunchServices.plist` on the -macOS machine. Please refer to -[Apple's documentation][LSCopyDefaultHandlerForURLScheme] for details. +> [!NOTE] +> On macOS, you can use this method to check if the app has been +> registered as the default protocol handler for a protocol. You can also verify +> this by checking `~/Library/Preferences/com.apple.LaunchServices.plist` on the +> macOS machine. Please refer to +> [Apple's documentation][LSCopyDefaultHandlerForURLScheme] for details. The API uses the Windows Registry and `LSCopyDefaultHandlerForURLScheme` internally. ### `app.getApplicationNameForProtocol(url)` -* `url` String - a URL with the protocol name to check. Unlike the other +* `url` string - a URL with the protocol name to check. Unlike the other methods in this family, this accepts an entire URL, including `://` at a minimum (e.g. `https://`). -Returns `String` - Name of the application handling the protocol, or an empty +Returns `string` - Name of the application handling the protocol, or an empty string if there is no handler. For instance, if Electron is the default handler of the URL, this could be `Electron` on Windows and Mac. However, don't rely on the precise format which is not guaranteed to remain unchanged. @@ -854,15 +884,15 @@ This method returns the application name of the default handler for the protocol ### `app.getApplicationInfoForProtocol(url)` _macOS_ _Windows_ -* `url` String - a URL with the protocol name to check. Unlike the other +* `url` string - a URL with the protocol name to check. Unlike the other methods in this family, this accepts an entire URL, including `://` at a minimum (e.g. `https://`). Returns `Promise` - Resolve with an object containing the following: * `icon` NativeImage - the display icon of the app handling the protocol. -* `path` String - installation path of the app handling the protocol. -* `name` String - display name of the app handling the protocol. +* `path` string - installation path of the app handling the protocol. +* `name` string - display name of the app handling the protocol. This method returns a promise that contains the application name, icon and path of the default handler for the protocol (aka URI scheme) of a URL. @@ -875,10 +905,11 @@ Adds `tasks` to the [Tasks][tasks] category of the Jump List on Windows. `tasks` is an array of [`Task`](structures/task.md) objects. -Returns `Boolean` - Whether the call succeeded. +Returns `boolean` - Whether the call succeeded. -**Note:** If you'd like to customize the Jump List even more use -`app.setJumpList(categories)` instead. +> [!NOTE] +> If you'd like to customize the Jump List even more use +> `app.setJumpList(categories)` instead. ### `app.getJumpListSettings()` _Windows_ @@ -897,6 +928,8 @@ Returns `Object`: * `categories` [JumpListCategory[]](structures/jump-list-category.md) | `null` - Array of `JumpListCategory` objects. +Returns `string` + Sets or removes a custom Jump List for the application, and returns one of the following strings: @@ -914,21 +947,28 @@ following strings: If `categories` is `null` the previously set custom Jump List (if any) will be replaced by the standard Jump List for the app (managed by Windows). -**Note:** If a `JumpListCategory` object has neither the `type` nor the `name` -property set then its `type` is assumed to be `tasks`. If the `name` property +> [!NOTE] +> If a `JumpListCategory` object has neither the `type` nor the `name` +> property set then its `type` is assumed to be `tasks`. If the `name` property is set but the `type` property is omitted then the `type` is assumed to be `custom`. -**Note:** Users can remove items from custom categories, and Windows will not -allow a removed item to be added back into a custom category until **after** -the next successful call to `app.setJumpList(categories)`. Any attempt to -re-add a removed item to a custom category earlier than that will result in the -entire custom category being omitted from the Jump List. The list of removed -items can be obtained using `app.getJumpListSettings()`. +> [!NOTE] +> Users can remove items from custom categories, and Windows will not +> allow a removed item to be added back into a custom category until **after** +> the next successful call to `app.setJumpList(categories)`. Any attempt to +> re-add a removed item to a custom category earlier than that will result in the +> entire custom category being omitted from the Jump List. The list of removed +> items can be obtained using `app.getJumpListSettings()`. + +> [!NOTE] +> The maximum length of a Jump List item's `description` property is +> 260 characters. Beyond this limit, the item will not be added to the Jump +> List, nor will it be displayed. Here's a very simple example of creating a custom Jump List: -```javascript +```js const { app } = require('electron') app.setJumpList([ @@ -948,7 +988,7 @@ app.setJumpList([ title: 'Tool A', program: process.execPath, args: '--run-tool-a', - icon: process.execPath, + iconPath: process.execPath, iconIndex: 0, description: 'Runs Tool A' }, @@ -957,7 +997,7 @@ app.setJumpList([ title: 'Tool B', program: process.execPath, args: '--run-tool-b', - icon: process.execPath, + iconPath: process.execPath, iconIndex: 0, description: 'Runs Tool B' } @@ -986,9 +1026,11 @@ app.setJumpList([ ]) ``` -### `app.requestSingleInstanceLock()` +### `app.requestSingleInstanceLock([additionalData])` + +* `additionalData` Record\ (optional) - A JSON object containing additional data to send to the first instance. -Returns `Boolean` +Returns `boolean` The return value of this method indicates whether or not this instance of your application successfully obtained the lock. If it failed to obtain the lock, @@ -1009,16 +1051,21 @@ use this method to ensure single instance. An example of activating the window of primary instance when a second instance starts: -```javascript -const { app } = require('electron') +```js +const { app, BrowserWindow } = require('electron') + let myWindow = null -const gotTheLock = app.requestSingleInstanceLock() +const additionalData = { myKey: 'myValue' } +const gotTheLock = app.requestSingleInstanceLock(additionalData) if (!gotTheLock) { app.quit() } else { - app.on('second-instance', (event, commandLine, workingDirectory) => { + app.on('second-instance', (event, commandLine, workingDirectory, additionalData) => { + // Print out data received from the second instance. + console.log(additionalData) + // Someone tried to run a second instance, we should focus our window. if (myWindow) { if (myWindow.isMinimized()) myWindow.restore() @@ -1026,16 +1073,16 @@ if (!gotTheLock) { } }) - // Create myWindow, load the rest of the app, etc... app.whenReady().then(() => { - myWindow = createWindow() + myWindow = new BrowserWindow({}) + myWindow.loadURL('https://electronjs.org') }) } ``` ### `app.hasSingleInstanceLock()` -Returns `Boolean` +Returns `boolean` This method returns whether or not this instance of your app is currently holding the single instance lock. You can request the lock with @@ -1049,10 +1096,10 @@ allow multiple instances of the application to once again run side by side. ### `app.setUserActivity(type, userInfo[, webpageURL])` _macOS_ -* `type` String - Uniquely identifies the activity. Maps to +* `type` string - Uniquely identifies the activity. Maps to [`NSUserActivity.activityType`][activity-type]. * `userInfo` any - App-specific state to store for use by another device. -* `webpageURL` String (optional) - The webpage to load in a browser if no suitable app is +* `webpageURL` string (optional) - The webpage to load in a browser if no suitable app is installed on the resuming device. The scheme must be `http` or `https`. Creates an `NSUserActivity` and sets it as the current activity. The activity @@ -1060,7 +1107,7 @@ is eligible for [Handoff][handoff] to another device afterward. ### `app.getCurrentActivityType()` _macOS_ -Returns `String` - The type of the currently running activity. +Returns `string` - The type of the currently running activity. ### `app.invalidateCurrentActivity()` _macOS_ @@ -1072,7 +1119,7 @@ Marks the current [Handoff][handoff] user activity as inactive without invalidat ### `app.updateCurrentActivity(type, userInfo)` _macOS_ -* `type` String - Uniquely identifies the activity. Maps to +* `type` string - Uniquely identifies the activity. Maps to [`NSUserActivity.activityType`][activity-type]. * `userInfo` any - App-specific state to store for use by another device. @@ -1081,13 +1128,26 @@ Updates the current activity if its type matches `type`, merging the entries fro ### `app.setAppUserModelId(id)` _Windows_ -* `id` String +* `id` string Changes the [Application User Model ID][app-user-model-id] to `id`. +### `app.setToastActivatorCLSID(id)` _Windows_ + +* `id` string + +Changes the [Toast Activator CLSID][toast-activator-clsid] to `id`. If one is not set via this method, it will be randomly generated for the app. + +* The value must be a valid GUID/CLSID in one of the following forms: + * Canonical brace-wrapped: `{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}` (preferred) + * Canonical without braces: `XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX` (braces will be added automatically) +* Hex digits are case-insensitive. + +This method should be called early (before showing notifications) so the value is baked into the registration/shortcut. Supplying an empty string or an unparsable value throws and leaves the existing (or generated) CLSID unchanged. If this method is never called, a random CLSID is generated once per run and exposed via `app.toastActivatorCLSID`. + ### `app.setActivationPolicy(policy)` _macOS_ -* `policy` String - Can be 'regular', 'accessory', or 'prohibited'. +* `policy` string - Can be 'regular', 'accessory', or 'prohibited'. Sets the activation policy for a given app. @@ -1100,14 +1160,78 @@ Activation policy types: ### `app.importCertificate(options, callback)` _Linux_ * `options` Object - * `certificate` String - Path for the pkcs12 file. - * `password` String - Passphrase for the certificate. + * `certificate` string - Path for the pkcs12 file. + * `password` string - Passphrase for the certificate. * `callback` Function * `result` Integer - Result of import. Imports the certificate in pkcs12 format into the platform certificate store. `callback` is called with the `result` of import operation, a value of `0` -indicates success while any other value indicates failure according to Chromium [net_error_list](https://source.chromium.org/chromium/chromium/src/+/master:net/base/net_error_list.h). +indicates success while any other value indicates failure according to Chromium [net_error_list](https://source.chromium.org/chromium/chromium/src/+/main:net/base/net_error_list.h). + +### `app.configureHostResolver(options)` + +* `options` Object + * `enableBuiltInResolver` boolean (optional) - Whether the built-in host + resolver is used in preference to getaddrinfo. When enabled, the built-in + resolver will attempt to use the system's DNS settings to do DNS lookups + itself. Enabled by default on macOS, disabled by default on Windows and + Linux. + * `enableHappyEyeballs` boolean (optional) - Whether the + [Happy Eyeballs V3][happy-eyeballs-v3] algorithm should be used in creating + network connections. When enabled, hostnames resolving to multiple IP + addresses will be attempted in parallel to have a chance at establishing a + connection more quickly. + * `secureDnsMode` string (optional) - Can be 'off', 'automatic' or 'secure'. + Configures the DNS-over-HTTP mode. When 'off', no DoH lookups will be + performed. When 'automatic', DoH lookups will be performed first if DoH is + available, and insecure DNS lookups will be performed as a fallback. When + 'secure', only DoH lookups will be performed. Defaults to 'automatic'. + * `secureDnsServers` string[] (optional) - A list of DNS-over-HTTP + server templates. See [RFC8484 § 3][] for details on the template format. + Most servers support the POST method; the template for such servers is + simply a URI. Note that for [some DNS providers][doh-providers], the + resolver will automatically upgrade to DoH unless DoH is explicitly + disabled, even if there are no DoH servers provided in this list. + * `enableAdditionalDnsQueryTypes` boolean (optional) - Controls whether additional DNS + query types, e.g. HTTPS (DNS type 65) will be allowed besides the + traditional A and AAAA queries when a request is being made via insecure + DNS. Has no effect on Secure DNS which always allows additional types. + Defaults to true. + +Configures host resolution (DNS and DNS-over-HTTPS). By default, the following +resolvers will be used, in order: + +1. DNS-over-HTTPS, if the [DNS provider supports it][doh-providers], then +2. the built-in resolver (enabled on macOS only by default), then +3. the system's resolver (e.g. `getaddrinfo`). + +This can be configured to either restrict usage of non-encrypted DNS +(`secureDnsMode: "secure"`), or disable DNS-over-HTTPS (`secureDnsMode: +"off"`). It is also possible to enable or disable the built-in resolver. + +To disable insecure DNS, you can specify a `secureDnsMode` of `"secure"`. If you do +so, you should make sure to provide a list of DNS-over-HTTPS servers to use, in +case the user's DNS configuration does not include a provider that supports +DoH. + +```js +const { app } = require('electron') + +app.whenReady().then(() => { + app.configureHostResolver({ + secureDnsMode: 'secure', + secureDnsServers: [ + 'https://cloudflare-dns.com/dns-query' + ] + }) +}) +``` + +This API must be called after the `ready` event is emitted. + +[doh-providers]: https://source.chromium.org/chromium/chromium/src/+/main:net/dns/public/doh_provider_entry.cc;l=31?q=%22DohProviderEntry::GetList()%22&ss=chromium%2Fchromium%2Fsrc +[RFC8484 § 3]: https://datatracker.ietf.org/doc/html/rfc8484#section-3 ### `app.disableHardwareAcceleration()` @@ -1115,10 +1239,17 @@ Disables hardware acceleration for current app. This method can only be called before app is ready. +### `app.isHardwareAccelerationEnabled()` + +Returns `boolean` - whether hardware acceleration is currently enabled. + + > [!NOTE] + > This information is only usable after the `gpu-info-update` event is emitted. + ### `app.disableDomainBlockingFor3DAPIs()` By default, Chromium disables 3D APIs (e.g. WebGL) until restart on a per -domain basis if the GPU processes crashes too frequently. This function +domain basis if the GPU process crashes too frequently. This function disables that behavior. This method can only be called before app is ready. @@ -1131,11 +1262,12 @@ Returns [`ProcessMetric[]`](structures/process-metric.md): Array of `ProcessMetr Returns [`GPUFeatureStatus`](structures/gpu-feature-status.md) - The Graphics Feature Status from `chrome://gpu/`. -**Note:** This information is only usable after the `gpu-info-update` event is emitted. +> [!NOTE] +> This information is only usable after the `gpu-info-update` event is emitted. ### `app.getGPUInfo(infoType)` -* `infoType` String - Can be `basic` or `complete`. +* `infoType` string - Can be `basic` or `complete`. Returns `Promise` @@ -1145,6 +1277,8 @@ For `infoType` equal to `complete`: For `infoType` equal to `basic`: Promise is fulfilled with `Object` containing fewer attributes than when requested with `complete`. Here's an example of basic response: + + ```js { auxAttributes: @@ -1172,21 +1306,28 @@ For `infoType` equal to `basic`: } ``` -Using `basic` should be preferred if only basic information like `vendorId` or `driverId` is needed. +Using `basic` should be preferred if only basic information like `vendorId` or `deviceId` is needed. + +Promise is rejected if the GPU is completely disabled, i.e. no hardware and software implementations are available. -### `app.setBadgeCount(count)` _Linux_ _macOS_ +### `app.setBadgeCount([count])` _Linux_ _macOS_ -* `count` Integer +* `count` Integer (optional) - If a value is provided, set the badge to the provided value otherwise, on macOS, display a plain white dot (e.g. unknown number of notifications). On Linux, if a value is not provided the badge will not display. -Returns `Boolean` - Whether the call succeeded. +Returns `boolean` - Whether the call succeeded. Sets the counter badge for current app. Setting the count to `0` will hide the badge. On macOS, it shows on the dock icon. On Linux, it only works for Unity launcher. -**Note:** Unity launcher requires the existence of a `.desktop` file to work, -for more information please read [Desktop Environment Integration][unity-requirement]. +> [!NOTE] +> Unity launcher requires a `.desktop` file to work. For more information, +> please read the [Unity integration documentation][unity-requirement]. + +> [!NOTE] +> On macOS, you need to ensure that your application has the permission +> to display notifications for this method to work. ### `app.getBadgeCount()` _Linux_ _macOS_ @@ -1194,82 +1335,87 @@ Returns `Integer` - The current value displayed in the counter badge. ### `app.isUnityRunning()` _Linux_ -Returns `Boolean` - Whether the current desktop environment is Unity launcher. +Returns `boolean` - Whether the current desktop environment is Unity launcher. ### `app.getLoginItemSettings([options])` _macOS_ _Windows_ * `options` Object (optional) - * `path` String (optional) _Windows_ - The executable path to compare against. - Defaults to `process.execPath`. - * `args` String[] (optional) _Windows_ - The command-line arguments to compare - against. Defaults to an empty array. + * `type` string (optional) _macOS_ - Can be `mainAppService`, `agentService`, `daemonService`, or `loginItemService`. Defaults to `mainAppService`. Only available on macOS 13 and up. See [app.setLoginItemSettings](app.md#appsetloginitemsettingssettings-macos-windows) for more information about each type. + * `serviceName` string (optional) _macOS_ - The name of the service. Required if `type` is non-default. Only available on macOS 13 and up. + * `path` string (optional) _Windows_ - The executable path to compare against. Defaults to `process.execPath`. + * `args` string[] (optional) _Windows_ - The command-line arguments to compare against. Defaults to an empty array. If you provided `path` and `args` options to `app.setLoginItemSettings`, then you need to pass the same arguments here for `openAtLogin` to be set correctly. Returns `Object`: -* `openAtLogin` Boolean - `true` if the app is set to open at login. -* `openAsHidden` Boolean _macOS_ - `true` if the app is set to open as hidden at login. - This setting is not available on [MAS builds][mas-builds]. -* `wasOpenedAtLogin` Boolean _macOS_ - `true` if the app was opened at login - automatically. This setting is not available on [MAS builds][mas-builds]. -* `wasOpenedAsHidden` Boolean _macOS_ - `true` if the app was opened as a hidden login - item. This indicates that the app should not open any windows at startup. - This setting is not available on [MAS builds][mas-builds]. -* `restoreState` Boolean _macOS_ - `true` if the app was opened as a login item that - should restore the state from the previous session. This indicates that the - app should restore the windows that were open the last time the app was - closed. This setting is not available on [MAS builds][mas-builds]. -* `executableWillLaunchAtLogin` Boolean _Windows_ - `true` if app is set to open at login and its run key is not deactivated. This differs from `openAtLogin` as it ignores the `args` option, this property will be true if the given executable would be launched at login with **any** arguments. +* `openAtLogin` boolean - `true` if the app is set to open at login. +* `openAsHidden` boolean _macOS_ _Deprecated_ - `true` if the app is set to open as hidden at login. This does not work on macOS 13 and up. +* `wasOpenedAtLogin` boolean _macOS_ - `true` if the app was opened at login automatically. +* `wasOpenedAsHidden` boolean _macOS_ _Deprecated_ - `true` if the app was opened as a hidden login item. This indicates that the app should not open any windows at startup. This setting is not available on [MAS builds][mas-builds] or on macOS 13 and up. +* `restoreState` boolean _macOS_ _Deprecated_ - `true` if the app was opened as a login item that should restore the state from the previous session. This indicates that the app should restore the windows that were open the last time the app was closed. This setting is not available on [MAS builds][mas-builds] or on macOS 13 and up. +* `status` string _macOS_ - can be `not-registered`, `enabled`, `requires-approval`, or `not-found`. +* `executableWillLaunchAtLogin` boolean _Windows_ - `true` if app is set to open at login and its run key is not deactivated. This differs from `openAtLogin` as it ignores the `args` option, this property will be true if the given executable would be launched at login with **any** arguments. * `launchItems` Object[] _Windows_ - * `name` String _Windows_ - name value of a registry entry. - * `path` String _Windows_ - The executable to an app that corresponds to a registry entry. - * `args` String[] _Windows_ - the command-line arguments to pass to the executable. - * `scope` String _Windows_ - one of `user` or `machine`. Indicates whether the registry entry is under `HKEY_CURRENT USER` or `HKEY_LOCAL_MACHINE`. - * `enabled` Boolean _Windows_ - `true` if the app registry key is startup approved and therefore shows as `enabled` in Task Manager and Windows settings. + * `name` string _Windows_ - name value of a registry entry. + * `path` string _Windows_ - The executable to an app that corresponds to a registry entry. + * `args` string[] _Windows_ - the command-line arguments to pass to the executable. + * `scope` string _Windows_ - can be `user` or `machine`. Indicates whether the registry entry is under `HKEY_CURRENT USER` or `HKEY_LOCAL_MACHINE`. + * `enabled` boolean _Windows_ - `true` if the app registry key is startup approved and therefore shows as `enabled` in Task Manager and Windows settings. ### `app.setLoginItemSettings(settings)` _macOS_ _Windows_ * `settings` Object - * `openAtLogin` Boolean (optional) - `true` to open the app at login, `false` to remove + * `openAtLogin` boolean (optional) - `true` to open the app at login, `false` to remove the app as a login item. Defaults to `false`. - * `openAsHidden` Boolean (optional) _macOS_ - `true` to open the app as hidden. Defaults to - `false`. The user can edit this setting from the System Preferences so - `app.getLoginItemSettings().wasOpenedAsHidden` should be checked when the app - is opened to know the current value. This setting is not available on [MAS builds][mas-builds]. - * `path` String (optional) _Windows_ - The executable to launch at login. + * `openAsHidden` boolean (optional) _macOS_ _Deprecated_ - `true` to open the app as hidden. Defaults to `false`. The user can edit this setting from the System Preferences so `app.getLoginItemSettings().wasOpenedAsHidden` should be checked when the app is opened to know the current value. This setting is not available on [MAS builds][mas-builds] or on macOS 13 and up. + * `type` string (optional) _macOS_ - The type of service to add as a login item. Defaults to `mainAppService`. Only available on macOS 13 and up. + * `mainAppService` - The primary application. + * `agentService` - The property list name for a launch agent. The property list name must correspond to a property list in the app’s `Contents/Library/LaunchAgents` directory. + * `daemonService` string (optional) _macOS_ - The property list name for a launch agent. The property list name must correspond to a property list in the app’s `Contents/Library/LaunchDaemons` directory. + * `loginItemService` string (optional) _macOS_ - The property list name for a login item service. The property list name must correspond to a property list in the app’s `Contents/Library/LoginItems` directory. + * `serviceName` string (optional) _macOS_ - The name of the service. Required if `type` is non-default. Only available on macOS 13 and up. + * `path` string (optional) _Windows_ - The executable to launch at login. Defaults to `process.execPath`. - * `args` String[] (optional) _Windows_ - The command-line arguments to pass to + * `args` string[] (optional) _Windows_ - The command-line arguments to pass to the executable. Defaults to an empty array. Take care to wrap paths in quotes. - * `enabled` Boolean (optional) _Windows_ - `true` will change the startup approved registry key and `enable / disable` the App in Task Manager and Windows Settings. + * `enabled` boolean (optional) _Windows_ - `true` will change the startup approved registry key and `enable / disable` the App in Task Manager and Windows Settings. Defaults to `true`. - * `name` String (optional) _Windows_ - value name to write into registry. Defaults to the app's AppUserModelId(). + * `name` string (optional) _Windows_ - value name to write into registry. Defaults to the app's AppUserModelId(). + Set the app's login item settings. To work with Electron's `autoUpdater` on Windows, which uses [Squirrel][Squirrel-Windows], -you'll want to set the launch path to Update.exe, and pass arguments that specify your -application name. For example: +you'll want to set the launch path to your executable's name but a directory up, which is +a stub application automatically generated by Squirrel which will automatically launch the +latest version. + +``` js +const { app } = require('electron') + +const path = require('node:path') -``` javascript const appFolder = path.dirname(process.execPath) -const updateExe = path.resolve(appFolder, '..', 'Update.exe') -const exeName = path.basename(process.execPath) +const ourExeName = path.basename(process.execPath) +const stubLauncher = path.resolve(appFolder, '..', ourExeName) app.setLoginItemSettings({ openAtLogin: true, - path: updateExe, + path: stubLauncher, args: [ - '--processStart', `"${exeName}"`, - '--process-start-args', `"--hidden"` + // You might want to pass a parameter here indicating that this + // app was launched via login, but you don't have to ] }) ``` +For more information about setting different services as login items on macOS 13 and up, see [`SMAppService`](https://developer.apple.com/documentation/servicemanagement/smappservice?language=objc). + ### `app.isAccessibilitySupportEnabled()` _macOS_ _Windows_ -Returns `Boolean` - `true` if Chrome's accessibility support is enabled, +Returns `boolean` - `true` if Chrome's accessibility support is enabled, `false` otherwise. This API will return `true` if the use of assistive technologies, such as screen readers, has been detected. See https://www.chromium.org/developers/design-documents/accessibility for more @@ -1277,30 +1423,99 @@ details. ### `app.setAccessibilitySupportEnabled(enabled)` _macOS_ _Windows_ -* `enabled` Boolean - Enable or disable [accessibility tree](https://developers.google.com/web/fundamentals/accessibility/semantics-builtin/the-accessibility-tree) rendering +* `enabled` boolean - Enable or disable [accessibility tree](https://developers.google.com/web/fundamentals/accessibility/semantics-builtin/the-accessibility-tree) rendering Manually enables Chrome's accessibility support, allowing to expose accessibility switch to users in application settings. See [Chromium's accessibility docs](https://www.chromium.org/developers/design-documents/accessibility) for more details. Disabled by default. This API must be called after the `ready` event is emitted. -**Note:** Rendering accessibility tree can significantly affect the performance of your app. It should not be enabled by default. +> [!NOTE] +> Rendering accessibility tree can significantly affect the performance of your app. It should not be enabled by default. Calling this method will enable the following accessibility support features: `nativeAPIs`, `webContents`, `inlineTextBoxes`, and `extendedProperties`. + +### `app.getAccessibilitySupportFeatures()` _macOS_ _Windows_ + +Returns `string[]` - Array of strings naming currently enabled accessibility support components. Possible values: + +* `nativeAPIs` - Native OS accessibility APIs integration enabled. +* `webContents` - Web contents accessibility tree exposure enabled. +* `inlineTextBoxes` - Inline text boxes (character bounding boxes) enabled. +* `extendedProperties` - Extended accessibility properties enabled. +* `screenReader` - Screen reader specific mode enabled. +* `html` - HTML accessibility tree construction enabled. +* `labelImages` - Accessibility support for automatic image annotations. +* `pdfPrinting` - Accessibility support for PDF printing enabled. + +Notes: + +* The array may be empty if no accessibility modes are active. +* Use `app.isAccessibilitySupportEnabled()` for the legacy boolean check; + prefer this method for granular diagnostics or telemetry. + +Example: + +```js +const { app } = require('electron') + +app.whenReady().then(() => { + if (app.getAccessibilitySupportFeatures().includes('screenReader')) { + // Change some app UI to better work with Screen Readers. + } +}) +``` + +### `app.setAccessibilitySupportFeatures(features)` _macOS_ _Windows_ + +* `features` string[] - An array of the accessibility features to enable. + +Possible values are: + +* `nativeAPIs` - Native OS accessibility APIs integration enabled. +* `webContents` - Web contents accessibility tree exposure enabled. +* `inlineTextBoxes` - Inline text boxes (character bounding boxes) enabled. +* `extendedProperties` - Extended accessibility properties enabled. +* `screenReader` - Screen reader specific mode enabled. +* `html` - HTML accessibility tree construction enabled. +* `labelImages` - Accessibility support for automatic image annotations. +* `pdfPrinting` - Accessibility support for PDF printing enabled. + +To disable all supported features, pass an empty array `[]`. + +Example: + +```js +const { app } = require('electron') + +app.whenReady().then(() => { + // Enable a subset of features: + app.setAccessibilitySupportFeatures([ + 'screenReader', + 'pdfPrinting', + 'webContents' + ]) + + // Other logic + + // Some time later, disable all features: + app.setAccessibilitySupportFeatures([]) +}) +``` ### `app.showAboutPanel()` -Show the app's about panel options. These options can be overridden with `app.setAboutPanelOptions(options)`. +Show the app's about panel options. These options can be overridden with `app.setAboutPanelOptions(options)`. This function runs asynchronously. ### `app.setAboutPanelOptions(options)` * `options` Object - * `applicationName` String (optional) - The app's name. - * `applicationVersion` String (optional) - The app's version. - * `copyright` String (optional) - Copyright information. - * `version` String (optional) _macOS_ - The app's build version number. - * `credits` String (optional) _macOS_ _Windows_ - Credit information. - * `authors` String[] (optional) _Linux_ - List of app authors. - * `website` String (optional) _Linux_ - The app's website. - * `iconPath` String (optional) _Linux_ _Windows_ - Path to the app's icon in a JPEG or PNG file format. On Linux, will be shown as 64x64 pixels while retaining aspect ratio. + * `applicationName` string (optional) - The app's name. + * `applicationVersion` string (optional) - The app's version. + * `copyright` string (optional) - Copyright information. + * `version` string (optional) _macOS_ - The app's build version number. + * `credits` string (optional) _macOS_ _Windows_ - Credit information. + * `authors` string[] (optional) _Linux_ - List of app authors. + * `website` string (optional) _Linux_ - The app's website. + * `iconPath` string (optional) _Linux_ _Windows_ - Path to the app's icon in a JPEG or PNG file format. On Linux, will be shown as 64x64 pixels while retaining aspect ratio. On Windows, a 48x48 PNG will result in the best visual quality. Set the about panel options. This will override the values defined in the app's `.plist` file on macOS. See the [Apple docs][about-panel-options] for more details. On Linux, values must be set in order to be shown; there are no defaults. @@ -1308,7 +1523,7 @@ If you do not set `credits` but still wish to surface them in your app, AppKit w ### `app.isEmojiPanelSupported()` -Returns `Boolean` - whether or not the current OS version allows for native emoji pickers. +Returns `boolean` - whether or not the current OS version allows for native emoji pickers. ### `app.showEmojiPanel()` _macOS_ _Windows_ @@ -1316,16 +1531,28 @@ Show the platform's native emoji picker. ### `app.startAccessingSecurityScopedResource(bookmarkData)` _mas_ -* `bookmarkData` String - The base64 encoded security scoped bookmark data returned by the `dialog.showOpenDialog` or `dialog.showSaveDialog` methods. +* `bookmarkData` string - The base64 encoded security scoped bookmark data returned by the `dialog.showOpenDialog` or `dialog.showSaveDialog` methods. Returns `Function` - This function **must** be called once you have finished accessing the security scoped file. If you do not remember to stop accessing the bookmark, [kernel resources will be leaked](https://developer.apple.com/reference/foundation/nsurl/1417051-startaccessingsecurityscopedreso?language=objc) and your app will lose its ability to reach outside the sandbox completely, until your app is restarted. ```js -// Start accessing the file. -const stopAccessingSecurityScopedResource = app.startAccessingSecurityScopedResource(data) -// You can now access the file outside of the sandbox 🎉 +const { app, dialog } = require('electron') -// Remember to stop accessing the file once you've finished with it. +const fs = require('node:fs') + +let filepath +let bookmark + +dialog.showOpenDialog(null, { securityScopedBookmarks: true }).then(({ filePaths, bookmarks }) => { + filepath = filePaths[0] + bookmark = bookmarks[0] + fs.readFileSync(filepath) +}) + +// ... restart app ... + +const stopAccessingSecurityScopedResource = app.startAccessingSecurityScopedResource(bookmark) +fs.readFileSync(filepath) stopAccessingSecurityScopedResource() ``` @@ -1333,22 +1560,22 @@ Start accessing a security scoped resource. With this method Electron applicatio ### `app.enableSandbox()` -Enables full sandbox mode on the app. This means that all renderers will be launched sandboxed, regardless of the value of the `sandbox` flag in WebPreferences. +Enables full sandbox mode on the app. This means that all renderers will be launched sandboxed, regardless of the value of the `sandbox` flag in [`WebPreferences`](structures/web-preferences.md). This method can only be called before app is ready. ### `app.isInApplicationsFolder()` _macOS_ -Returns `Boolean` - Whether the application is currently running from the +Returns `boolean` - Whether the application is currently running from the systems Application folder. Use in combination with `app.moveToApplicationsFolder()` ### `app.moveToApplicationsFolder([options])` _macOS_ * `options` Object (optional) - * `conflictHandler` Function\ (optional) - A handler for potential conflict in move failure. - * `conflictType` String - The type of move conflict encountered by the handler; can be `exists` or `existsAndRunning`, where `exists` means that an app of the same name is present in the Applications directory and `existsAndRunning` means both that it exists and that it's presently running. + * `conflictHandler` Function\ (optional) - A handler for potential conflict in move failure. + * `conflictType` string - The type of move conflict encountered by the handler; can be `exists` or `existsAndRunning`, where `exists` means that an app of the same name is present in the Applications directory and `existsAndRunning` means both that it exists and that it's presently running. -Returns `Boolean` - Whether the move was successful. Please note that if +Returns `boolean` - Whether the move was successful. Please note that if the move is successful, your application will quit and relaunch. No confirmation dialog will be presented by default. If you wish to allow @@ -1361,11 +1588,13 @@ method returns false. If we fail to perform the copy, then this method will throw an error. The message in the error should be informative and tell you exactly what went wrong. -By default, if an app of the same name as the one being moved exists in the Applications directory and is _not_ running, the existing app will be trashed and the active app moved into its place. If it _is_ running, the pre-existing running app will assume focus and the previously active app will quit itself. This behavior can be changed by providing the optional conflict handler, where the boolean returned by the handler determines whether or not the move conflict is resolved with default behavior. i.e. returning `false` will ensure no further action is taken, returning `true` will result in the default behavior and the method continuing. +By default, if an app of the same name as the one being moved exists in the Applications directory and is _not_ running, the existing app will be trashed and the active app moved into its place. If it _is_ running, the preexisting running app will assume focus and the previously active app will quit itself. This behavior can be changed by providing the optional conflict handler, where the boolean returned by the handler determines whether or not the move conflict is resolved with default behavior. i.e. returning `false` will ensure no further action is taken, returning `true` will result in the default behavior and the method continuing. For example: ```js +const { app, dialog } = require('electron') + app.moveToApplicationsFolder({ conflictHandler: (conflictType) => { if (conflictType === 'exists') { @@ -1384,13 +1613,13 @@ Would mean that if an app already exists in the user directory, if the user choo ### `app.isSecureKeyboardEntryEnabled()` _macOS_ -Returns `Boolean` - whether `Secure Keyboard Entry` is enabled. +Returns `boolean` - whether `Secure Keyboard Entry` is enabled. By default this API will return `false`. ### `app.setSecureKeyboardEntryEnabled(enabled)` _macOS_ -* `enabled` Boolean - Enable or disable `Secure Keyboard Entry` +* `enabled` boolean - Enable or disable `Secure Keyboard Entry` Set the `Secure Keyboard Entry` is enabled in your application. @@ -1399,19 +1628,71 @@ By using this API, important information such as password and other sensitive in See [Apple's documentation](https://developer.apple.com/library/archive/technotes/tn2150/_index.html) for more details. -**Note:** Enable `Secure Keyboard Entry` only when it is needed and disable it when it is no longer needed. +> [!NOTE] +> Enable `Secure Keyboard Entry` only when it is needed and disable it when it is no longer needed. + +### `app.setProxy(config)` + +* `config` [ProxyConfig](structures/proxy-config.md) + +Returns `Promise` - Resolves when the proxy setting process is complete. + +Sets the proxy settings for networks requests made without an associated [Session](session.md). +Currently this will affect requests made with [Net](net.md) in the [utility process](../glossary.md#utility-process) +and internal requests made by the runtime (ex: geolocation queries). + +This method can only be called after app is ready. + +### `app.resolveProxy(url)` + +* `url` URL + +Returns `Promise` - Resolves with the proxy information for `url` that will be used when attempting to make requests using [Net](net.md) in the [utility process](../glossary.md#utility-process). + +### `app.setClientCertRequestPasswordHandler(handler)` _Linux_ + +* `handler` Function\\> + * `clientCertRequestParams` Object + * `hostname` string - the hostname of the site requiring a client certificate + * `tokenName` string - the token (or slot) name of the cryptographic device + * `isRetry` boolean - whether there have been previous failed attempts at prompting the password + + Returns `Promise` - Resolves with the password + +The handler is called when a password is needed to unlock a client certificate for +`hostname`. + +```js +const { app } = require('electron') + +async function passwordPromptUI (text) { + return new Promise((resolve, reject) => { + // display UI to prompt user for password + // ... + // ... + resolve('the password') + }) +} + +app.setClientCertRequestPasswordHandler(async ({ hostname, tokenName, isRetry }) => { + const text = `Please sign in to ${tokenName} to authenticate to ${hostname} with your certificate` + const password = await passwordPromptUI(text) + return password +}) +``` ## Properties ### `app.accessibilitySupportEnabled` _macOS_ _Windows_ -A `Boolean` property that's `true` if Chrome's accessibility support is enabled, `false` otherwise. This property will be `true` if the use of assistive technologies, such as screen readers, has been detected. Setting this property to `true` manually enables Chrome's accessibility support, allowing developers to expose accessibility switch to users in application settings. +A `boolean` property that's `true` if Chrome's accessibility support is enabled, `false` otherwise. This property will be `true` if the use of assistive technologies, such as screen readers, has been detected. Setting this property to `true` manually enables Chrome's accessibility support, allowing developers to expose accessibility switch to users in application settings. See [Chromium's accessibility docs](https://www.chromium.org/developers/design-documents/accessibility) for more details. Disabled by default. This API must be called after the `ready` event is emitted. -**Note:** Rendering accessibility tree can significantly affect the performance of your app. It should not be enabled by default. +> [!NOTE] +> Rendering accessibility tree can significantly affect the performance of your app. It should not be enabled by default. ### `app.applicationMenu` @@ -1424,11 +1705,13 @@ An `Integer` property that returns the badge count for current app. Setting the On macOS, setting this with any nonzero integer shows on the dock icon. On Linux, this property only works for Unity launcher. -**Note:** Unity launcher requires the existence of a `.desktop` file to work, -for more information please read [Desktop Environment Integration][unity-requirement]. +> [!NOTE] +> Unity launcher requires a `.desktop` file to work. For more information, +> please read the [Unity integration documentation][unity-requirement]. -**Note:** On macOS, you need to ensure that your application has the permission -to display notifications for this property to take effect. +> [!NOTE] +> On macOS, you need to ensure that your application has the permission +> to display notifications for this property to take effect. ### `app.commandLine` _Readonly_ @@ -1437,31 +1720,36 @@ command line arguments that Chromium uses. ### `app.dock` _macOS_ _Readonly_ -A [`Dock`](./dock.md) `| undefined` object that allows you to perform actions on your app icon in the user's -dock on macOS. +A `Dock | undefined` property ([`Dock`](./dock.md) on macOS, `undefined` on all other +platforms) that allows you to perform actions on your app icon in the user's dock. ### `app.isPackaged` _Readonly_ -A `Boolean` property that returns `true` if the app is packaged, `false` otherwise. For many apps, this property can be used to distinguish development and production environments. +A `boolean` property that returns `true` if the app is packaged, `false` otherwise. For many apps, this property can be used to distinguish development and production environments. + +### `app.toastActivatorCLSID` _Windows_ _Readonly_ + +A `string` property that returns the app's [Toast Activator CLSID][toast-activator-clsid]. -[dock-menu]:https://developer.apple.com/macos/human-interface-guidelines/menus/dock-menus/ -[tasks]:https://msdn.microsoft.com/en-us/library/windows/desktop/dd378460(v=vs.85).aspx#tasks -[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx +[tasks]:https://learn.microsoft.com/en-us/windows/win32/shell/taskbar-extensions#tasks +[app-user-model-id]: https://learn.microsoft.com/en-us/windows/win32/shell/appids +[toast-activator-clsid]: https://learn.microsoft.com/en-us/windows/win32/properties/props-system-appusermodel-toastactivatorclsid [electron-forge]: https://www.electronforge.io/ -[electron-packager]: https://github.com/electron/electron-packager +[electron-packager]: https://github.com/electron/packager [CFBundleURLTypes]: https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html#//apple_ref/doc/uid/TP40009249-102207-TPXREF115 -[LSCopyDefaultHandlerForURLScheme]: https://developer.apple.com/library/mac/documentation/Carbon/Reference/LaunchServicesReference/#//apple_ref/c/func/LSCopyDefaultHandlerForURLScheme +[LSCopyDefaultHandlerForURLScheme]: https://developer.apple.com/documentation/coreservices/1441725-lscopydefaulthandlerforurlscheme?language=objc [handoff]: https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/Handoff/HandoffFundamentals/HandoffFundamentals.html [activity-type]: https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSUserActivity_Class/index.html#//apple_ref/occ/instp/NSUserActivity/activityType -[unity-requirement]: ../tutorial/desktop-environment-integration.md#unity-launcher +[unity-requirement]: https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles#Adding_shortcuts_to_a_launcher [mas-builds]: ../tutorial/mac-app-store-submission-guide.md [Squirrel-Windows]: https://github.com/Squirrel/Squirrel.Windows -[JumpListBeginListMSDN]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378398(v=vs.85).aspx +[JumpListBeginListMSDN]: https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-icustomdestinationlist-beginlist [about-panel-options]: https://developer.apple.com/reference/appkit/nsapplication/1428479-orderfrontstandardaboutpanelwith?language=objc +[happy-eyeballs-v3]: https://datatracker.ietf.org/doc/draft-pauly-happy-happyeyeballs-v3/ ### `app.name` -A `String` property that indicates the current application's name, which is the name in the application's `package.json` file. +A `string` property that indicates the current application's name, which is the name in the application's `package.json` file. Usually the `name` field of `package.json` is a short lowercase name, according to the npm modules spec. You should usually also specify a `productName` @@ -1470,31 +1758,19 @@ preferred over `name` by Electron. ### `app.userAgentFallback` -A `String` which is the user agent string Electron will use as a global fallback. +A `string` which is the user agent string Electron will use as a global fallback. This is the user agent that will be used when no user agent is set at the `webContents` or `session` level. It is useful for ensuring that your entire app has the same user agent. Set to a custom value as early as possible in your app's initialization to ensure that your overridden value is used. -### `app.allowRendererProcessReuse` - -A `Boolean` which when `true` disables the overrides that Electron has in place -to ensure renderer processes are restarted on every navigation. The current -default value for this property is `true`. - -The intention is for these overrides to become disabled by default and then at -some point in the future this property will be removed. This property impacts -which native modules you can use in the renderer process. For more information -on the direction Electron is going with renderer process restarts and usage of -native modules in the renderer process please check out this -[Tracking Issue](https://github.com/electron/electron/issues/18397). - -### `app.runningUnderRosettaTranslation` _macOS_ _Readonly_ +### `app.runningUnderARM64Translation` _Readonly_ _macOS_ _Windows_ -A `Boolean` which when `true` indicates that the app is currently running -under the [Rosetta Translator Environment](https://en.wikipedia.org/wiki/Rosetta_(software)). +A `boolean` which when `true` indicates that the app is currently running under +an ARM64 translator (like the macOS +[Rosetta Translator Environment](https://en.wikipedia.org/wiki/Rosetta_(software)) +or Windows [WOW](https://en.wikipedia.org/wiki/Windows_on_Windows)). You can use this property to prompt users to download the arm64 version of -your application when they are running the x64 version under Rosetta -incorrectly. +your application when they are mistakenly running the x64 version under Rosetta or WOW. diff --git a/docs/api/auto-updater.md b/docs/api/auto-updater.md index 77d3e4c4d514f..5472904f106cf 100644 --- a/docs/api/auto-updater.md +++ b/docs/api/auto-updater.md @@ -20,32 +20,58 @@ In addition, there are some subtle differences on each platform: On macOS, the `autoUpdater` module is built upon [Squirrel.Mac][squirrel-mac], meaning you don't need any special setup to make it work. For server-side -requirements, you can read [Server Support][server-support]. Note that [App -Transport Security](https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW35) (ATS) applies to all requests made as part of the +requirements, you can read [Server Support][server-support]. Note that +[App Transport Security](https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW35) +(ATS) applies to all requests made as part of the update process. Apps that need to disable ATS can add the `NSAllowsArbitraryLoads` key to their app's plist. -**Note:** Your application must be signed for automatic updates on macOS. -This is a requirement of `Squirrel.Mac`. +> [!IMPORTANT] +> Your application must be signed for automatic updates on macOS. +> This is a requirement of `Squirrel.Mac`. ### Windows -On Windows, you have to install your app into a user's machine before you can -use the `autoUpdater`, so it is recommended that you use the -[electron-winstaller][installer-lib], [electron-forge][electron-forge-lib] or the [grunt-electron-installer][installer] package to generate a Windows installer. +On Windows, the `autoUpdater` module automatically selects the appropriate update mechanism +based on how your app is packaged: -When using [electron-winstaller][installer-lib] or [electron-forge][electron-forge-lib] make sure you do not try to update your app [the first time it runs](https://github.com/electron/windows-installer#handling-squirrel-events) (Also see [this issue for more info](https://github.com/electron/electron/issues/7155)). It's also recommended to use [electron-squirrel-startup](https://github.com/mongodb-js/electron-squirrel-startup) to get desktop shortcuts for your app. +* **MSIX packages**: If your app is running as an MSIX package (created with [electron-windows-msix][msix-lib] and detected via [`process.windowsStore`](process.md#processwindowsstore-readonly)), + the module uses the MSIX updater, which supports direct MSIX file links and JSON update feeds. +* **Squirrel.Windows**: For apps installed via traditional installers (created with + [electron-winstaller][installer-lib] or [Electron Forge's Squirrel.Windows maker][electron-forge-lib]), + the module uses Squirrel.Windows for updates. -The installer generated with Squirrel will create a shortcut icon with an +You don't need to configure which updater to use; Electron automatically detects the packaging +format and uses the appropriate one. + +#### Squirrel.Windows + +Apps built with Squirrel.Windows will trigger [custom launch events](https://github.com/Squirrel/Squirrel.Windows/blob/51f5e2cb01add79280a53d51e8d0cfa20f8c9f9f/docs/using/custom-squirrel-events-non-cs.md#application-startup-commands) +that must be handled by your Electron application to ensure proper setup and teardown. + +Squirrel.Windows apps will launch with the `--squirrel-firstrun` argument immediately +after installation. During this time, Squirrel.Windows will obtain a file lock on +your app, and `autoUpdater` requests will fail until the lock is released. In practice, +this means that you won't be able to check for updates on first launch for the first +few seconds. You can work around this by not checking for updates when `process.argv` +contains the `--squirrel-firstrun` flag or by setting a 10-second timeout on your +update checks (see [electron/electron#7155](https://github.com/electron/electron/issues/7155) +for more information). + +The installer generated with Squirrel.Windows will create a shortcut icon with an [Application User Model ID][app-user-model-id] in the format of `com.squirrel.PACKAGE_ID.YOUR_EXE_WITHOUT_DOT_EXE`, examples are `com.squirrel.slack.Slack` and `com.squirrel.code.Code`. You have to use the same ID for your app with `app.setAppUserModelId` API, otherwise Windows will not be able to pin your app properly in task bar. -Unlike Squirrel.Mac, Windows can host updates on S3 or any other static file host. -You can read the documents of [Squirrel.Windows][squirrel-windows] to get more details -about how Squirrel.Windows works. +#### MSIX Packages + +When your app is packaged as an MSIX, the `autoUpdater` module provides additional +functionality: + +* Use the `allowAnyVersion` option in `setFeedURL()` to allow updates to older versions (downgrades) +* Support for direct MSIX file links or JSON update feeds (similar to Squirrel.Mac format) ## Events @@ -61,7 +87,7 @@ Emitted when there is an error while updating. ### Event: 'checking-for-update' -Emitted when checking if an update has started. +Emitted when checking for an available update has started. ### Event: 'update-available' @@ -77,20 +103,28 @@ Emitted when there is no available update. Returns: * `event` Event -* `releaseNotes` String -* `releaseName` String +* `releaseNotes` string +* `releaseName` string * `releaseDate` Date -* `updateURL` String +* `updateURL` string Emitted when an update has been downloaded. -On Windows only `releaseName` is available. +With Squirrel.Windows only `releaseName` is available. -**Note:** It is not strictly necessary to handle this event. A successfully -downloaded update will still be applied the next time the application starts. +> [!NOTE] +> It is not strictly necessary to handle this event. A successfully +> downloaded update will still be applied the next time the application starts. ### Event: 'before-quit-for-update' + + This event is emitted after a user calls `quitAndInstall()`. When this API is called, the `before-quit` event is not emitted before all windows are closed. As a result you should listen to this event if you wish to perform actions before the windows are closed while a process is quitting, as well as listening to `before-quit`. @@ -101,23 +135,39 @@ The `autoUpdater` object has the following methods: ### `autoUpdater.setFeedURL(options)` + + * `options` Object - * `url` String - * `headers` Record (optional) _macOS_ - HTTP request headers. - * `serverType` String (optional) _macOS_ - Can be `json` or `default`, see the [Squirrel.Mac][squirrel-mac] + * `url` string - The update server URL. For _Windows_ MSIX, this can be either a direct link to an MSIX file (e.g., `https://example.com/update.msix`) or a JSON endpoint that returns update information (see the [Squirrel.Mac][squirrel-mac] README for more information). + * `headers` Record\ (optional) _macOS_ - HTTP request headers. + * `serverType` string (optional) _macOS_ - Can be `json` or `default`, see the [Squirrel.Mac][squirrel-mac] README for more information. + * `allowAnyVersion` boolean (optional) _Windows_ - If `true`, allows downgrades to older versions for MSIX packages. + Defaults to `false`. Sets the `url` and initialize the auto updater. ### `autoUpdater.getFeedURL()` -Returns `String` - The current update feed URL. +Returns `string` - The current update feed URL. ### `autoUpdater.checkForUpdates()` Asks the server whether there is an update. You must call `setFeedURL` before using this API. +> [!NOTE] +> If an update is available it will be downloaded automatically. +> Calling `autoUpdater.checkForUpdates()` twice will download the update two times. + ### `autoUpdater.quitAndInstall()` Restarts the app and installs the update after it has been downloaded. It @@ -127,15 +177,15 @@ Under the hood calling `autoUpdater.quitAndInstall()` will close all application windows first, and automatically call `app.quit()` after all windows have been closed. -**Note:** It is not strictly necessary to call this function to apply an update, -as a successfully downloaded update will always be applied the next time the -application starts. +> [!NOTE] +> It is not strictly necessary to call this function to apply an update, +> as a successfully downloaded update will always be applied the next time the +> application starts. [squirrel-mac]: https://github.com/Squirrel/Squirrel.Mac [server-support]: https://github.com/Squirrel/Squirrel.Mac#server-support -[squirrel-windows]: https://github.com/Squirrel/Squirrel.Windows -[installer]: https://github.com/electron/grunt-electron-installer [installer-lib]: https://github.com/electron/windows-installer -[electron-forge-lib]: https://github.com/electron-userland/electron-forge -[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx +[electron-forge-lib]: https://www.electronforge.io/config/makers/squirrel.windows +[app-user-model-id]: https://learn.microsoft.com/en-us/windows/win32/shell/appids [event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter +[msix-lib]: https://github.com/electron-userland/electron-windows-msix diff --git a/docs/api/base-window.md b/docs/api/base-window.md new file mode 100644 index 0000000000000..4ab9afb72bab9 --- /dev/null +++ b/docs/api/base-window.md @@ -0,0 +1,1543 @@ +# BaseWindow + +> Create and control windows. + +Process: [Main](../glossary.md#main-process) + +> [!NOTE] +> `BaseWindow` provides a flexible way to compose multiple web views in a +> single window. For windows with only a single, full-size web view, the +> [`BrowserWindow`](browser-window.md) class may be a simpler option. + +This module cannot be used until the `ready` event of the `app` +module is emitted. + +```js +// In the main process. +const { BaseWindow, WebContentsView } = require('electron') + +const win = new BaseWindow({ width: 800, height: 600 }) + +const leftView = new WebContentsView() +leftView.webContents.loadURL('https://electronjs.org') +win.contentView.addChildView(leftView) + +const rightView = new WebContentsView() +rightView.webContents.loadURL('https://github.com/electron/electron') +win.contentView.addChildView(rightView) + +leftView.setBounds({ x: 0, y: 0, width: 400, height: 600 }) +rightView.setBounds({ x: 400, y: 0, width: 400, height: 600 }) +``` + +## Parent and child windows + +By using `parent` option, you can create child windows: + +```js +const { BaseWindow } = require('electron') + +const parent = new BaseWindow() +const child = new BaseWindow({ parent }) +``` + +The `child` window will always show on top of the `parent` window. + +## Modal windows + +A modal window is a child window that disables parent window. To create a modal +window, you have to set both the `parent` and `modal` options: + +```js +const { BaseWindow } = require('electron') + +const parent = new BaseWindow() +const child = new BaseWindow({ parent, modal: true }) +``` + +## Platform notices + +* On macOS modal windows will be displayed as sheets attached to the parent window. +* On macOS the child windows will keep the relative position to parent window + when parent window moves, while on Windows and Linux child windows will not + move. +* On Linux the type of modal windows will be changed to `dialog`. +* On Linux many desktop environments do not support hiding a modal window. + +## Resource management + +When you add a [`WebContentsView`](web-contents-view.md) to a `BaseWindow` and the `BaseWindow` +is closed, the [`webContents`](web-contents.md) of the `WebContentsView` are not destroyed +automatically. + +It is your responsibility to close the `webContents` when you no longer need them, e.g. when +the `BaseWindow` is closed: + +```js +const { BaseWindow, WebContentsView } = require('electron') + +const win = new BaseWindow({ width: 800, height: 600 }) + +const view = new WebContentsView() +win.contentView.addChildView(view) + +win.on('closed', () => { + view.webContents.close() +}) +``` + +Unlike with a [`BrowserWindow`](browser-window.md), if you don't explicitly close the +`webContents`, you'll encounter memory leaks. + +## Class: BaseWindow + +> Create and control windows. + +Process: [Main](../glossary.md#main-process) + +`BaseWindow` is an [EventEmitter][event-emitter]. + +It creates a new `BaseWindow` with native properties as set by the `options`. + +> [!WARNING] +> Electron's built-in classes cannot be subclassed in user code. +> For more information, see [the FAQ](../faq.md#class-inheritance-does-not-work-with-electron-built-in-modules). + +### `new BaseWindow([options])` + +* `options` [BaseWindowConstructorOptions](structures/base-window-options.md?inline) (optional) + +### Instance Events + +Objects created with `new BaseWindow` emit the following events: + +> [!NOTE] +> Some events are only available on specific operating systems and are +> labeled as such. + +#### Event: 'close' + +Returns: + +* `event` Event + +Emitted when the window is going to be closed. It's emitted before the +`beforeunload` and `unload` event of the DOM. Calling `event.preventDefault()` +will cancel the close. + +Usually you would want to use the `beforeunload` handler to decide whether the +window should be closed, which will also be called when the window is +reloaded. In Electron, returning any value other than `undefined` would cancel the +close. For example: + +```js +window.onbeforeunload = (e) => { + console.log('I do not want to be closed') + + // Unlike usual browsers that a message box will be prompted to users, returning + // a non-void value will silently cancel the close. + // It is recommended to use the dialog API to let the user confirm closing the + // application. + e.returnValue = false +} +``` + +> [!NOTE] +> There is a subtle difference between the behaviors of `window.onbeforeunload = handler` and +> `window.addEventListener('beforeunload', handler)`. It is recommended to always set the +> `event.returnValue` explicitly, instead of only returning a value, as the former works more +> consistently within Electron. + +#### Event: 'closed' + +Emitted when the window is closed. After you have received this event you should +remove the reference to the window and avoid using it any more. + +#### Event: 'query-session-end' _Windows_ + +Returns: + +* `event` [WindowSessionEndEvent][window-session-end-event] + +Emitted when a session is about to end due to a shutdown, machine restart, or user log-off. +Calling `event.preventDefault()` can delay the system shutdown, though it’s generally best +to respect the user’s choice to end the session. However, you may choose to use it if +ending the session puts the user at risk of losing data. + +#### Event: 'session-end' _Windows_ + +Returns: + +* `event` [WindowSessionEndEvent][window-session-end-event] + +Emitted when a session is about to end due to a shutdown, machine restart, or user log-off. Once this event fires, there is no way to prevent the session from ending. + +#### Event: 'blur' + +Returns: + +* `event` Event + +Emitted when the window loses focus. + +#### Event: 'focus' + +Returns: + +* `event` Event + +Emitted when the window gains focus. + +#### Event: 'show' + +Emitted when the window is shown. + +#### Event: 'hide' + +Emitted when the window is hidden. + +#### Event: 'maximize' + +Emitted when window is maximized. + +#### Event: 'unmaximize' + +Emitted when the window exits from a maximized state. + +#### Event: 'minimize' + +Emitted when the window is minimized. + +#### Event: 'restore' + +Emitted when the window is restored from a minimized state. + +#### Event: 'will-resize' _macOS_ _Windows_ + +Returns: + +* `event` Event +* `newBounds` [Rectangle](structures/rectangle.md) - Size the window is being resized to. +* `details` Object + * `edge` (string) - The edge of the window being dragged for resizing. Can be `bottom`, `left`, `right`, `top-left`, `top-right`, `bottom-left` or `bottom-right`. + +Emitted before the window is resized. Calling `event.preventDefault()` will prevent the window from being resized. + +Note that this is only emitted when the window is being resized manually. Resizing the window with `setBounds`/`setSize` will not emit this event. + +The possible values and behaviors of the `edge` option are platform dependent. Possible values are: + +* On Windows, possible values are `bottom`, `top`, `left`, `right`, `top-left`, `top-right`, `bottom-left`, `bottom-right`. +* On macOS, possible values are `bottom` and `right`. + * The value `bottom` is used to denote vertical resizing. + * The value `right` is used to denote horizontal resizing. + +#### Event: 'resize' + +Emitted after the window has been resized. + +#### Event: 'resized' _macOS_ _Windows_ + +Emitted once when the window has finished being resized. + +This is usually emitted when the window has been resized manually. On macOS, resizing the window with `setBounds`/`setSize` and setting the `animate` parameter to `true` will also emit this event once resizing has finished. + +#### Event: 'will-move' _macOS_ _Windows_ + +Returns: + +* `event` Event +* `newBounds` [Rectangle](structures/rectangle.md) - Location the window is being moved to. + +Emitted before the window is moved. On Windows, calling `event.preventDefault()` will prevent the window from being moved. + +Note that this is only emitted when the window is being moved manually. Moving the window with `setPosition`/`setBounds`/`center` will not emit this event. + +#### Event: 'move' + +Emitted when the window is being moved to a new position. + +#### Event: 'moved' _macOS_ _Windows_ + +Emitted once when the window is moved to a new position. + +> [!NOTE] +> On macOS, this event is an alias of `move`. + +#### Event: 'enter-full-screen' + +Emitted when the window enters a full-screen state. + +#### Event: 'leave-full-screen' + +Emitted when the window leaves a full-screen state. + +#### Event: 'always-on-top-changed' + +Returns: + +* `event` Event +* `isAlwaysOnTop` boolean + +Emitted when the window is set or unset to show always on top of other windows. + +#### Event: 'app-command' _Windows_ _Linux_ + +Returns: + +* `event` Event +* `command` string + +Emitted when an [App Command](https://learn.microsoft.com/en-us/windows/win32/inputdev/wm-appcommand) +is invoked. These are typically related to keyboard media keys or browser +commands, as well as the "Back" button built into some mice on Windows. + +Commands are lowercased, underscores are replaced with hyphens, and the +`APPCOMMAND_` prefix is stripped off. +e.g. `APPCOMMAND_BROWSER_BACKWARD` is emitted as `browser-backward`. + +```js +const { BaseWindow } = require('electron') + +const win = new BaseWindow() +win.on('app-command', (e, cmd) => { + // Navigate the window back when the user hits their mouse back button + if (cmd === 'browser-backward') { + // Find the appropriate WebContents to navigate. + } +}) +``` + +The following app commands are explicitly supported on Linux: + +* `browser-backward` +* `browser-forward` + +#### Event: 'swipe' _macOS_ + +Returns: + +* `event` Event +* `direction` string + +Emitted on 3-finger swipe. Possible directions are `up`, `right`, `down`, `left`. + +The method underlying this event is built to handle older macOS-style trackpad swiping, +where the content on the screen doesn't move with the swipe. Most macOS trackpads are not +configured to allow this kind of swiping anymore, so in order for it to emit properly the +'Swipe between pages' preference in `System Preferences > Trackpad > More Gestures` must be +set to 'Swipe with two or three fingers'. + +#### Event: 'rotate-gesture' _macOS_ + +Returns: + +* `event` Event +* `rotation` Float + +Emitted on trackpad rotation gesture. Continually emitted until rotation gesture is +ended. The `rotation` value on each emission is the angle in degrees rotated since +the last emission. The last emitted event upon a rotation gesture will always be of +value `0`. Counter-clockwise rotation values are positive, while clockwise ones are +negative. + +#### Event: 'sheet-begin' _macOS_ + +Emitted when the window opens a sheet. + +#### Event: 'sheet-end' _macOS_ + +Emitted when the window has closed a sheet. + +#### Event: 'new-window-for-tab' _macOS_ + +Emitted when the user clicks the native macOS new tab button. The new +tab button is only visible if the current `BrowserWindow` has a +`tabbingIdentifier`. + +You must create a window in this handler in order for macOS tabbing to work as expected. + +#### Event: 'system-context-menu' _Windows_ _Linux_ + +Returns: + +* `event` Event +* `point` [Point](structures/point.md) - The screen coordinates where the context menu was triggered. + +Emitted when the system context menu is triggered on the window, this is +normally only triggered when the user right clicks on the non-client area +of your window. This is the window titlebar or any area you have declared +as `-webkit-app-region: drag` in a frameless window. + +Calling `event.preventDefault()` will prevent the menu from being displayed. + +To convert `point` to DIP, use [`screen.screenToDipPoint(point)`](./screen.md#screenscreentodippointpoint-windows-linux). + +### Static Methods + +The `BaseWindow` class has the following static methods: + +#### `BaseWindow.getAllWindows()` + +Returns `BaseWindow[]` - An array of all opened browser windows. + +#### `BaseWindow.getFocusedWindow()` + +Returns `BaseWindow | null` - The window that is focused in this application, otherwise returns `null`. + +#### `BaseWindow.fromId(id)` + +* `id` Integer + +Returns `BaseWindow | null` - The window with the given `id`. + +### Instance Properties + +Objects created with `new BaseWindow` have the following properties: + +```js +const { BaseWindow } = require('electron') +// In this example `win` is our instance +const win = new BaseWindow({ width: 800, height: 600 }) +``` + +#### `win.id` _Readonly_ + +A `Integer` property representing the unique ID of the window. Each ID is unique among all `BaseWindow` instances of the entire Electron application. + +#### `win.contentView` + +A `View` property for the content view of the window. + +#### `win.tabbingIdentifier` _macOS_ _Readonly_ + +A `string` (optional) property that is equal to the `tabbingIdentifier` passed to the `BrowserWindow` constructor or `undefined` if none was set. + +#### `win.autoHideMenuBar` _Linux_ _Windows_ + +A `boolean` property that determines whether the window menu bar should hide itself automatically. Once set, the menu bar will only show when users press the single `Alt` key. + +If the menu bar is already visible, setting this property to `true` won't +hide it immediately. + +#### `win.simpleFullScreen` + +A `boolean` property that determines whether the window is in simple (pre-Lion) fullscreen mode. + +#### `win.fullScreen` + +A `boolean` property that determines whether the window is in fullscreen mode. + +#### `win.focusable` _Windows_ _macOS_ + +A `boolean` property that determines whether the window is focusable. + +#### `win.visibleOnAllWorkspaces` _macOS_ _Linux_ + +A `boolean` property that determines whether the window is visible on all workspaces. + +> [!NOTE] +> Always returns false on Windows. + +#### `win.shadow` + +A `boolean` property that determines whether the window has a shadow. + +#### `win.menuBarVisible` _Windows_ _Linux_ + +A `boolean` property that determines whether the menu bar should be visible. + +> [!NOTE] +> If the menu bar is auto-hide, users can still bring up the menu bar by pressing the single `Alt` key. + +#### `win.kiosk` + +A `boolean` property that determines whether the window is in kiosk mode. + +#### `win.documentEdited` _macOS_ + +A `boolean` property that specifies whether the window’s document has been edited. + +The icon in title bar will become gray when set to `true`. + +#### `win.representedFilename` _macOS_ + +A `string` property that determines the pathname of the file the window represents, +and the icon of the file will show in window's title bar. + +#### `win.title` + +A `string` property that determines the title of the native window. + +> [!NOTE] +> The title of the web page can be different from the title of the native window. + +#### `win.minimizable` _macOS_ _Windows_ + +A `boolean` property that determines whether the window can be manually minimized by user. + +On Linux the setter is a no-op, although the getter returns `true`. + +#### `win.maximizable` _macOS_ _Windows_ + +A `boolean` property that determines whether the window can be manually maximized by user. + +On Linux the setter is a no-op, although the getter returns `true`. + +#### `win.fullScreenable` + +A `boolean` property that determines whether the maximize/zoom window button toggles fullscreen mode or +maximizes the window. + +#### `win.resizable` + +A `boolean` property that determines whether the window can be manually resized by user. + +#### `win.closable` _macOS_ _Windows_ + +A `boolean` property that determines whether the window can be manually closed by user. + +On Linux the setter is a no-op, although the getter returns `true`. + +#### `win.movable` _macOS_ _Windows_ + +A `boolean` property that determines Whether the window can be moved by user. + +On Linux the setter is a no-op, although the getter returns `true`. + +#### `win.excludedFromShownWindowsMenu` _macOS_ + +A `boolean` property that determines whether the window is excluded from the application’s Windows menu. `false` by default. + +```js @ts-expect-error=[12] +const { Menu, BaseWindow } = require('electron') + +const win = new BaseWindow({ height: 600, width: 600 }) + +const template = [ + { + role: 'windowmenu' + } +] + +win.excludedFromShownWindowsMenu = true + +const menu = Menu.buildFromTemplate(template) +Menu.setApplicationMenu(menu) +``` + +#### `win.accessibleTitle` + +A `string` property that defines an alternative title provided only to +accessibility tools such as screen readers. This string is not directly +visible to users. + +#### `win.snapped` _Windows_ _Readonly_ + +A `boolean` property that indicates whether the window is arranged via [Snap.](https://support.microsoft.com/en-us/windows/snap-your-windows-885a9b1e-a983-a3b1-16cd-c531795e6241) + +### Instance Methods + +Objects created with `new BaseWindow` have the following instance methods: + +> [!NOTE] +> Some methods are only available on specific operating systems and are +> labeled as such. + +#### `win.setContentView(view)` + +* `view` [View](view.md) + +Sets the content view of the window. + +#### `win.getContentView()` + +Returns [`View`](view.md) - The content view of the window. + +#### `win.destroy()` + +Force closing the window, the `unload` and `beforeunload` event won't be emitted +for the web page, and `close` event will also not be emitted +for this window, but it guarantees the `closed` event will be emitted. + +#### `win.close()` + +Try to close the window. This has the same effect as a user manually clicking +the close button of the window. The web page may cancel the close though. See +the [close event](#event-close). + +#### `win.focus()` + +Focuses on the window. + +#### `win.blur()` + +Removes focus from the window. + +#### `win.isFocused()` + +Returns `boolean` - Whether the window is focused. + +#### `win.isDestroyed()` + +Returns `boolean` - Whether the window is destroyed. + +#### `win.show()` + +Shows and gives focus to the window. + +#### `win.showInactive()` + +Shows the window but doesn't focus on it. + +#### `win.hide()` + +Hides the window. + +#### `win.isVisible()` + +Returns `boolean` - Whether the window is visible to the user in the foreground of the app. + +#### `win.isModal()` + +Returns `boolean` - Whether current window is a modal window. + +#### `win.maximize()` + +Maximizes the window. This will also show (but not focus) the window if it +isn't being displayed already. + +#### `win.unmaximize()` + +Unmaximizes the window. + +#### `win.isMaximized()` + +Returns `boolean` - Whether the window is maximized. + +#### `win.minimize()` + +Minimizes the window. On some platforms the minimized window will be shown in +the Dock. + +#### `win.restore()` + +Restores the window from minimized state to its previous state. + +#### `win.isMinimized()` + +Returns `boolean` - Whether the window is minimized. + +#### `win.setFullScreen(flag)` + +* `flag` boolean + +Sets whether the window should be in fullscreen mode. + +> [!NOTE] +> On macOS, fullscreen transitions take place asynchronously. If further actions depend on the fullscreen state, use the ['enter-full-screen'](base-window.md#event-enter-full-screen) or > ['leave-full-screen'](base-window.md#event-leave-full-screen) events. + +#### `win.isFullScreen()` + +Returns `boolean` - Whether the window is in fullscreen mode. + +#### `win.setSimpleFullScreen(flag)` _macOS_ + +* `flag` boolean + +Enters or leaves simple fullscreen mode. + +Simple fullscreen mode emulates the native fullscreen behavior found in versions of macOS prior to Lion (10.7). + +#### `win.isSimpleFullScreen()` _macOS_ + +Returns `boolean` - Whether the window is in simple (pre-Lion) fullscreen mode. + +#### `win.isNormal()` + +Returns `boolean` - Whether the window is in normal state (not maximized, not minimized, not in fullscreen mode). + +#### `win.setAspectRatio(aspectRatio[, extraSize])` + +* `aspectRatio` Float - The aspect ratio to maintain for some portion of the +content view. +* `extraSize` [Size](structures/size.md) (optional) _macOS_ - The extra size not to be included while +maintaining the aspect ratio. + +This will make a window maintain an aspect ratio. The extra size allows a +developer to have space, specified in pixels, not included within the aspect +ratio calculations. This API already takes into account the difference between a +window's size and its content size. + +Consider a normal window with an HD video player and associated controls. +Perhaps there are 15 pixels of controls on the left edge, 25 pixels of controls +on the right edge and 50 pixels of controls below the player. In order to +maintain a 16:9 aspect ratio (standard aspect ratio for HD @1920x1080) within +the player itself we would call this function with arguments of 16/9 and +\{ width: 40, height: 50 \}. The second argument doesn't care where the extra width and height +are within the content view--only that they exist. Sum any extra width and +height areas you have within the overall content view. + +The aspect ratio is not respected when window is resized programmatically with +APIs like `win.setSize`. + +To reset an aspect ratio, pass 0 as the `aspectRatio` value: `win.setAspectRatio(0)`. + +#### `win.setBackgroundColor(backgroundColor)` + +* `backgroundColor` string - Color in Hex, RGB, RGBA, HSL, HSLA or named CSS color format. The alpha channel is optional for the hex type. + +Examples of valid `backgroundColor` values: + +* Hex + * #fff (shorthand RGB) + * #ffff (shorthand ARGB) + * #ffffff (RGB) + * #ffffffff (ARGB) +* RGB + * `rgb\(([\d]+),\s*([\d]+),\s*([\d]+)\)` + * e.g. rgb(255, 255, 255) +* RGBA + * `rgba\(([\d]+),\s*([\d]+),\s*([\d]+),\s*([\d.]+)\)` + * e.g. rgba(255, 255, 255, 1.0) +* HSL + * `hsl\((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%\)` + * e.g. hsl(200, 20%, 50%) +* HSLA + * `hsla\((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)\)` + * e.g. hsla(200, 20%, 50%, 0.5) +* Color name + * Options are listed in [SkParseColor.cpp](https://source.chromium.org/chromium/chromium/src/+/main:third_party/skia/src/utils/SkParseColor.cpp;l=11-152;drc=eea4bf52cb0d55e2a39c828b017c80a5ee054148) + * Similar to CSS Color Module Level 3 keywords, but case-sensitive. + * e.g. `blueviolet` or `red` + +Sets the background color of the window. See [Setting `backgroundColor`](browser-window.md#setting-the-backgroundcolor-property). + +#### `win.previewFile(path[, displayName])` _macOS_ + +* `path` string - The absolute path to the file to preview with QuickLook. This + is important as Quick Look uses the file name and file extension on the path + to determine the content type of the file to open. +* `displayName` string (optional) - The name of the file to display on the + Quick Look modal view. This is purely visual and does not affect the content + type of the file. Defaults to `path`. + +Uses [Quick Look][quick-look] to preview a file at a given path. + +#### `win.closeFilePreview()` _macOS_ + +Closes the currently open [Quick Look][quick-look] panel. + +#### `win.setBounds(bounds[, animate])` + +* `bounds` Partial\<[Rectangle](structures/rectangle.md)\> +* `animate` boolean (optional) _macOS_ + +Resizes and moves the window to the supplied bounds. Any properties that are not supplied will default to their current values. + +```js +const { BaseWindow } = require('electron') + +const win = new BaseWindow() + +// set all bounds properties +win.setBounds({ x: 440, y: 225, width: 800, height: 600 }) + +// set a single bounds property +win.setBounds({ width: 100 }) + +// { x: 440, y: 225, width: 100, height: 600 } +console.log(win.getBounds()) +``` + +> [!NOTE] +> On macOS, the y-coordinate value cannot be smaller than the [Tray](tray.md) height. The tray height has changed over time and depends on the operating system, but is between 20-40px. Passing a value lower than the tray height will result in a window that is flush to the tray. + +#### `win.getBounds()` + +Returns [`Rectangle`](structures/rectangle.md) - The `bounds` of the window as `Object`. + +> [!NOTE] +> On macOS, the y-coordinate value returned will be at minimum the [Tray](tray.md) height. For example, calling `win.setBounds({ x: 25, y: 20, width: 800, height: 600 })` with a tray height of 38 means that `win.getBounds()` will return `{ x: 25, y: 38, width: 800, height: 600 }`. + +> [!NOTE] +> On Wayland, this method will return `{ x: 0, y: 0, ... }` as introspecting or programmatically changing the global window coordinates is prohibited. + +#### `win.getBackgroundColor()` + +Returns `string` - Gets the background color of the window in Hex (`#RRGGBB`) format. + +See [Setting `backgroundColor`](browser-window.md#setting-the-backgroundcolor-property). + +> [!NOTE] +> The alpha value is _not_ returned alongside the red, green, and blue values. + +#### `win.setContentBounds(bounds[, animate])` + +* `bounds` [Rectangle](structures/rectangle.md) +* `animate` boolean (optional) _macOS_ + +Resizes and moves the window's client area (e.g. the web page) to +the supplied bounds. + +#### `win.getContentBounds()` + +Returns [`Rectangle`](structures/rectangle.md) - The `bounds` of the window's client area as `Object`. + +#### `win.getNormalBounds()` + +Returns [`Rectangle`](structures/rectangle.md) - Contains the window bounds of the normal state + +> [!NOTE] +> Whatever the current state of the window : maximized, minimized or in fullscreen, this function always returns the position and size of the window in normal state. In normal state, getBounds and getNormalBounds returns the same [`Rectangle`](structures/rectangle.md). + +#### `win.setEnabled(enable)` + +* `enable` boolean + +Disable or enable the window. + +#### `win.isEnabled()` + +Returns `boolean` - whether the window is enabled. + +#### `win.setSize(width, height[, animate])` + +* `width` Integer +* `height` Integer +* `animate` boolean (optional) _macOS_ + +Resizes the window to `width` and `height`. If `width` or `height` are below any set minimum size constraints the window will snap to its minimum size. + +#### `win.getSize()` + +Returns `Integer[]` - Contains the window's width and height. + +#### `win.setContentSize(width, height[, animate])` + +* `width` Integer +* `height` Integer +* `animate` boolean (optional) _macOS_ + +Resizes the window's client area (e.g. the web page) to `width` and `height`. + +#### `win.getContentSize()` + +Returns `Integer[]` - Contains the window's client area's width and height. + +#### `win.setMinimumSize(width, height)` + +* `width` Integer +* `height` Integer + +Sets the minimum size of window to `width` and `height`. + +#### `win.getMinimumSize()` + +Returns `Integer[]` - Contains the window's minimum width and height. + +#### `win.setMaximumSize(width, height)` + +* `width` Integer +* `height` Integer + +Sets the maximum size of window to `width` and `height`. + +#### `win.getMaximumSize()` + +Returns `Integer[]` - Contains the window's maximum width and height. + +#### `win.setResizable(resizable)` + +* `resizable` boolean + +Sets whether the window can be manually resized by the user. + +#### `win.isResizable()` + +Returns `boolean` - Whether the window can be manually resized by the user. + +#### `win.setMovable(movable)` _macOS_ _Windows_ + +* `movable` boolean + +Sets whether the window can be moved by user. On Linux does nothing. + +#### `win.isMovable()` _macOS_ _Windows_ + +Returns `boolean` - Whether the window can be moved by user. + +On Linux always returns `true`. + +#### `win.setMinimizable(minimizable)` _macOS_ _Windows_ + +* `minimizable` boolean + +Sets whether the window can be manually minimized by user. On Linux does nothing. + +#### `win.isMinimizable()` _macOS_ _Windows_ + +Returns `boolean` - Whether the window can be manually minimized by the user. + +On Linux always returns `true`. + +#### `win.setMaximizable(maximizable)` _macOS_ _Windows_ + +* `maximizable` boolean + +Sets whether the window can be manually maximized by user. On Linux does nothing. + +#### `win.isMaximizable()` _macOS_ _Windows_ + +Returns `boolean` - Whether the window can be manually maximized by user. + +On Linux always returns `true`. + +#### `win.setFullScreenable(fullscreenable)` + +* `fullscreenable` boolean + +Sets whether the maximize/zoom window button toggles fullscreen mode or maximizes the window. + +#### `win.isFullScreenable()` + +Returns `boolean` - Whether the maximize/zoom window button toggles fullscreen mode or maximizes the window. + +#### `win.setClosable(closable)` _macOS_ _Windows_ + +* `closable` boolean + +Sets whether the window can be manually closed by user. On Linux does nothing. + +#### `win.isClosable()` _macOS_ _Windows_ + +Returns `boolean` - Whether the window can be manually closed by user. + +On Linux always returns `true`. + +#### `win.setHiddenInMissionControl(hidden)` _macOS_ + +* `hidden` boolean + +Sets whether the window will be hidden when the user toggles into mission control. + +#### `win.isHiddenInMissionControl()` _macOS_ + +Returns `boolean` - Whether the window will be hidden when the user toggles into mission control. + +#### `win.setAlwaysOnTop(flag[, level][, relativeLevel])` + +* `flag` boolean +* `level` string (optional) _macOS_ _Windows_ - Values include `normal`, + `floating`, `torn-off-menu`, `modal-panel`, `main-menu`, `status`, + `pop-up-menu`, `screen-saver`, and ~~`dock`~~ (Deprecated). The default is + `floating` when `flag` is true. The `level` is reset to `normal` when the + flag is false. Note that from `floating` to `status` included, the window is + placed below the Dock on macOS and below the taskbar on Windows. From + `pop-up-menu` to a higher it is shown above the Dock on macOS and above the + taskbar on Windows. See the [macOS docs][window-levels] for more details. +* `relativeLevel` Integer (optional) _macOS_ - The number of layers higher to set + this window relative to the given `level`. The default is `0`. Note that Apple + discourages setting levels higher than 1 above `screen-saver`. + +Sets whether the window should show always on top of other windows. After +setting this, the window is still a normal window, not a toolbox window which +can not be focused on. + +#### `win.isAlwaysOnTop()` + +Returns `boolean` - Whether the window is always on top of other windows. + +#### `win.moveAbove(mediaSourceId)` + +* `mediaSourceId` string - Window id in the format of DesktopCapturerSource's id. For example "window:1869:0". + +Moves window above the source window in the sense of z-order. If the +`mediaSourceId` is not of type window or if the window does not exist then +this method throws an error. + +#### `win.moveTop()` + +Moves window to top(z-order) regardless of focus + +#### `win.center()` + +Moves window to the center of the screen. + +#### `win.setPosition(x, y[, animate])` + +* `x` Integer +* `y` Integer +* `animate` boolean (optional) _macOS_ + +Moves window to `x` and `y`. + +#### `win.getPosition()` + +Returns `Integer[]` - Contains the window's current position. + +> [!NOTE] +> On Wayland, this method will return `[0, 0]` as introspecting or programmatically changing the global window coordinates is prohibited. + +#### `win.setTitle(title)` + +* `title` string + +Changes the title of native window to `title`. + +#### `win.getTitle()` + +Returns `string` - The title of the native window. + +> [!NOTE] +> The title of the web page can be different from the title of the native +> window. + +#### `win.setSheetOffset(offsetY[, offsetX])` _macOS_ + +* `offsetY` Float +* `offsetX` Float (optional) + +Changes the attachment point for sheets on macOS. By default, sheets are +attached just below the window frame, but you may want to display them beneath +a HTML-rendered toolbar. For example: + +```js +const { BaseWindow } = require('electron') + +const win = new BaseWindow() + +const toolbarRect = document.getElementById('toolbar').getBoundingClientRect() +win.setSheetOffset(toolbarRect.height) +``` + +#### `win.flashFrame(flag)` + + + +* `flag` boolean + +Starts or stops flashing the window to attract user's attention. + +#### `win.setSkipTaskbar(skip)` _macOS_ _Windows_ + +* `skip` boolean + +Makes the window not show in the taskbar. + +#### `win.setKiosk(flag)` + +* `flag` boolean + +Enters or leaves kiosk mode. + +#### `win.isKiosk()` + +Returns `boolean` - Whether the window is in kiosk mode. + +#### `win.isTabletMode()` _Windows_ + +Returns `boolean` - Whether the window is in Windows 10 tablet mode. + +Since Windows 10 users can [use their PC as tablet](https://support.microsoft.com/en-us/help/17210/windows-10-use-your-pc-like-a-tablet), +under this mode apps can choose to optimize their UI for tablets, such as +enlarging the titlebar and hiding titlebar buttons. + +This API returns whether the window is in tablet mode, and the `resize` event +can be used to listen to changes to tablet mode. + +#### `win.getMediaSourceId()` + +Returns `string` - Window id in the format of DesktopCapturerSource's id. For example "window:1324:0". + +More precisely the format is `window:id:other_id` where `id` is `HWND` on +Windows, `CGWindowID` (`uint64_t`) on macOS and `Window` (`unsigned long`) on +Linux. `other_id` is used to identify web contents (tabs) so within the same +top level window. + +#### `win.getNativeWindowHandle()` + +Returns `Buffer` - The platform-specific handle of the window. + +The native type of the handle is `HWND` on Windows, `NSView*` on macOS, and +`Window` (`unsigned long`) on Linux. + +#### `win.hookWindowMessage(message, callback)` _Windows_ + +* `message` Integer +* `callback` Function + * `wParam` Buffer - The `wParam` provided to the WndProc + * `lParam` Buffer - The `lParam` provided to the WndProc + +Hooks a windows message. The `callback` is called when +the message is received in the WndProc. + +#### `win.isWindowMessageHooked(message)` _Windows_ + +* `message` Integer + +Returns `boolean` - `true` or `false` depending on whether the message is hooked. + +#### `win.unhookWindowMessage(message)` _Windows_ + +* `message` Integer + +Unhook the window message. + +#### `win.unhookAllWindowMessages()` _Windows_ + +Unhooks all of the window messages. + +#### `win.setRepresentedFilename(filename)` _macOS_ + +* `filename` string + +Sets the pathname of the file the window represents, and the icon of the file +will show in window's title bar. + +#### `win.getRepresentedFilename()` _macOS_ + +Returns `string` - The pathname of the file the window represents. + +#### `win.setDocumentEdited(edited)` _macOS_ + +* `edited` boolean + +Specifies whether the window’s document has been edited, and the icon in title +bar will become gray when set to `true`. + +#### `win.isDocumentEdited()` _macOS_ + +Returns `boolean` - Whether the window's document has been edited. + +#### `win.setMenu(menu)` _Linux_ _Windows_ + +* `menu` Menu | null + +Sets the `menu` as the window's menu bar. + +#### `win.removeMenu()` _Linux_ _Windows_ + +Remove the window's menu bar. + +#### `win.setProgressBar(progress[, options])` + +* `progress` Double +* `options` Object (optional) + * `mode` string _Windows_ - Mode for the progress bar. Can be `none`, `normal`, `indeterminate`, `error` or `paused`. + +Sets progress value in progress bar. Valid range is \[0, 1.0]. + +Remove progress bar when progress < 0; +Change to indeterminate mode when progress > 1. + +On Linux platform, only supports Unity desktop environment, you need to specify +the `*.desktop` file name to `desktopName` field in `package.json`. By default, +it will assume `{app.name}.desktop`. + +On Windows, a mode can be passed. Accepted values are `none`, `normal`, +`indeterminate`, `error`, and `paused`. If you call `setProgressBar` without a +mode set (but with a value within the valid range), `normal` will be assumed. + +#### `win.setOverlayIcon(overlay, description)` _Windows_ + +* `overlay` [NativeImage](native-image.md) | null - the icon to display on the bottom +right corner of the taskbar icon. If this parameter is `null`, the overlay is +cleared +* `description` string - a description that will be provided to Accessibility +screen readers + +Sets a 16 x 16 pixel overlay onto the current taskbar icon, usually used to +convey some sort of application status or to passively notify the user. + +#### `win.invalidateShadow()` _macOS_ + +Invalidates the window shadow so that it is recomputed based on the current window shape. + +`BaseWindow`s that are transparent can sometimes leave behind visual artifacts on macOS. +This method can be used to clear these artifacts when, for example, performing an animation. + +#### `win.setHasShadow(hasShadow)` + +* `hasShadow` boolean + +Sets whether the window should have a shadow. + +#### `win.hasShadow()` + +Returns `boolean` - Whether the window has a shadow. + +#### `win.setOpacity(opacity)` _Windows_ _macOS_ + +* `opacity` number - between 0.0 (fully transparent) and 1.0 (fully opaque) + +Sets the opacity of the window. On Linux, does nothing. Out of bound number +values are clamped to the \[0, 1] range. + +#### `win.getOpacity()` + +Returns `number` - between 0.0 (fully transparent) and 1.0 (fully opaque). On +Linux, always returns 1. + +#### `win.setShape(rects)` _Windows_ _Linux_ _Experimental_ + +* `rects` [Rectangle[]](structures/rectangle.md) - Sets a shape on the window. + Passing an empty list reverts the window to being rectangular. + +Setting a window shape determines the area within the window where the system +permits drawing and user interaction. Outside of the given region, no pixels +will be drawn and no mouse events will be registered. Mouse events outside of +the region will not be received by that window, but will fall through to +whatever is behind the window. + +#### `win.setThumbarButtons(buttons)` _Windows_ + +* `buttons` [ThumbarButton[]](structures/thumbar-button.md) + +Returns `boolean` - Whether the buttons were added successfully + +Add a thumbnail toolbar with a specified set of buttons to the thumbnail image +of a window in a taskbar button layout. Returns a `boolean` object indicates +whether the thumbnail has been added successfully. + +The number of buttons in thumbnail toolbar should be no greater than 7 due to +the limited room. Once you setup the thumbnail toolbar, the toolbar cannot be +removed due to the platform's limitation. But you can call the API with an empty +array to clean the buttons. + +The `buttons` is an array of `Button` objects: + +* `Button` Object + * `icon` [NativeImage](native-image.md) - The icon showing in thumbnail + toolbar. + * `click` Function + * `tooltip` string (optional) - The text of the button's tooltip. + * `flags` string[] (optional) - Control specific states and behaviors of the + button. By default, it is `['enabled']`. + +The `flags` is an array that can include following `string`s: + +* `enabled` - The button is active and available to the user. +* `disabled` - The button is disabled. It is present, but has a visual state + indicating it will not respond to user action. +* `dismissonclick` - When the button is clicked, the thumbnail window closes + immediately. +* `nobackground` - Do not draw a button border, use only the image. +* `hidden` - The button is not shown to the user. +* `noninteractive` - The button is enabled but not interactive; no pressed + button state is drawn. This value is intended for instances where the button + is used in a notification. + +#### `win.setThumbnailClip(region)` _Windows_ + +* `region` [Rectangle](structures/rectangle.md) - Region of the window + +Sets the region of the window to show as the thumbnail image displayed when +hovering over the window in the taskbar. You can reset the thumbnail to be +the entire window by specifying an empty region: +`{ x: 0, y: 0, width: 0, height: 0 }`. + +#### `win.setThumbnailToolTip(toolTip)` _Windows_ + +* `toolTip` string + +Sets the toolTip that is displayed when hovering over the window thumbnail +in the taskbar. + +#### `win.setAppDetails(options)` _Windows_ + +* `options` Object + * `appId` string (optional) - Window's [App User Model ID](https://learn.microsoft.com/en-us/windows/win32/shell/appids). + It has to be set, otherwise the other options will have no effect. + * `appIconPath` string (optional) - Window's [Relaunch Icon](https://learn.microsoft.com/en-us/windows/win32/properties/props-system-appusermodel-relaunchiconresource). + * `appIconIndex` Integer (optional) - Index of the icon in `appIconPath`. + Ignored when `appIconPath` is not set. Default is `0`. + * `relaunchCommand` string (optional) - Window's [Relaunch Command](https://learn.microsoft.com/en-us/windows/win32/properties/props-system-appusermodel-relaunchcommand). + * `relaunchDisplayName` string (optional) - Window's [Relaunch Display Name](https://learn.microsoft.com/en-us/windows/win32/properties/props-system-appusermodel-relaunchdisplaynameresource). + +Sets the properties for the window's taskbar button. + +> [!NOTE] +> `relaunchCommand` and `relaunchDisplayName` must always be set +> together. If one of those properties is not set, then neither will be used. + +#### `win.setAccentColor(accentColor)` _Windows_ + +* `accentColor` boolean | string | null - The accent color for the window. By default, follows user preference in System Settings. To reset to system default, pass `null`. + +Sets the system accent color and highlighting of active window border. + +The `accentColor` parameter accepts the following values: + +* **Color string** - Like `true`, but sets a custom accent color using standard CSS color formats (Hex, RGB, RGBA, HSL, HSLA, or named colors). Alpha values in RGBA/HSLA formats are ignored and the color is treated as fully opaque. +* **`true`** - Enable accent color highlighting for the window with the system accent color regardless of whether accent colors are enabled for windows in System `Settings.` +* **`false`** - Disable accent color highlighting for the window regardless of whether accent colors are currently enabled for windows in System Settings. +* **`null`** - Reset window accent color behavior to follow behavior set in System Settings. + +Examples: + +```js +const win = new BrowserWindow({ frame: false }) + +// Set red accent color. +win.setAccentColor('#ff0000') + +// RGB format (alpha ignored if present). +win.setAccentColor('rgba(255,0,0,0.5)') + +// Enable accent color, using the color specified in System Settings. +win.setAccentColor(true) + +// Disable accent color. +win.setAccentColor(false) + +// Reset window accent color behavior to follow behavior set in System Settings. +win.setAccentColor(null) +``` + +#### `win.getAccentColor()` _Windows_ + +Returns `string | boolean` - the system accent color and highlighting of active window border in Hex RGB format. + +If a color has been set for the window that differs from the system accent color, the window accent color will +be returned. Otherwise, a boolean will be returned, with `true` indicating that the window uses the global system accent color, and `false` indicating that accent color highlighting is disabled for this window. + +#### `win.setIcon(icon)` _Windows_ _Linux_ + +* `icon` [NativeImage](native-image.md) | string + +Changes window icon. + +#### `win.setWindowButtonVisibility(visible)` _macOS_ + +* `visible` boolean + +Sets whether the window traffic light buttons should be visible. + +#### `win.setAutoHideMenuBar(hide)` _Windows_ _Linux_ + +* `hide` boolean + +Sets whether the window menu bar should hide itself automatically. Once set the +menu bar will only show when users press the single `Alt` key. + +If the menu bar is already visible, calling `setAutoHideMenuBar(true)` won't hide it immediately. + +#### `win.isMenuBarAutoHide()` _Windows_ _Linux_ + +Returns `boolean` - Whether menu bar automatically hides itself. + +#### `win.setMenuBarVisibility(visible)` _Windows_ _Linux_ + +* `visible` boolean + +Sets whether the menu bar should be visible. If the menu bar is auto-hide, users can still bring up the menu bar by pressing the single `Alt` key. + +#### `win.isMenuBarVisible()` _Windows_ _Linux_ + +Returns `boolean` - Whether the menu bar is visible. + +#### `win.isSnapped()` _Windows_ + +Returns `boolean` - whether the window is arranged via [Snap.](https://support.microsoft.com/en-us/windows/snap-your-windows-885a9b1e-a983-a3b1-16cd-c531795e6241) + +The window is snapped via buttons shown when the mouse is hovered over window +maximize button, or by dragging it to the edges of the screen. + +#### `win.setVisibleOnAllWorkspaces(visible[, options])` _macOS_ _Linux_ + +* `visible` boolean +* `options` Object (optional) + * `visibleOnFullScreen` boolean (optional) _macOS_ - Sets whether + the window should be visible above fullscreen windows. + * `skipTransformProcessType` boolean (optional) _macOS_ - Calling + setVisibleOnAllWorkspaces will by default transform the process + type between UIElementApplication and ForegroundApplication to + ensure the correct behavior. However, this will hide the window + and dock for a short time every time it is called. If your window + is already of type UIElementApplication, you can bypass this + transformation by passing true to skipTransformProcessType. + +Sets whether the window should be visible on all workspaces. + +> [!NOTE] +> This API does nothing on Windows. + +#### `win.isVisibleOnAllWorkspaces()` _macOS_ _Linux_ + +Returns `boolean` - Whether the window is visible on all workspaces. + +> [!NOTE] +> This API always returns false on Windows. + +#### `win.setIgnoreMouseEvents(ignore[, options])` + +* `ignore` boolean +* `options` Object (optional) + * `forward` boolean (optional) _macOS_ _Windows_ - If true, forwards mouse move + messages to Chromium, enabling mouse related events such as `mouseleave`. + Only used when `ignore` is true. If `ignore` is false, forwarding is always + disabled regardless of this value. + +Makes the window ignore all mouse events. + +All mouse events happened in this window will be passed to the window below +this window, but if this window has focus, it will still receive keyboard +events. + +#### `win.setContentProtection(enable)` _macOS_ _Windows_ + +* `enable` boolean + +Prevents the window contents from being captured by other apps. + +On macOS it sets the NSWindow's sharingType to NSWindowSharingNone. +On Windows it calls SetWindowDisplayAffinity with `WDA_EXCLUDEFROMCAPTURE`. +For Windows 10 version 2004 and up the window will be removed from capture entirely, +older Windows versions behave as if `WDA_MONITOR` is applied capturing a black window. + +#### `win.isContentProtected()` _macOS_ _Windows_ + +Returns `boolean` - whether or not content protection is currently enabled. + +#### `win.setFocusable(focusable)` _macOS_ _Windows_ + +* `focusable` boolean + +Changes whether the window can be focused. + +On macOS it does not remove the focus from the window. + +#### `win.isFocusable()` _macOS_ _Windows_ + +Returns `boolean` - Whether the window can be focused. + +#### `win.setParentWindow(parent)` + +* `parent` BaseWindow | null + +Sets `parent` as current window's parent window, passing `null` will turn +current window into a top-level window. + +#### `win.getParentWindow()` + +Returns `BaseWindow | null` - The parent window or `null` if there is no parent. + +#### `win.getChildWindows()` + +Returns `BaseWindow[]` - All child windows. + +#### `win.setAutoHideCursor(autoHide)` _macOS_ + +* `autoHide` boolean + +Controls whether to hide cursor when typing. + +#### `win.selectPreviousTab()` _macOS_ + +Selects the previous tab when native tabs are enabled and there are other +tabs in the window. + +#### `win.selectNextTab()` _macOS_ + +Selects the next tab when native tabs are enabled and there are other +tabs in the window. + +#### `win.showAllTabs()` _macOS_ + +Shows or hides the tab overview when native tabs are enabled. + +#### `win.mergeAllWindows()` _macOS_ + +Merges all windows into one window with multiple tabs when native tabs +are enabled and there is more than one open window. + +#### `win.moveTabToNewWindow()` _macOS_ + +Moves the current tab into a new window if native tabs are enabled and +there is more than one tab in the current window. + +#### `win.toggleTabBar()` _macOS_ + +Toggles the visibility of the tab bar if native tabs are enabled and +there is only one tab in the current window. + +#### `win.addTabbedWindow(baseWindow)` _macOS_ + +* `baseWindow` BaseWindow + +Adds a window as a tab on this window, after the tab for the window instance. + +#### `win.setVibrancy(type)` _macOS_ + +* `type` string | null - Can be `titlebar`, `selection`, `menu`, `popover`, `sidebar`, `header`, `sheet`, `window`, `hud`, `fullscreen-ui`, `tooltip`, `content`, `under-window`, or `under-page`. See + the [macOS documentation][vibrancy-docs] for more details. + +Adds a vibrancy effect to the window. Passing `null` or an empty string +will remove the vibrancy effect on the window. + +#### `win.setBackgroundMaterial(material)` _Windows_ + +* `material` string + * `auto` - Let the Desktop Window Manager (DWM) automatically decide the system-drawn backdrop material for this window. This is the default. + * `none` - Don't draw any system backdrop. + * `mica` - Draw the backdrop material effect corresponding to a long-lived window. + * `acrylic` - Draw the backdrop material effect corresponding to a transient window. + * `tabbed` - Draw the backdrop material effect corresponding to a window with a tabbed title bar. + +This method sets the browser window's system-drawn background material, including behind the non-client area. + +See the [Windows documentation](https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwm_systembackdrop_type) for more details. + +> [!NOTE] +> This method is only supported on Windows 11 22H2 and up. + +#### `win.setWindowButtonPosition(position)` _macOS_ + +* `position` [Point](structures/point.md) | null + +Set a custom position for the traffic light buttons in frameless window. +Passing `null` will reset the position to default. + +#### `win.getWindowButtonPosition()` _macOS_ + +Returns `Point | null` - The custom position for the traffic light buttons in +frameless window, `null` will be returned when there is no custom position. + +#### `win.setTouchBar(touchBar)` _macOS_ + +* `touchBar` TouchBar | null + +Sets the touchBar layout for the current window. Specifying `null` or +`undefined` clears the touch bar. This method only has an effect if the +machine has a touch bar. + +> [!NOTE] +> The TouchBar API is currently experimental and may change or be +> removed in future Electron releases. + +#### `win.setTitleBarOverlay(options)` _Windows_ _Linux_ + +* `options` Object + * `color` String (optional) - The CSS color of the Window Controls Overlay when enabled. + * `symbolColor` String (optional) - The CSS color of the symbols on the Window Controls Overlay when enabled. + * `height` Integer (optional) - The height of the title bar and Window Controls Overlay in pixels. + +On a Window with Window Controls Overlay already enabled, this method updates the style of the title bar overlay. + +On Linux, the `symbolColor` is automatically calculated to have minimum accessible contrast to the `color` if not explicitly set. + +[quick-look]: https://en.wikipedia.org/wiki/Quick_Look +[vibrancy-docs]: https://developer.apple.com/documentation/appkit/nsvisualeffectview?preferredLanguage=objc +[window-levels]: https://developer.apple.com/documentation/appkit/nswindow/level +[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter +[window-session-end-event]:../api/structures/window-session-end-event.md diff --git a/docs/api/browser-view.md b/docs/api/browser-view.md index 0b7c1ef1ec8e5..87f6ead865960 100644 --- a/docs/api/browser-view.md +++ b/docs/api/browser-view.md @@ -1,38 +1,89 @@ -## Class: BrowserView +# BrowserView -> Create and control views. + -Process: [Main](../glossary.md#main-process) +> [!NOTE] +> The `BrowserView` class is deprecated, and replaced by the new +> [`WebContentsView`](web-contents-view.md) class. A `BrowserView` can be used to embed additional web content into a [`BrowserWindow`](browser-window.md). It is like a child window, except that it is positioned relative to its owning window. It is meant to be an alternative to the `webview` tag. +## Class: BrowserView + + + +> Create and control views. + +> [!NOTE] +> The `BrowserView` class is deprecated, and replaced by the new +> [`WebContentsView`](web-contents-view.md) class. + +Process: [Main](../glossary.md#main-process) + +This module cannot be used until the `ready` event of the `app` +module is emitted. + +> [!WARNING] +> Electron's built-in classes cannot be subclassed in user code. +> For more information, see [the FAQ](../faq.md#class-inheritance-does-not-work-with-electron-built-in-modules). + ### Example -```javascript +```js // In the main process. -const { BrowserView, BrowserWindow } = require('electron') +const { app, BrowserView, BrowserWindow } = require('electron') -const win = new BrowserWindow({ width: 800, height: 600 }) +app.whenReady().then(() => { + const win = new BrowserWindow({ width: 800, height: 600 }) -const view = new BrowserView() -win.setBrowserView(view) -view.setBounds({ x: 0, y: 0, width: 300, height: 300 }) -view.webContents.loadURL('https://electronjs.org') + const view = new BrowserView() + win.setBrowserView(view) + view.setBounds({ x: 0, y: 0, width: 300, height: 300 }) + view.webContents.loadURL('https://electronjs.org') +}) ``` -### `new BrowserView([options])` _Experimental_ +### `new BrowserView([options])` _Experimental_ _Deprecated_ + + * `options` Object (optional) - * `webPreferences` Object (optional) - See [BrowserWindow](browser-window.md). + * `webPreferences` [WebPreferences](structures/web-preferences.md?inline) (optional) - Settings of web page's features. ### Instance Properties Objects created with `new BrowserView` have the following properties: -#### `view.webContents` _Experimental_ +#### `view.webContents` _Experimental_ _Deprecated_ + + A [`WebContents`](web-contents.md) object owned by this view. @@ -40,31 +91,94 @@ A [`WebContents`](web-contents.md) object owned by this view. Objects created with `new BrowserView` have the following instance methods: -#### `view.setAutoResize(options)` _Experimental_ +#### `view.setAutoResize(options)` _Experimental_ _Deprecated_ + + * `options` Object - * `width` Boolean (optional) - If `true`, the view's width will grow and shrink together + * `width` boolean (optional) - If `true`, the view's width will grow and shrink together with the window. `false` by default. - * `height` Boolean (optional) - If `true`, the view's height will grow and shrink + * `height` boolean (optional) - If `true`, the view's height will grow and shrink together with the window. `false` by default. - * `horizontal` Boolean (optional) - If `true`, the view's x position and width will grow + * `horizontal` boolean (optional) - If `true`, the view's x position and width will grow and shrink proportionally with the window. `false` by default. - * `vertical` Boolean (optional) - If `true`, the view's y position and height will grow + * `vertical` boolean (optional) - If `true`, the view's y position and height will grow and shrink proportionally with the window. `false` by default. -#### `view.setBounds(bounds)` _Experimental_ +#### `view.setBounds(bounds)` _Experimental_ _Deprecated_ + + * `bounds` [Rectangle](structures/rectangle.md) Resizes and moves the view to the supplied bounds relative to the window. -#### `view.getBounds()` _Experimental_ +#### `view.getBounds()` _Experimental_ _Deprecated_ + + Returns [`Rectangle`](structures/rectangle.md) The `bounds` of this BrowserView instance as `Object`. -#### `view.setBackgroundColor(color)` _Experimental_ +#### `view.setBackgroundColor(color)` _Experimental_ _Deprecated_ -* `color` String - Color in `#aarrggbb` or `#argb` form. The alpha channel is - optional. + + +* `color` string - Color in Hex, RGB, ARGB, HSL, HSLA or named CSS color format. The alpha channel is + optional for the hex type. + +Examples of valid `color` values: + +* Hex + * `#fff` (RGB) + * `#ffff` (ARGB) + * `#ffffff` (RRGGBB) + * `#ffffffff` (AARRGGBB) +* RGB + * `rgb\(([\d]+),\s*([\d]+),\s*([\d]+)\)` + * e.g. `rgb(255, 255, 255)` +* RGBA + * `rgba\(([\d]+),\s*([\d]+),\s*([\d]+),\s*([\d.]+)\)` + * e.g. `rgba(255, 255, 255, 1.0)` +* HSL + * `hsl\((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%\)` + * e.g. `hsl(200, 20%, 50%)` +* HSLA + * `hsla\((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)\)` + * e.g. `hsla(200, 20%, 50%, 0.5)` +* Color name + * Options are listed in [SkParseColor.cpp](https://source.chromium.org/chromium/chromium/src/+/main:third_party/skia/src/utils/SkParseColor.cpp;l=11-152;drc=eea4bf52cb0d55e2a39c828b017c80a5ee054148) + * Similar to CSS Color Module Level 3 keywords, but case-sensitive. + * e.g. `blueviolet` or `red` + +> [!NOTE] +> Hex format with alpha takes `AARRGGBB` or `ARGB`, _not_ `RRGGBBAA` or `RGB`. diff --git a/docs/api/browser-window-proxy.md b/docs/api/browser-window-proxy.md deleted file mode 100644 index 33a1022317d99..0000000000000 --- a/docs/api/browser-window-proxy.md +++ /dev/null @@ -1,53 +0,0 @@ -## Class: BrowserWindowProxy - -> Manipulate the child browser window - -Process: [Renderer](../glossary.md#renderer-process) - -The `BrowserWindowProxy` object is returned from `window.open` and provides -limited functionality with the child window. - -### Instance Methods - -The `BrowserWindowProxy` object has the following instance methods: - -#### `win.blur()` - -Removes focus from the child window. - -#### `win.close()` - -Forcefully closes the child window without calling its unload event. - -#### `win.eval(code)` - -* `code` String - -Evaluates the code in the child window. - -#### `win.focus()` - -Focuses the child window (brings the window to front). - -#### `win.print()` - -Invokes the print dialog on the child window. - -#### `win.postMessage(message, targetOrigin)` - -* `message` any -* `targetOrigin` String - -Sends a message to the child window with the specified origin or `*` for no -origin preference. - -In addition to these methods, the child window implements `window.opener` object -with no properties and a single method. - -### Instance Properties - -The `BrowserWindowProxy` object has the following instance properties: - -#### `win.closed` - -A `Boolean` that is set to true after the child window gets closed. diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index e175fefee1033..2779ed08fd84a 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -4,7 +4,10 @@ Process: [Main](../glossary.md#main-process) -```javascript +This module cannot be used until the `ready` event of the `app` +module is emitted. + +```js // In the main process. const { BrowserWindow } = require('electron') @@ -14,27 +17,30 @@ const win = new BrowserWindow({ width: 800, height: 600 }) win.loadURL('https://github.com') // Or load a local HTML file -win.loadURL(`file://${__dirname}/app/index.html`) +win.loadFile('index.html') ``` -## Frameless window +## Window customization -To create a window without chrome, or a transparent window in arbitrary shape, -you can use the [Frameless Window](frameless-window.md) API. +The `BrowserWindow` class exposes various ways to modify the look and behavior of +your app's windows. For more details, see the [Window Customization](../tutorial/window-customization.md) +tutorial. -## Showing window gracefully +## Showing the window gracefully -When loading a page in the window directly, users may see the page load incrementally, which is not a good experience for a native app. To make the window display -without visual flash, there are two solutions for different situations. +When loading a page in the window directly, users may see the page load incrementally, +which is not a good experience for a native app. To make the window display +without a visual flash, there are two solutions for different situations. -## Using `ready-to-show` event +### Using the `ready-to-show` event While loading the page, the `ready-to-show` event will be emitted when the renderer process has rendered the page for the first time if the window has not been shown yet. Showing the window after this event will have no visual flash: -```javascript +```js const { BrowserWindow } = require('electron') + const win = new BrowserWindow({ show: false }) win.once('ready-to-show', () => { win.show() @@ -48,13 +54,13 @@ event. Please note that using this event implies that the renderer will be considered "visible" and paint even though `show` is false. This event will never fire if you use `paintWhenInitiallyHidden: false` -## Setting `backgroundColor` +### Setting the `backgroundColor` property For a complex app, the `ready-to-show` event could be emitted too late, making the app feel slow. In this case, it is recommended to show the window immediately, and use a `backgroundColor` close to your app's background: -```javascript +```js const { BrowserWindow } = require('electron') const win = new BrowserWindow({ backgroundColor: '#2e2c29' }) @@ -62,13 +68,25 @@ win.loadURL('https://github.com') ``` Note that even for apps that use `ready-to-show` event, it is still recommended -to set `backgroundColor` to make app feel more native. +to set `backgroundColor` to make the app feel more native. + +Some examples of valid `backgroundColor` values include: + +```js +const win = new BrowserWindow() +win.setBackgroundColor('hsl(230, 100%, 50%)') +win.setBackgroundColor('rgb(255, 145, 145)') +win.setBackgroundColor('#ff00a3') +win.setBackgroundColor('blueviolet') +``` + +For more information about these color types see valid options in [win.setBackgroundColor](browser-window.md#winsetbackgroundcolorbackgroundcolor). ## Parent and child windows By using `parent` option, you can create child windows: -```javascript +```js const { BrowserWindow } = require('electron') const top = new BrowserWindow() @@ -81,12 +99,13 @@ The `child` window will always show on top of the `top` window. ## Modal windows -A modal window is a child window that disables parent window, to create a modal -window, you have to set both `parent` and `modal` options: +A modal window is a child window that disables parent window. To create a modal +window, you have to set both the `parent` and `modal` options: -```javascript +```js const { BrowserWindow } = require('electron') +const top = new BrowserWindow() const child = new BrowserWindow({ parent: top, modal: true, show: false }) child.loadURL('https://github.com') child.once('ready-to-show', () => { @@ -121,8 +140,12 @@ state is `hidden` in order to minimize power consumption. move. * On Linux the type of modal windows will be changed to `dialog`. * On Linux many desktop environments do not support hiding a modal window. +* On Wayland (Linux) it is generally not possible to programmatically resize windows + after creation, or to position, move, focus, or blur windows without user input. + If your app needs these capabilities, run it in Xwayland by appending the flag + `--ozone-platform=x11`. -## Class: BrowserWindow +## Class: BrowserWindow extends `BaseWindow` > Create and control browser windows. @@ -132,301 +155,20 @@ Process: [Main](../glossary.md#main-process) It creates a new `BrowserWindow` with native properties as set by the `options`. +> [!WARNING] +> Electron's built-in classes cannot be subclassed in user code. +> For more information, see [the FAQ](../faq.md#class-inheritance-does-not-work-with-electron-built-in-modules). + ### `new BrowserWindow([options])` -* `options` Object (optional) - * `width` Integer (optional) - Window's width in pixels. Default is `800`. - * `height` Integer (optional) - Window's height in pixels. Default is `600`. - * `x` Integer (optional) - (**required** if y is used) Window's left offset from screen. - Default is to center the window. - * `y` Integer (optional) - (**required** if x is used) Window's top offset from screen. - Default is to center the window. - * `useContentSize` Boolean (optional) - The `width` and `height` would be used as web - page's size, which means the actual window's size will include window - frame's size and be slightly larger. Default is `false`. - * `center` Boolean (optional) - Show window in the center of the screen. - * `minWidth` Integer (optional) - Window's minimum width. Default is `0`. - * `minHeight` Integer (optional) - Window's minimum height. Default is `0`. - * `maxWidth` Integer (optional) - Window's maximum width. Default is no limit. - * `maxHeight` Integer (optional) - Window's maximum height. Default is no limit. - * `resizable` Boolean (optional) - Whether window is resizable. Default is `true`. - * `movable` Boolean (optional) - Whether window is movable. This is not implemented - on Linux. Default is `true`. - * `minimizable` Boolean (optional) - Whether window is minimizable. This is not - implemented on Linux. Default is `true`. - * `maximizable` Boolean (optional) - Whether window is maximizable. This is not - implemented on Linux. Default is `true`. - * `closable` Boolean (optional) - Whether window is closable. This is not implemented - on Linux. Default is `true`. - * `focusable` Boolean (optional) - Whether the window can be focused. Default is - `true`. On Windows setting `focusable: false` also implies setting - `skipTaskbar: true`. On Linux setting `focusable: false` makes the window - stop interacting with wm, so the window will always stay on top in all - workspaces. - * `alwaysOnTop` Boolean (optional) - Whether the window should always stay on top of - other windows. Default is `false`. - * `fullscreen` Boolean (optional) - Whether the window should show in fullscreen. When - explicitly set to `false` the fullscreen button will be hidden or disabled - on macOS. Default is `false`. - * `fullscreenable` Boolean (optional) - Whether the window can be put into fullscreen - mode. On macOS, also whether the maximize/zoom button should toggle full - screen mode or maximize window. Default is `true`. - * `simpleFullscreen` Boolean (optional) - Use pre-Lion fullscreen on macOS. Default is `false`. - * `skipTaskbar` Boolean (optional) - Whether to show the window in taskbar. Default is - `false`. - * `kiosk` Boolean (optional) - Whether the window is in kiosk mode. Default is `false`. - * `title` String (optional) - Default window title. Default is `"Electron"`. If the HTML tag `` is defined in the HTML file loaded by `loadURL()`, this property will be ignored. - * `icon` ([NativeImage](native-image.md) | String) (optional) - The window icon. On Windows it is - recommended to use `ICO` icons to get best visual effects, you can also - leave it undefined so the executable's icon will be used. - * `show` Boolean (optional) - Whether window should be shown when created. Default is - `true`. - * `paintWhenInitiallyHidden` Boolean (optional) - Whether the renderer should be active when `show` is `false` and it has just been created. In order for `document.visibilityState` to work correctly on first load with `show: false` you should set this to `false`. Setting this to `false` will cause the `ready-to-show` event to not fire. Default is `true`. - * `frame` Boolean (optional) - Specify `false` to create a - [Frameless Window](frameless-window.md). Default is `true`. - * `parent` BrowserWindow (optional) - Specify parent window. Default is `null`. - * `modal` Boolean (optional) - Whether this is a modal window. This only works when the - window is a child window. Default is `false`. - * `acceptFirstMouse` Boolean (optional) - Whether the web view accepts a single - mouse-down event that simultaneously activates the window. Default is - `false`. - * `disableAutoHideCursor` Boolean (optional) - Whether to hide cursor when typing. - Default is `false`. - * `autoHideMenuBar` Boolean (optional) - Auto hide the menu bar unless the `Alt` - key is pressed. Default is `false`. - * `enableLargerThanScreen` Boolean (optional) - Enable the window to be resized larger - than screen. Only relevant for macOS, as other OSes allow - larger-than-screen windows by default. Default is `false`. - * `backgroundColor` String (optional) - Window's background color as a hexadecimal value, - like `#66CD00` or `#FFF` or `#80FFFFFF` (alpha in #AARRGGBB format is supported if - `transparent` is set to `true`). Default is `#FFF` (white). - * `hasShadow` Boolean (optional) - Whether window should have a shadow. Default is `true`. - * `opacity` Number (optional) - Set the initial opacity of the window, between 0.0 (fully - transparent) and 1.0 (fully opaque). This is only implemented on Windows and macOS. - * `darkTheme` Boolean (optional) - Forces using dark theme for the window, only works on - some GTK+3 desktop environments. Default is `false`. - * `transparent` Boolean (optional) - Makes the window [transparent](frameless-window.md#transparent-window). - Default is `false`. On Windows, does not work unless the window is frameless. - * `type` String (optional) - The type of window, default is normal window. See more about - this below. - * `visualEffectState` String (optional) - Specify how the material appearance should reflect window activity state on macOS. Must be used with the `vibrancy` property. Possible values are: - * `followWindow` - The backdrop should automatically appear active when the window is active, and inactive when it is not. This is the default. - * `active` - The backdrop should always appear active. - * `inactive` - The backdrop should always appear inactive. - * `titleBarStyle` String (optional) - The style of window title bar. - Default is `default`. Possible values are: - * `default` - Results in the standard gray opaque Mac title - bar. - * `hidden` - Results in a hidden title bar and a full size content window, yet - the title bar still has the standard window controls ("traffic lights") in - the top left. - * `hiddenInset` - Results in a hidden title bar with an alternative look - where the traffic light buttons are slightly more inset from the window edge. - * `customButtonsOnHover` Boolean (optional) - Draw custom close, - and minimize buttons on macOS frameless windows. These buttons will not display - unless hovered over in the top left of the window. These custom buttons prevent - issues with mouse events that occur with the standard window toolbar buttons. - **Note:** This option is currently experimental. - * `trafficLightPosition` [Point](structures/point.md) (optional) - Set a custom position for the traffic light buttons. Can only be used with `titleBarStyle` set to `hidden` - * `fullscreenWindowTitle` Boolean (optional) - Shows the title in the - title bar in full screen mode on macOS for all `titleBarStyle` options. - Default is `false`. - * `thickFrame` Boolean (optional) - Use `WS_THICKFRAME` style for frameless windows on - Windows, which adds standard window frame. Setting it to `false` will remove - window shadow and window animations. Default is `true`. - * `vibrancy` String (optional) - Add a type of vibrancy effect to the window, only on - macOS. Can be `appearance-based`, `light`, `dark`, `titlebar`, `selection`, - `menu`, `popover`, `sidebar`, `medium-light`, `ultra-dark`, `header`, `sheet`, `window`, `hud`, `fullscreen-ui`, `tooltip`, `content`, `under-window`, or `under-page`. Please note that using `frame: false` in combination with a vibrancy value requires that you use a non-default `titleBarStyle` as well. Also note that `appearance-based`, `light`, `dark`, `medium-light`, and `ultra-dark` have been deprecated and will be removed in an upcoming version of macOS. - * `zoomToPageWidth` Boolean (optional) - Controls the behavior on macOS when - option-clicking the green stoplight button on the toolbar or by clicking the - Window > Zoom menu item. If `true`, the window will grow to the preferred - width of the web page when zoomed, `false` will cause it to zoom to the - width of the screen. This will also affect the behavior when calling - `maximize()` directly. Default is `false`. - * `tabbingIdentifier` String (optional) - Tab group name, allows opening the - window as a native tab on macOS 10.12+. Windows with the same tabbing - identifier will be grouped together. This also adds a native new tab button - to your window's tab bar and allows your `app` and window to receive the - `new-window-for-tab` event. - * `webPreferences` Object (optional) - Settings of web page's features. - * `devTools` Boolean (optional) - Whether to enable DevTools. If it is set to `false`, can not use `BrowserWindow.webContents.openDevTools()` to open DevTools. Default is `true`. - * `nodeIntegration` Boolean (optional) - Whether node integration is enabled. - Default is `false`. - * `nodeIntegrationInWorker` Boolean (optional) - Whether node integration is - enabled in web workers. Default is `false`. More about this can be found - in [Multithreading](../tutorial/multithreading.md). - * `nodeIntegrationInSubFrames` Boolean (optional) - Experimental option for - enabling Node.js support in sub-frames such as iframes and child windows. All your preloads will load for - every iframe, you can use `process.isMainFrame` to determine if you are - in the main frame or not. - * `preload` String (optional) - Specifies a script that will be loaded before other - scripts run in the page. This script will always have access to node APIs - no matter whether node integration is turned on or off. The value should - be the absolute file path to the script. - When node integration is turned off, the preload script can reintroduce - Node global symbols back to the global scope. See example - [here](process.md#event-loaded). - * `sandbox` Boolean (optional) - If set, this will sandbox the renderer - associated with the window, making it compatible with the Chromium - OS-level sandbox and disabling the Node.js engine. This is not the same as - the `nodeIntegration` option and the APIs available to the preload script - are more limited. Read more about the option [here](sandbox-option.md). - * `enableRemoteModule` Boolean (optional) - Whether to enable the [`remote`](remote.md) module. - Default is `false`. - * `session` [Session](session.md#class-session) (optional) - Sets the session used by the - page. Instead of passing the Session object directly, you can also choose to - use the `partition` option instead, which accepts a partition string. When - both `session` and `partition` are provided, `session` will be preferred. - Default is the default session. - * `partition` String (optional) - Sets the session used by the page according to the - session's partition string. If `partition` starts with `persist:`, the page - will use a persistent session available to all pages in the app with the - same `partition`. If there is no `persist:` prefix, the page will use an - in-memory session. By assigning the same `partition`, multiple pages can share - the same session. Default is the default session. - * `affinity` String (optional) - When specified, web pages with the same - `affinity` will run in the same renderer process. Note that due to reusing - the renderer process, certain `webPreferences` options will also be shared - between the web pages even when you specified different values for them, - including but not limited to `preload`, `sandbox` and `nodeIntegration`. - So it is suggested to use exact same `webPreferences` for web pages with - the same `affinity`. _Deprecated_ - * `zoomFactor` Number (optional) - The default zoom factor of the page, `3.0` represents - `300%`. Default is `1.0`. - * `javascript` Boolean (optional) - Enables JavaScript support. Default is `true`. - * `webSecurity` Boolean (optional) - When `false`, it will disable the - same-origin policy (usually using testing websites by people), and set - `allowRunningInsecureContent` to `true` if this options has not been set - by user. Default is `true`. - * `allowRunningInsecureContent` Boolean (optional) - Allow an https page to run - JavaScript, CSS or plugins from http URLs. Default is `false`. - * `images` Boolean (optional) - Enables image support. Default is `true`. - * `textAreasAreResizable` Boolean (optional) - Make TextArea elements resizable. Default - is `true`. - * `webgl` Boolean (optional) - Enables WebGL support. Default is `true`. - * `plugins` Boolean (optional) - Whether plugins should be enabled. Default is `false`. - * `experimentalFeatures` Boolean (optional) - Enables Chromium's experimental features. - Default is `false`. - * `scrollBounce` Boolean (optional) - Enables scroll bounce (rubber banding) effect on - macOS. Default is `false`. - * `enableBlinkFeatures` String (optional) - A list of feature strings separated by `,`, like - `CSSVariables,KeyboardEventKey` to enable. The full list of supported feature - strings can be found in the [RuntimeEnabledFeatures.json5][runtime-enabled-features] - file. - * `disableBlinkFeatures` String (optional) - A list of feature strings separated by `,`, - like `CSSVariables,KeyboardEventKey` to disable. The full list of supported - feature strings can be found in the - [RuntimeEnabledFeatures.json5][runtime-enabled-features] file. - * `defaultFontFamily` Object (optional) - Sets the default font for the font-family. - * `standard` String (optional) - Defaults to `Times New Roman`. - * `serif` String (optional) - Defaults to `Times New Roman`. - * `sansSerif` String (optional) - Defaults to `Arial`. - * `monospace` String (optional) - Defaults to `Courier New`. - * `cursive` String (optional) - Defaults to `Script`. - * `fantasy` String (optional) - Defaults to `Impact`. - * `defaultFontSize` Integer (optional) - Defaults to `16`. - * `defaultMonospaceFontSize` Integer (optional) - Defaults to `13`. - * `minimumFontSize` Integer (optional) - Defaults to `0`. - * `defaultEncoding` String (optional) - Defaults to `ISO-8859-1`. - * `backgroundThrottling` Boolean (optional) - Whether to throttle animations and timers - when the page becomes background. This also affects the - [Page Visibility API](#page-visibility). Defaults to `true`. - * `offscreen` Boolean (optional) - Whether to enable offscreen rendering for the browser - window. Defaults to `false`. See the - [offscreen rendering tutorial](../tutorial/offscreen-rendering.md) for - more details. - * `contextIsolation` Boolean (optional) - Whether to run Electron APIs and - the specified `preload` script in a separate JavaScript context. Defaults - to `false`. The context that the `preload` script runs in will only have - access to its own dedicated `document` and `window` globals, as well as - its own set of JavaScript builtins (`Array`, `Object`, `JSON`, etc.), - which are all invisible to the loaded content. The Electron API will only - be available in the `preload` script and not the loaded page. This option - should be used when loading potentially untrusted remote content to ensure - the loaded content cannot tamper with the `preload` script and any - Electron APIs being used. This option uses the same technique used by - [Chrome Content Scripts][chrome-content-scripts]. You can access this - context in the dev tools by selecting the 'Electron Isolated Context' - entry in the combo box at the top of the Console tab. - * `worldSafeExecuteJavaScript` Boolean (optional) - If true, values returned from `webFrame.executeJavaScript` will be sanitized to ensure JS values - can't unsafely cross between worlds when using `contextIsolation`. The default - is `false`. In Electron 12, the default will be changed to `true`. _Deprecated_ - * `nativeWindowOpen` Boolean (optional) - Whether to use native - `window.open()`. Defaults to `false`. Child windows will always have node - integration disabled unless `nodeIntegrationInSubFrames` is true. **Note:** This option is currently - experimental. - * `webviewTag` Boolean (optional) - Whether to enable the [`<webview>` tag](webview-tag.md). - Defaults to `false`. **Note:** The - `preload` script configured for the `<webview>` will have node integration - enabled when it is executed so you should ensure remote/untrusted content - is not able to create a `<webview>` tag with a possibly malicious `preload` - script. You can use the `will-attach-webview` event on [webContents](web-contents.md) - to strip away the `preload` script and to validate or alter the - `<webview>`'s initial settings. - * `additionalArguments` String[] (optional) - A list of strings that will be appended - to `process.argv` in the renderer process of this app. Useful for passing small - bits of data down to renderer process preload scripts. - * `safeDialogs` Boolean (optional) - Whether to enable browser style - consecutive dialog protection. Default is `false`. - * `safeDialogsMessage` String (optional) - The message to display when - consecutive dialog protection is triggered. If not defined the default - message would be used, note that currently the default message is in - English and not localized. - * `disableDialogs` Boolean (optional) - Whether to disable dialogs - completely. Overrides `safeDialogs`. Default is `false`. - * `navigateOnDragDrop` Boolean (optional) - Whether dragging and dropping a - file or link onto the page causes a navigation. Default is `false`. - * `autoplayPolicy` String (optional) - Autoplay policy to apply to - content in the window, can be `no-user-gesture-required`, - `user-gesture-required`, `document-user-activation-required`. Defaults to - `no-user-gesture-required`. - * `disableHtmlFullscreenWindowResize` Boolean (optional) - Whether to - prevent the window from resizing when entering HTML Fullscreen. Default - is `false`. - * `accessibleTitle` String (optional) - An alternative title string provided only - to accessibility tools such as screen readers. This string is not directly - visible to users. - * `spellcheck` Boolean (optional) - Whether to enable the builtin spellchecker. - Default is `true`. - * `enableWebSQL` Boolean (optional) - Whether to enable the [WebSQL api](https://www.w3.org/TR/webdatabase/). - Default is `true`. - * `v8CacheOptions` String (optional) - Enforces the v8 code caching policy - used by blink. Accepted values are - * `none` - Disables code caching - * `code` - Heuristic based code caching - * `bypassHeatCheck` - Bypass code caching heuristics but with lazy compilation - * `bypassHeatCheckAndEagerCompile` - Same as above except compilation is eager. - Default policy is `code`. - * `enablePreferredSizeMode` Boolean (optional) - Whether to enable - preferred size mode. The preferred size is the minimum size needed to - contain the layout of the document—without requiring scrolling. Enabling - this will cause the `preferred-size-changed` event to be emitted on the - `WebContents` when the preferred size changes. Default is `false`. - -When setting minimum or maximum window size with `minWidth`/`maxWidth`/ -`minHeight`/`maxHeight`, it only constrains the users. It won't prevent you from -passing a size that does not follow size constraints to `setBounds`/`setSize` or -to the constructor of `BrowserWindow`. - -The possible values and behaviors of the `type` option are platform dependent. -Possible values are: - -* On Linux, possible types are `desktop`, `dock`, `toolbar`, `splash`, - `notification`. -* On macOS, possible types are `desktop`, `textured`. - * The `textured` type adds metal gradient appearance - (`NSTexturedBackgroundWindowMask`). - * The `desktop` type places the window at the desktop background window level - (`kCGDesktopWindowLevel - 1`). Note that desktop window will not receive - focus, keyboard or mouse events, but you can use `globalShortcut` to receive - input sparingly. -* On Windows, possible type is `toolbar`. +* `options` [BrowserWindowConstructorOptions](structures/browser-window-options.md?inline) (optional) ### Instance Events Objects created with `new BrowserWindow` emit the following events: -**Note:** Some events are only available on specific operating systems and are +> [!NOTE] +> Some events are only available on specific operating systems and are labeled as such. #### Event: 'page-title-updated' @@ -434,8 +176,8 @@ labeled as such. Returns: * `event` Event -* `title` String -* `explicitSet` Boolean +* `title` string +* `explicitSet` boolean Emitted when the document changed its title, calling `event.preventDefault()` will prevent the native window's title from changing. @@ -456,7 +198,7 @@ window should be closed, which will also be called when the window is reloaded. In Electron, returning any value other than `undefined` would cancel the close. For example: -```javascript +```js window.onbeforeunload = (e) => { console.log('I do not want to be closed') @@ -464,21 +206,39 @@ window.onbeforeunload = (e) => { // a non-void value will silently cancel the close. // It is recommended to use the dialog API to let the user confirm closing the // application. - e.returnValue = false // equivalent to `return false` but not recommended + e.returnValue = false } ``` -_**Note**: There is a subtle difference between the behaviors of `window.onbeforeunload = handler` and `window.addEventListener('beforeunload', handler)`. It is recommended to always set the `event.returnValue` explicitly, instead of only returning a value, as the former works more consistently within Electron._ +> [!NOTE] +> There is a subtle difference between the behaviors of `window.onbeforeunload = handler` and +> `window.addEventListener('beforeunload', handler)`. It is recommended to always set the +> `event.returnValue` explicitly, instead of only returning a value, as the former works more +> consistently within Electron. #### Event: 'closed' Emitted when the window is closed. After you have received this event you should remove the reference to the window and avoid using it any more. +#### Event: 'query-session-end' _Windows_ + +Returns: + +* `event` [WindowSessionEndEvent][window-session-end-event] + +Emitted when a session is about to end due to a shutdown, machine restart, or user log-off. +Calling `event.preventDefault()` can delay the system shutdown, though it’s generally best +to respect the user’s choice to end the session. However, you may choose to use it if +ending the session puts the user at risk of losing data. + #### Event: 'session-end' _Windows_ -Emitted when window session is going to end due to force shutdown or machine restart -or session log off. +Returns: + +* `event` [WindowSessionEndEvent][window-session-end-event] + +Emitted when a session is about to end due to a shutdown, machine restart, or user log-off. Once this event fires, there is no way to prevent the session from ending. #### Event: 'unresponsive' @@ -534,11 +294,20 @@ Returns: * `event` Event * `newBounds` [Rectangle](structures/rectangle.md) - Size the window is being resized to. +* `details` Object + * `edge` (string) - The edge of the window being dragged for resizing. Can be `bottom`, `left`, `right`, `top-left`, `top-right`, `bottom-left` or `bottom-right`. Emitted before the window is resized. Calling `event.preventDefault()` will prevent the window from being resized. Note that this is only emitted when the window is being resized manually. Resizing the window with `setBounds`/`setSize` will not emit this event. +The possible values and behaviors of the `edge` option are platform dependent. Possible values are: + +* On Windows, possible values are `bottom`, `top`, `left`, `right`, `top-left`, `top-right`, `bottom-left`, `bottom-right`. +* On macOS, possible values are `bottom` and `right`. + * The value `bottom` is used to denote vertical resizing. + * The value `right` is used to denote horizontal resizing. + #### Event: 'resize' Emitted after the window has been resized. @@ -558,7 +327,7 @@ Returns: Emitted before the window is moved. On Windows, calling `event.preventDefault()` will prevent the window from being moved. -Note that this is only emitted when the window is being resized manually. Resizing the window with `setBounds`/`setSize` will not emit this event. +Note that this is only emitted when the window is being moved manually. Moving the window with `setPosition`/`setBounds`/`center` will not emit this event. #### Event: 'move' @@ -568,7 +337,8 @@ Emitted when the window is being moved to a new position. Emitted once when the window is moved to a new position. -__Note__: On macOS this event is an alias of `move`. +> [!NOTE] +> On macOS, this event is an alias of `move`. #### Event: 'enter-full-screen' @@ -591,7 +361,7 @@ Emitted when the window leaves a full-screen state triggered by HTML API. Returns: * `event` Event -* `isAlwaysOnTop` Boolean +* `isAlwaysOnTop` boolean Emitted when the window is set or unset to show always on top of other windows. @@ -600,9 +370,9 @@ Emitted when the window is set or unset to show always on top of other windows. Returns: * `event` Event -* `command` String +* `command` string -Emitted when an [App Command](https://msdn.microsoft.com/en-us/library/windows/desktop/ms646275(v=vs.85).aspx) +Emitted when an [App Command](https://learn.microsoft.com/en-us/windows/win32/inputdev/wm-appcommand) is invoked. These are typically related to keyboard media keys or browser commands, as well as the "Back" button built into some mice on Windows. @@ -610,8 +380,9 @@ Commands are lowercased, underscores are replaced with hyphens, and the `APPCOMMAND_` prefix is stripped off. e.g. `APPCOMMAND_BROWSER_BACKWARD` is emitted as `browser-backward`. -```javascript +```js const { BrowserWindow } = require('electron') + const win = new BrowserWindow() win.on('app-command', (e, cmd) => { // Navigate the window back when the user hits their mouse back button @@ -626,24 +397,12 @@ The following app commands are explicitly supported on Linux: * `browser-backward` * `browser-forward` -#### Event: 'scroll-touch-begin' _macOS_ - -Emitted when scroll wheel event phase has begun. - -#### Event: 'scroll-touch-end' _macOS_ - -Emitted when scroll wheel event phase has ended. - -#### Event: 'scroll-touch-edge' _macOS_ - -Emitted when scroll wheel event phase filed upon reaching the edge of element. - #### Event: 'swipe' _macOS_ Returns: * `event` Event -* `direction` String +* `direction` string Emitted on 3-finger swipe. Possible directions are `up`, `right`, `down`, `left`. @@ -676,14 +435,18 @@ Emitted when the window has closed a sheet. #### Event: 'new-window-for-tab' _macOS_ -Emitted when the native new tab button is clicked. +Emitted when the user clicks the native macOS new tab button. The new +tab button is only visible if the current `BrowserWindow` has a +`tabbingIdentifier`. + +You must create a window in this handler in order for macOS tabbing to work as expected. -#### Event: 'system-context-menu' _Windows_ +#### Event: 'system-context-menu' _Windows_ _Linux_ Returns: * `event` Event -* `point` [Point](structures/point.md) - The screen coordinates the context menu was triggered at +* `point` [Point](structures/point.md) - The screen coordinates where the context menu was triggered. Emitted when the system context menu is triggered on the window, this is normally only triggered when the user right clicks on the non-client area @@ -692,6 +455,8 @@ as `-webkit-app-region: drag` in a frameless window. Calling `event.preventDefault()` will prevent the menu from being displayed. +To convert `point` to DIP, use [`screen.screenToDipPoint(point)`](./screen.md#screenscreentodippointpoint-windows-linux). + ### Static Methods The `BrowserWindow` class has the following static methods: @@ -711,10 +476,14 @@ Returns `BrowserWindow | null` - The window that is focused in this application, Returns `BrowserWindow | null` - The window that owns the given `webContents` or `null` if the contents are not owned by a window. -#### `BrowserWindow.fromBrowserView(browserView)` +#### `BrowserWindow.fromBrowserView(browserView)` _Deprecated_ * `browserView` [BrowserView](browser-view.md) +> [!NOTE] +> The `BrowserView` class is deprecated, and replaced by the new +> [`WebContentsView`](web-contents-view.md) class. + Returns `BrowserWindow | null` - The window that owns the given `browserView`. If the given view is not attached to any window, returns `null`. #### `BrowserWindow.fromId(id)` @@ -723,99 +492,11 @@ Returns `BrowserWindow | null` - The window that owns the given `browserView`. I Returns `BrowserWindow | null` - The window with the given `id`. -#### `BrowserWindow.addExtension(path)` _Deprecated_ - -* `path` String - -Adds Chrome extension located at `path`, and returns extension's name. - -The method will also not return if the extension's manifest is missing or incomplete. - -**Note:** This API cannot be called before the `ready` event of the `app` module -is emitted. - -**Note:** This method is deprecated. Instead, use -[`ses.loadExtension(path)`](session.md#sesloadextensionpath). - -#### `BrowserWindow.removeExtension(name)` _Deprecated_ - -* `name` String - -Remove a Chrome extension by name. - -**Note:** This API cannot be called before the `ready` event of the `app` module -is emitted. - -**Note:** This method is deprecated. Instead, use -[`ses.removeExtension(extension_id)`](session.md#sesremoveextensionextensionid). - -#### `BrowserWindow.getExtensions()` _Deprecated_ - -Returns `Record<String, ExtensionInfo>` - The keys are the extension names and each value is -an Object containing `name` and `version` properties. - -**Note:** This API cannot be called before the `ready` event of the `app` module -is emitted. - -**Note:** This method is deprecated. Instead, use -[`ses.getAllExtensions()`](session.md#sesgetallextensions). - -#### `BrowserWindow.addDevToolsExtension(path)` _Deprecated_ - -* `path` String - -Adds DevTools extension located at `path`, and returns extension's name. - -The extension will be remembered so you only need to call this API once, this -API is not for programming use. If you try to add an extension that has already -been loaded, this method will not return and instead log a warning to the -console. - -The method will also not return if the extension's manifest is missing or incomplete. - -**Note:** This API cannot be called before the `ready` event of the `app` module -is emitted. - -**Note:** This method is deprecated. Instead, use -[`ses.loadExtension(path)`](session.md#sesloadextensionpath). - -#### `BrowserWindow.removeDevToolsExtension(name)` _Deprecated_ - -* `name` String - -Remove a DevTools extension by name. - -**Note:** This API cannot be called before the `ready` event of the `app` module -is emitted. - -**Note:** This method is deprecated. Instead, use -[`ses.removeExtension(extension_id)`](session.md#sesremoveextensionextensionid). - -#### `BrowserWindow.getDevToolsExtensions()` _Deprecated_ - -Returns `Record<string, ExtensionInfo>` - The keys are the extension names and each value is -an Object containing `name` and `version` properties. - -To check if a DevTools extension is installed you can run the following: - -```javascript -const { BrowserWindow } = require('electron') - -const installed = 'devtron' in BrowserWindow.getDevToolsExtensions() -console.log(installed) -``` - -**Note:** This API cannot be called before the `ready` event of the `app` module -is emitted. - -**Note:** This method is deprecated. Instead, use -[`ses.getAllExtensions()`](session.md#sesgetallextensions). - ### Instance Properties Objects created with `new BrowserWindow` have the following properties: -```javascript +```js const { BrowserWindow } = require('electron') // In this example `win` is our instance const win = new BrowserWindow({ width: 800, height: 600 }) @@ -834,96 +515,107 @@ events. A `Integer` property representing the unique ID of the window. Each ID is unique among all `BrowserWindow` instances of the entire Electron application. -#### `win.autoHideMenuBar` +#### `win.tabbingIdentifier` _macOS_ _Readonly_ + +A `string` (optional) property that is equal to the `tabbingIdentifier` passed to the `BrowserWindow` constructor or `undefined` if none was set. + +#### `win.autoHideMenuBar` _Linux_ _Windows_ -A `Boolean` property that determines whether the window menu bar should hide itself automatically. Once set, the menu bar will only show when users press the single `Alt` key. +A `boolean` property that determines whether the window menu bar should hide itself automatically. Once set, the menu bar will only show when users press the single `Alt` key. If the menu bar is already visible, setting this property to `true` won't hide it immediately. #### `win.simpleFullScreen` -A `Boolean` property that determines whether the window is in simple (pre-Lion) fullscreen mode. +A `boolean` property that determines whether the window is in simple (pre-Lion) fullscreen mode. #### `win.fullScreen` -A `Boolean` property that determines whether the window is in fullscreen mode. +A `boolean` property that determines whether the window is in fullscreen mode. -#### `win.visibleOnAllWorkspaces` +#### `win.focusable` _Windows_ _macOS_ -A `Boolean` property that determines whether the window is visible on all workspaces. +A `boolean` property that determines whether the window is focusable. -**Note:** Always returns false on Windows. +#### `win.visibleOnAllWorkspaces` _macOS_ _Linux_ + +A `boolean` property that determines whether the window is visible on all workspaces. + +> [!NOTE] +> Always returns false on Windows. #### `win.shadow` -A `Boolean` property that determines whether the window has a shadow. +A `boolean` property that determines whether the window has a shadow. #### `win.menuBarVisible` _Windows_ _Linux_ -A `Boolean` property that determines whether the menu bar should be visible. +A `boolean` property that determines whether the menu bar should be visible. -**Note:** If the menu bar is auto-hide, users can still bring up the menu bar by pressing the single `Alt` key. +> [!NOTE] +> If the menu bar is auto-hide, users can still bring up the menu bar by pressing the single `Alt` key. #### `win.kiosk` -A `Boolean` property that determines whether the window is in kiosk mode. +A `boolean` property that determines whether the window is in kiosk mode. #### `win.documentEdited` _macOS_ -A `Boolean` property that specifies whether the window’s document has been edited. +A `boolean` property that specifies whether the window’s document has been edited. The icon in title bar will become gray when set to `true`. #### `win.representedFilename` _macOS_ -A `String` property that determines the pathname of the file the window represents, +A `string` property that determines the pathname of the file the window represents, and the icon of the file will show in window's title bar. #### `win.title` -A `String` property that determines the title of the native window. +A `string` property that determines the title of the native window. -**Note:** The title of the web page can be different from the title of the native window. +> [!NOTE] +> The title of the web page can be different from the title of the native window. -#### `win.minimizable` +#### `win.minimizable` _macOS_ _Windows_ -A `Boolean` property that determines whether the window can be manually minimized by user. +A `boolean` property that determines whether the window can be manually minimized by user. On Linux the setter is a no-op, although the getter returns `true`. -#### `win.maximizable` +#### `win.maximizable` _macOS_ _Windows_ -A `Boolean` property that determines whether the window can be manually maximized by user. +A `boolean` property that determines whether the window can be manually maximized by user. On Linux the setter is a no-op, although the getter returns `true`. #### `win.fullScreenable` -A `Boolean` property that determines whether the maximize/zoom window button toggles fullscreen mode or +A `boolean` property that determines whether the maximize/zoom window button toggles fullscreen mode or maximizes the window. #### `win.resizable` -A `Boolean` property that determines whether the window can be manually resized by user. +A `boolean` property that determines whether the window can be manually resized by user. -#### `win.closable` +#### `win.closable` _macOS_ _Windows_ -A `Boolean` property that determines whether the window can be manually closed by user. +A `boolean` property that determines whether the window can be manually closed by user. On Linux the setter is a no-op, although the getter returns `true`. -#### `win.movable` +#### `win.movable` _macOS_ _Windows_ -A `Boolean` property that determines Whether the window can be moved by user. +A `boolean` property that determines Whether the window can be moved by user. On Linux the setter is a no-op, although the getter returns `true`. #### `win.excludedFromShownWindowsMenu` _macOS_ -A `Boolean` property that determines whether the window is excluded from the application’s Windows menu. `false` by default. +A `boolean` property that determines whether the window is excluded from the application’s Windows menu. `false` by default. -```js +```js @ts-expect-error=[11] const win = new BrowserWindow({ height: 600, width: 600 }) const template = [ @@ -940,16 +632,21 @@ Menu.setApplicationMenu(menu) #### `win.accessibleTitle` -A `String` property that defines an alternative title provided only to +A `string` property that defines an alternative title provided only to accessibility tools such as screen readers. This string is not directly visible to users. +#### `win.snapped` _Windows_ _Readonly_ + +A `boolean` property that indicates whether the window is arranged via [Snap.](https://support.microsoft.com/en-us/windows/snap-your-windows-885a9b1e-a983-a3b1-16cd-c531795e6241) + ### Instance Methods Objects created with `new BrowserWindow` have the following instance methods: -**Note:** Some methods are only available on specific operating systems and are -labeled as such. +> [!NOTE] +> Some methods are only available on specific operating systems and are +> labeled as such. #### `win.destroy()` @@ -967,17 +664,22 @@ the [close event](#event-close). Focuses on the window. +On Wayland (Linux), the desktop environment may show a notification or flash +the app icon if the window or app is not already focused. + #### `win.blur()` Removes focus from the window. +Not supported on Wayland (Linux). + #### `win.isFocused()` -Returns `Boolean` - Whether the window is focused. +Returns `boolean` - Whether the window is focused. #### `win.isDestroyed()` -Returns `Boolean` - Whether the window is destroyed. +Returns `boolean` - Whether the window is destroyed. #### `win.show()` @@ -987,17 +689,19 @@ Shows and gives focus to the window. Shows the window but doesn't focus on it. +Not supported on Wayland (Linux). + #### `win.hide()` Hides the window. #### `win.isVisible()` -Returns `Boolean` - Whether the window is visible to the user. +Returns `boolean` - Whether the window is visible to the user in the foreground of the app. #### `win.isModal()` -Returns `Boolean` - Whether current window is a modal window. +Returns `boolean` - Whether current window is a modal window. #### `win.maximize()` @@ -1010,7 +714,7 @@ Unmaximizes the window. #### `win.isMaximized()` -Returns `Boolean` - Whether the window is maximized. +Returns `boolean` - Whether the window is maximized. #### `win.minimize()` @@ -1023,21 +727,27 @@ Restores the window from minimized state to its previous state. #### `win.isMinimized()` -Returns `Boolean` - Whether the window is minimized. +Returns `boolean` - Whether the window is minimized. #### `win.setFullScreen(flag)` -* `flag` Boolean +* `flag` boolean Sets whether the window should be in fullscreen mode. +> [!NOTE] +> On macOS, fullscreen transitions take place asynchronously. If further actions depend on the fullscreen state, use the ['enter-full-screen'](browser-window.md#event-enter-full-screen) or ['leave-full-screen'](browser-window.md#event-leave-full-screen) events. + #### `win.isFullScreen()` -Returns `Boolean` - Whether the window is in fullscreen mode. +Returns `boolean` - Whether the window is in fullscreen mode. + +> [!NOTE] +> On macOS, fullscreen transitions take place asynchronously. When querying for a BrowserWindow's fullscreen status, you should ensure that either the ['enter-full-screen'](browser-window.md#event-enter-full-screen) or ['leave-full-screen'](browser-window.md#event-leave-full-screen) events have been emitted. #### `win.setSimpleFullScreen(flag)` _macOS_ -* `flag` Boolean +* `flag` boolean Enters or leaves simple fullscreen mode. @@ -1045,13 +755,13 @@ Simple fullscreen mode emulates the native fullscreen behavior found in versions #### `win.isSimpleFullScreen()` _macOS_ -Returns `Boolean` - Whether the window is in simple (pre-Lion) fullscreen mode. +Returns `boolean` - Whether the window is in simple (pre-Lion) fullscreen mode. #### `win.isNormal()` -Returns `Boolean` - Whether the window is in normal state (not maximized, not minimized, not in fullscreen mode). +Returns `boolean` - Whether the window is in normal state (not maximized, not minimized, not in fullscreen mode). -#### `win.setAspectRatio(aspectRatio[, extraSize])` _macOS_ _Linux_ +#### `win.setAspectRatio(aspectRatio[, extraSize])` * `aspectRatio` Float - The aspect ratio to maintain for some portion of the content view. @@ -1068,25 +778,51 @@ Perhaps there are 15 pixels of controls on the left edge, 25 pixels of controls on the right edge and 50 pixels of controls below the player. In order to maintain a 16:9 aspect ratio (standard aspect ratio for HD @1920x1080) within the player itself we would call this function with arguments of 16/9 and -{ width: 40, height: 50 }. The second argument doesn't care where the extra width and height +\{ width: 40, height: 50 \}. The second argument doesn't care where the extra width and height are within the content view--only that they exist. Sum any extra width and height areas you have within the overall content view. -#### `win.setBackgroundColor(backgroundColor)` +The aspect ratio is not respected when window is resized programmatically with +APIs like `win.setSize`. + +To reset an aspect ratio, pass 0 as the `aspectRatio` value: `win.setAspectRatio(0)`. -* `backgroundColor` String - Window's background color as a hexadecimal value, - like `#66CD00` or `#FFF` or `#80FFFFFF` (alpha is supported if `transparent` - is `true`). Default is `#FFF` (white). +#### `win.setBackgroundColor(backgroundColor)` -Sets the background color of the window. See [Setting -`backgroundColor`](#setting-backgroundcolor). +* `backgroundColor` string - Color in Hex, RGB, RGBA, HSL, HSLA or named CSS color format. The alpha channel is optional for the hex type. + +Examples of valid `backgroundColor` values: + +* Hex + * #fff (shorthand RGB) + * #ffff (shorthand ARGB) + * #ffffff (RGB) + * #ffffffff (ARGB) +* RGB + * `rgb\(([\d]+),\s*([\d]+),\s*([\d]+)\)` + * e.g. rgb(255, 255, 255) +* RGBA + * `rgba\(([\d]+),\s*([\d]+),\s*([\d]+),\s*([\d.]+)\)` + * e.g. rgba(255, 255, 255, 1.0) +* HSL + * `hsl\((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%\)` + * e.g. hsl(200, 20%, 50%) +* HSLA + * `hsla\((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)\)` + * e.g. hsla(200, 20%, 50%, 0.5) +* Color name + * Options are listed in [SkParseColor.cpp](https://source.chromium.org/chromium/chromium/src/+/main:third_party/skia/src/utils/SkParseColor.cpp;l=11-152;drc=eea4bf52cb0d55e2a39c828b017c80a5ee054148) + * Similar to CSS Color Module Level 3 keywords, but case-sensitive. + * e.g. `blueviolet` or `red` + +Sets the background color of the window. See [Setting `backgroundColor`](#setting-the-backgroundcolor-property). #### `win.previewFile(path[, displayName])` _macOS_ -* `path` String - The absolute path to the file to preview with QuickLook. This +* `path` string - The absolute path to the file to preview with QuickLook. This is important as Quick Look uses the file name and file extension on the path to determine the content type of the file to open. -* `displayName` String (optional) - The name of the file to display on the +* `displayName` string (optional) - The name of the file to display on the Quick Look modal view. This is purely visual and does not affect the content type of the file. Defaults to `path`. @@ -1098,13 +834,16 @@ Closes the currently open [Quick Look][quick-look] panel. #### `win.setBounds(bounds[, animate])` -* `bounds` Partial<[Rectangle](structures/rectangle.md)> -* `animate` Boolean (optional) _macOS_ +* `bounds` Partial\<[Rectangle](structures/rectangle.md)\> +* `animate` boolean (optional) _macOS_ Resizes and moves the window to the supplied bounds. Any properties that are not supplied will default to their current values. -```javascript +On Wayland (Linux), has the same limitations as `setSize` and `setPosition`. + +```js const { BrowserWindow } = require('electron') + const win = new BrowserWindow() // set all bounds properties @@ -1117,23 +856,38 @@ win.setBounds({ width: 100 }) console.log(win.getBounds()) ``` +> [!NOTE] +> On macOS, the y-coordinate value cannot be smaller than the [Tray](tray.md) height. The tray height has changed over time and depends on the operating system, but is between 20-40px. Passing a value lower than the tray height will result in a window that is flush to the tray. + #### `win.getBounds()` Returns [`Rectangle`](structures/rectangle.md) - The `bounds` of the window as `Object`. +> [!NOTE] +> On macOS, the y-coordinate value returned will be at minimum the [Tray](tray.md) height. For example, calling `win.setBounds({ x: 25, y: 20, width: 800, height: 600 })` with a tray height of 38 means that `win.getBounds()` will return `{ x: 25, y: 38, width: 800, height: 600 }`. + +> [!NOTE] +> On Wayland, this method will return `{ x: 0, y: 0, ... }` as introspecting or programmatically changing the global window coordinates is prohibited. + #### `win.getBackgroundColor()` -Returns `String` - Gets the background color of the window. See [Setting -`backgroundColor`](#setting-backgroundcolor). +Returns `string` - Gets the background color of the window in Hex (`#RRGGBB`) format. + +See [Setting `backgroundColor`](#setting-the-backgroundcolor-property). + +> [!NOTE] +> The alpha value is _not_ returned alongside the red, green, and blue values. #### `win.setContentBounds(bounds[, animate])` * `bounds` [Rectangle](structures/rectangle.md) -* `animate` Boolean (optional) _macOS_ +* `animate` boolean (optional) _macOS_ Resizes and moves the window's client area (e.g. the web page) to the supplied bounds. +On Wayland (Linux), has the same limitations as `setContentSize` and `setPosition`. + #### `win.getContentBounds()` Returns [`Rectangle`](structures/rectangle.md) - The `bounds` of the window's client area as `Object`. @@ -1142,26 +896,29 @@ Returns [`Rectangle`](structures/rectangle.md) - The `bounds` of the window's cl Returns [`Rectangle`](structures/rectangle.md) - Contains the window bounds of the normal state -**Note:** whatever the current state of the window : maximized, minimized or in fullscreen, this function always returns the position and size of the window in normal state. In normal state, getBounds and getNormalBounds returns the same [`Rectangle`](structures/rectangle.md). +> [!NOTE] +> Whatever the current state of the window (maximized, minimized or in fullscreen), this function always returns the position and size of the window in normal state. In normal state, `getBounds` and `getNormalBounds` return the same [`Rectangle`](structures/rectangle.md). #### `win.setEnabled(enable)` -* `enable` Boolean +* `enable` boolean Disable or enable the window. #### `win.isEnabled()` -Returns `Boolean` - whether the window is enabled. +Returns `boolean` - whether the window is enabled. #### `win.setSize(width, height[, animate])` * `width` Integer * `height` Integer -* `animate` Boolean (optional) _macOS_ +* `animate` boolean (optional) _macOS_ Resizes the window to `width` and `height`. If `width` or `height` are below any set minimum size constraints the window will snap to its minimum size. +On Wayland (Linux), may not work as some window managers restrict programmatic window resizing. + #### `win.getSize()` Returns `Integer[]` - Contains the window's width and height. @@ -1170,10 +927,12 @@ Returns `Integer[]` - Contains the window's width and height. * `width` Integer * `height` Integer -* `animate` Boolean (optional) _macOS_ +* `animate` boolean (optional) _macOS_ Resizes the window's client area (e.g. the web page) to `width` and `height`. +On Wayland (Linux), may not work as some window managers restrict programmatic window resizing. + #### `win.getContentSize()` Returns `Integer[]` - Contains the window's client area's width and height. @@ -1202,76 +961,86 @@ Returns `Integer[]` - Contains the window's maximum width and height. #### `win.setResizable(resizable)` -* `resizable` Boolean +* `resizable` boolean Sets whether the window can be manually resized by the user. #### `win.isResizable()` -Returns `Boolean` - Whether the window can be manually resized by the user. +Returns `boolean` - Whether the window can be manually resized by the user. #### `win.setMovable(movable)` _macOS_ _Windows_ -* `movable` Boolean +* `movable` boolean Sets whether the window can be moved by user. On Linux does nothing. #### `win.isMovable()` _macOS_ _Windows_ -Returns `Boolean` - Whether the window can be moved by user. +Returns `boolean` - Whether the window can be moved by user. On Linux always returns `true`. #### `win.setMinimizable(minimizable)` _macOS_ _Windows_ -* `minimizable` Boolean +* `minimizable` boolean Sets whether the window can be manually minimized by user. On Linux does nothing. #### `win.isMinimizable()` _macOS_ _Windows_ -Returns `Boolean` - Whether the window can be manually minimized by the user. +Returns `boolean` - Whether the window can be manually minimized by the user. On Linux always returns `true`. #### `win.setMaximizable(maximizable)` _macOS_ _Windows_ -* `maximizable` Boolean +* `maximizable` boolean Sets whether the window can be manually maximized by user. On Linux does nothing. #### `win.isMaximizable()` _macOS_ _Windows_ -Returns `Boolean` - Whether the window can be manually maximized by user. +Returns `boolean` - Whether the window can be manually maximized by user. On Linux always returns `true`. #### `win.setFullScreenable(fullscreenable)` -* `fullscreenable` Boolean +* `fullscreenable` boolean Sets whether the maximize/zoom window button toggles fullscreen mode or maximizes the window. #### `win.isFullScreenable()` -Returns `Boolean` - Whether the maximize/zoom window button toggles fullscreen mode or maximizes the window. +Returns `boolean` - Whether the maximize/zoom window button toggles fullscreen mode or maximizes the window. #### `win.setClosable(closable)` _macOS_ _Windows_ -* `closable` Boolean +* `closable` boolean Sets whether the window can be manually closed by user. On Linux does nothing. #### `win.isClosable()` _macOS_ _Windows_ -Returns `Boolean` - Whether the window can be manually closed by user. +Returns `boolean` - Whether the window can be manually closed by user. On Linux always returns `true`. +#### `win.setHiddenInMissionControl(hidden)` _macOS_ + +* `hidden` boolean + +Sets whether the window will be hidden when the user toggles into mission control. + +#### `win.isHiddenInMissionControl()` _macOS_ + +Returns `boolean` - Whether the window will be hidden when the user toggles into mission control. + #### `win.setAlwaysOnTop(flag[, level][, relativeLevel])` -* `flag` Boolean -* `level` String (optional) _macOS_ _Windows_ - Values include `normal`, +* `flag` boolean +* `level` string (optional) _macOS_ _Windows_ - Values include `normal`, `floating`, `torn-off-menu`, `modal-panel`, `main-menu`, `status`, `pop-up-menu`, `screen-saver`, and ~~`dock`~~ (Deprecated). The default is `floating` when `flag` is true. The `level` is reset to `normal` when the @@ -1289,11 +1058,11 @@ can not be focused on. #### `win.isAlwaysOnTop()` -Returns `Boolean` - Whether the window is always on top of other windows. +Returns `boolean` - Whether the window is always on top of other windows. #### `win.moveAbove(mediaSourceId)` -* `mediaSourceId` String - Window id in the format of DesktopCapturerSource's id. For example "window:1869:0". +* `mediaSourceId` string - Window id in the format of DesktopCapturerSource's id. For example "window:1869:0". Moves window above the source window in the sense of z-order. If the `mediaSourceId` is not of type window or if the window does not exist then @@ -1301,36 +1070,46 @@ this method throws an error. #### `win.moveTop()` -Moves window to top(z-order) regardless of focus +Moves window to top(z-order) regardless of focus. + +Not supported on Wayland (Linux). #### `win.center()` Moves window to the center of the screen. +Not supported on Wayland (Linux). + #### `win.setPosition(x, y[, animate])` * `x` Integer * `y` Integer -* `animate` Boolean (optional) _macOS_ +* `animate` boolean (optional) _macOS_ Moves window to `x` and `y`. +Not supported on Wayland (Linux). + #### `win.getPosition()` Returns `Integer[]` - Contains the window's current position. +> [!NOTE] +> On Wayland, this method will return `[0, 0]` as introspecting or programmatically changing the global window coordinates is prohibited. + #### `win.setTitle(title)` -* `title` String +* `title` string Changes the title of native window to `title`. #### `win.getTitle()` -Returns `String` - The title of the native window. +Returns `string` - The title of the native window. -**Note:** The title of the web page can be different from the title of the native -window. +> [!NOTE] +> The title of the web page can be different from the title of the native +> window. #### `win.setSheetOffset(offsetY[, offsetX])` _macOS_ @@ -1341,8 +1120,9 @@ Changes the attachment point for sheets on macOS. By default, sheets are attached just below the window frame, but you may want to display them beneath a HTML-rendered toolbar. For example: -```javascript +```js const { BrowserWindow } = require('electron') + const win = new BrowserWindow() const toolbarRect = document.getElementById('toolbar').getBoundingClientRect() @@ -1351,40 +1131,49 @@ win.setSheetOffset(toolbarRect.height) #### `win.flashFrame(flag)` -* `flag` Boolean +<!-- +```YAML history +changes: + - pr-url: https://github.com/electron/electron/pull/41391 + description: "`window.flashFrame(bool)` will flash dock icon continuously on macOS" + breaking-changes-header: behavior-changed-windowflashframebool-will-flash-dock-icon-continuously-on-macos +``` +--> + +* `flag` boolean Starts or stops flashing the window to attract user's attention. -#### `win.setSkipTaskbar(skip)` +#### `win.setSkipTaskbar(skip)` _macOS_ _Windows_ -* `skip` Boolean +* `skip` boolean Makes the window not show in the taskbar. #### `win.setKiosk(flag)` -* `flag` Boolean +* `flag` boolean Enters or leaves kiosk mode. #### `win.isKiosk()` -Returns `Boolean` - Whether the window is in kiosk mode. +Returns `boolean` - Whether the window is in kiosk mode. #### `win.isTabletMode()` _Windows_ -Returns `Boolean` - Whether the window is in Windows 10 tablet mode. +Returns `boolean` - Whether the window is in Windows 10 tablet mode. Since Windows 10 users can [use their PC as tablet](https://support.microsoft.com/en-us/help/17210/windows-10-use-your-pc-like-a-tablet), under this mode apps can choose to optimize their UI for tablets, such as enlarging the titlebar and hiding titlebar buttons. This API returns whether the window is in tablet mode, and the `resize` event -can be be used to listen to changes to tablet mode. +can be used to listen to changes to tablet mode. #### `win.getMediaSourceId()` -Returns `String` - Window id in the format of DesktopCapturerSource's id. For example "window:1234:0". +Returns `string` - Window id in the format of DesktopCapturerSource's id. For example "window:1324:0". More precisely the format is `window:id:other_id` where `id` is `HWND` on Windows, `CGWindowID` (`uint64_t`) on macOS and `Window` (`unsigned long`) on @@ -1402,6 +1191,8 @@ The native type of the handle is `HWND` on Windows, `NSView*` on macOS, and * `message` Integer * `callback` Function + * `wParam` Buffer - The `wParam` provided to the WndProc + * `lParam` Buffer - The `lParam` provided to the WndProc Hooks a windows message. The `callback` is called when the message is received in the WndProc. @@ -1410,7 +1201,7 @@ the message is received in the WndProc. * `message` Integer -Returns `Boolean` - `true` or `false` depending on whether the message is hooked. +Returns `boolean` - `true` or `false` depending on whether the message is hooked. #### `win.unhookWindowMessage(message)` _Windows_ @@ -1424,51 +1215,55 @@ Unhooks all of the window messages. #### `win.setRepresentedFilename(filename)` _macOS_ -* `filename` String +* `filename` string Sets the pathname of the file the window represents, and the icon of the file will show in window's title bar. #### `win.getRepresentedFilename()` _macOS_ -Returns `String` - The pathname of the file the window represents. +Returns `string` - The pathname of the file the window represents. #### `win.setDocumentEdited(edited)` _macOS_ -* `edited` Boolean +* `edited` boolean Specifies whether the window’s document has been edited, and the icon in title bar will become gray when set to `true`. #### `win.isDocumentEdited()` _macOS_ -Returns `Boolean` - Whether the window's document has been edited. +Returns `boolean` - Whether the window's document has been edited. #### `win.focusOnWebView()` #### `win.blurWebView()` -#### `win.capturePage([rect])` +#### `win.capturePage([rect, opts])` * `rect` [Rectangle](structures/rectangle.md) (optional) - The bounds to capture +* `opts` Object (optional) + * `stayHidden` boolean (optional) - Keep the page hidden instead of visible. Default is `false`. + * `stayAwake` boolean (optional) - Keep the system awake instead of allowing it to sleep. Default is `false`. Returns `Promise<NativeImage>` - Resolves with a [NativeImage](native-image.md) -Captures a snapshot of the page within `rect`. Omitting `rect` will capture the whole visible page. +Captures a snapshot of the page within `rect`. Omitting `rect` will capture the whole visible page. If the page is not visible, `rect` may be empty. The page is considered visible when its browser window is hidden and the capturer count is non-zero. If you would like the page to stay hidden, you should ensure that `stayHidden` is set to true. #### `win.loadURL(url[, options])` -* `url` String +* `url` string * `options` Object (optional) - * `httpReferrer` (String | [Referrer](structures/referrer.md)) (optional) - An HTTP Referrer URL. - * `userAgent` String (optional) - A user agent originating the request. - * `extraHeaders` String (optional) - Extra headers separated by "\n" - * `postData` ([UploadRawData[]](structures/upload-raw-data.md) | [UploadFile[]](structures/upload-file.md)) (optional) - * `baseURLForDataURL` String (optional) - Base URL (with trailing path separator) for files to be loaded by the data URL. This is needed only if the specified `url` is a data URL and needs to load other files. + * `httpReferrer` (string | [Referrer](structures/referrer.md)) (optional) - An HTTP Referrer URL. + * `userAgent` string (optional) - A user agent originating the request. + * `extraHeaders` string (optional) - Extra headers separated by "\n" + * `postData` ([UploadRawData](structures/upload-raw-data.md) | [UploadFile](structures/upload-file.md))[] (optional) + * `baseURLForDataURL` string (optional) - Base URL (with trailing path separator) for files to be loaded by the data URL. This is needed only if the specified `url` is a data URL and needs to load other files. Returns `Promise<void>` - the promise will resolve when the page has finished loading (see [`did-finish-load`](web-contents.md#event-did-finish-load)), and rejects -if the page fails to load (see [`did-fail-load`](web-contents.md#event-did-fail-load)). +if the page fails to load (see +[`did-fail-load`](web-contents.md#event-did-fail-load)). A noop rejection handler is already attached, which avoids unhandled rejection errors. If the existing page has a beforeUnload handler, [`did-fail-load`](web-contents.md#event-did-fail-load) will be called unless [`will-prevent-unload`](web-contents.md#event-did-fail-load) is handled. Same as [`webContents.loadURL(url[, options])`](web-contents.md#contentsloadurlurl-options). @@ -1479,11 +1274,15 @@ To ensure that file URLs are properly formatted, it is recommended to use Node's [`url.format`](https://nodejs.org/api/url.html#url_url_format_urlobject) method: -```javascript -const url = require('url').format({ +```js +const { BrowserWindow } = require('electron') + +const win = new BrowserWindow() + +const url = require('node:url').format({ protocol: 'file', slashes: true, - pathname: require('path').join(__dirname, 'index.html') + pathname: require('node:path').join(__dirname, 'index.html') }) win.loadURL(url) @@ -1492,7 +1291,11 @@ win.loadURL(url) You can load a URL using a `POST` request with URL-encoded data by doing the following: -```javascript +```js +const { BrowserWindow } = require('electron') + +const win = new BrowserWindow() + win.loadURL('http://localhost:8000/post', { postData: [{ type: 'rawData', @@ -1504,11 +1307,11 @@ win.loadURL('http://localhost:8000/post', { #### `win.loadFile(filePath[, options])` -* `filePath` String +* `filePath` string * `options` Object (optional) - * `query` Record<String, String> (optional) - Passed to `url.format()`. - * `search` String (optional) - Passed to `url.format()`. - * `hash` String (optional) - Passed to `url.format()`. + * `query` Record\<string, string\> (optional) - Passed to `url.format()`. + * `search` string (optional) - Passed to `url.format()`. + * `hash` string (optional) - Passed to `url.format()`. Returns `Promise<void>` - the promise will resolve when the page has finished loading (see [`did-finish-load`](web-contents.md#event-did-finish-load)), and rejects @@ -1536,9 +1339,9 @@ Remove the window's menu bar. * `progress` Double * `options` Object (optional) - * `mode` String _Windows_ - Mode for the progress bar. Can be `none`, `normal`, `indeterminate`, `error` or `paused`. + * `mode` string _Windows_ - Mode for the progress bar. Can be `none`, `normal`, `indeterminate`, `error` or `paused`. -Sets progress value in progress bar. Valid range is [0, 1.0]. +Sets progress value in progress bar. Valid range is \[0, 1.0]. Remove progress bar when progress < 0; Change to indeterminate mode when progress > 1. @@ -1556,32 +1359,39 @@ mode set (but with a value within the valid range), `normal` will be assumed. * `overlay` [NativeImage](native-image.md) | null - the icon to display on the bottom right corner of the taskbar icon. If this parameter is `null`, the overlay is cleared -* `description` String - a description that will be provided to Accessibility +* `description` string - a description that will be provided to Accessibility screen readers Sets a 16 x 16 pixel overlay onto the current taskbar icon, usually used to convey some sort of application status or to passively notify the user. +#### `win.invalidateShadow()` _macOS_ + +Invalidates the window shadow so that it is recomputed based on the current window shape. + +`BrowserWindows` that are transparent can sometimes leave behind visual artifacts on macOS. +This method can be used to clear these artifacts when, for example, performing an animation. + #### `win.setHasShadow(hasShadow)` -* `hasShadow` Boolean +* `hasShadow` boolean Sets whether the window should have a shadow. #### `win.hasShadow()` -Returns `Boolean` - Whether the window has a shadow. +Returns `boolean` - Whether the window has a shadow. #### `win.setOpacity(opacity)` _Windows_ _macOS_ -* `opacity` Number - between 0.0 (fully transparent) and 1.0 (fully opaque) +* `opacity` number - between 0.0 (fully transparent) and 1.0 (fully opaque) Sets the opacity of the window. On Linux, does nothing. Out of bound number -values are clamped to the [0, 1] range. +values are clamped to the \[0, 1] range. #### `win.getOpacity()` -Returns `Number` - between 0.0 (fully transparent) and 1.0 (fully opaque). On +Returns `number` - between 0.0 (fully transparent) and 1.0 (fully opaque). On Linux, always returns 1. #### `win.setShape(rects)` _Windows_ _Linux_ _Experimental_ @@ -1599,10 +1409,10 @@ whatever is behind the window. * `buttons` [ThumbarButton[]](structures/thumbar-button.md) -Returns `Boolean` - Whether the buttons were added successfully +Returns `boolean` - Whether the buttons were added successfully Add a thumbnail toolbar with a specified set of buttons to the thumbnail image -of a window in a taskbar button layout. Returns a `Boolean` object indicates +of a window in a taskbar button layout. Returns a `boolean` object indicates whether the thumbnail has been added successfully. The number of buttons in thumbnail toolbar should be no greater than 7 due to @@ -1616,11 +1426,11 @@ The `buttons` is an array of `Button` objects: * `icon` [NativeImage](native-image.md) - The icon showing in thumbnail toolbar. * `click` Function - * `tooltip` String (optional) - The text of the button's tooltip. - * `flags` String[] (optional) - Control specific states and behaviors of the + * `tooltip` string (optional) - The text of the button's tooltip. + * `flags` string[] (optional) - Control specific states and behaviors of the button. By default, it is `['enabled']`. -The `flags` is an array that can include following `String`s: +The `flags` is an array that can include following `string`s: * `enabled` - The button is active and available to the user. * `disabled` - The button is disabled. It is present, but has a visual state @@ -1644,7 +1454,7 @@ the entire window by specifying an empty region: #### `win.setThumbnailToolTip(toolTip)` _Windows_ -* `toolTip` String +* `toolTip` string Sets the toolTip that is displayed when hovering over the window thumbnail in the taskbar. @@ -1652,18 +1462,60 @@ in the taskbar. #### `win.setAppDetails(options)` _Windows_ * `options` Object - * `appId` String (optional) - Window's [App User Model ID](https://msdn.microsoft.com/en-us/library/windows/desktop/dd391569(v=vs.85).aspx). + * `appId` string (optional) - Window's [App User Model ID](https://learn.microsoft.com/en-us/windows/win32/shell/appids). It has to be set, otherwise the other options will have no effect. - * `appIconPath` String (optional) - Window's [Relaunch Icon](https://msdn.microsoft.com/en-us/library/windows/desktop/dd391573(v=vs.85).aspx). + * `appIconPath` string (optional) - Window's [Relaunch Icon](https://learn.microsoft.com/en-us/windows/win32/properties/props-system-appusermodel-relaunchiconresource). * `appIconIndex` Integer (optional) - Index of the icon in `appIconPath`. Ignored when `appIconPath` is not set. Default is `0`. - * `relaunchCommand` String (optional) - Window's [Relaunch Command](https://msdn.microsoft.com/en-us/library/windows/desktop/dd391571(v=vs.85).aspx). - * `relaunchDisplayName` String (optional) - Window's [Relaunch Display Name](https://msdn.microsoft.com/en-us/library/windows/desktop/dd391572(v=vs.85).aspx). + * `relaunchCommand` string (optional) - Window's [Relaunch Command](https://learn.microsoft.com/en-us/windows/win32/properties/props-system-appusermodel-relaunchcommand). + * `relaunchDisplayName` string (optional) - Window's [Relaunch Display Name](https://learn.microsoft.com/en-us/windows/win32/properties/props-system-appusermodel-relaunchdisplaynameresource). Sets the properties for the window's taskbar button. -**Note:** `relaunchCommand` and `relaunchDisplayName` must always be set -together. If one of those properties is not set, then neither will be used. +> [!NOTE] +> `relaunchCommand` and `relaunchDisplayName` must always be set +> together. If one of those properties is not set, then neither will be used. + +#### `win.setAccentColor(accentColor)` _Windows_ + +* `accentColor` boolean | string | null - The accent color for the window. By default, follows user preference in System Settings. To reset to system default, pass `null`. + +Sets the system accent color and highlighting of active window border. + +The `accentColor` parameter accepts the following values: + +* **Color string** - Like `true`, but sets a custom accent color using standard CSS color formats (Hex, RGB, RGBA, HSL, HSLA, or named colors). Alpha values in RGBA/HSLA formats are ignored and the color is treated as fully opaque. +* **`true`** - Enable accent color highlighting for the window with the system accent color regardless of whether accent colors are enabled for windows in System `Settings.` +* **`false`** - Disable accent color highlighting for the window regardless of whether accent colors are currently enabled for windows in System Settings. +* **`null`** - Reset window accent color behavior to follow behavior set in System Settings. + +Examples: + +```js +const win = new BrowserWindow({ frame: false }) + +// Set red accent color. +win.setAccentColor('#ff0000') + +// RGB format (alpha ignored if present). +win.setAccentColor('rgba(255,0,0,0.5)') + +// Enable accent color, using the color specified in System Settings. +win.setAccentColor(true) + +// Disable accent color. +win.setAccentColor(false) + +// Reset window accent color behavior to follow behavior set in System Settings. +win.setAccentColor(null) +``` + +#### `win.getAccentColor()` _Windows_ + +Returns `string | boolean` - the system accent color and highlighting of active window border in Hex RGB format. + +If a color has been set for the window that differs from the system accent color, the window accent color will +be returned. Otherwise, a boolean will be returned, with `true` indicating that the window uses the global system accent color, and `false` indicating that accent color highlighting is disabled for this window. #### `win.showDefinitionForSelection()` _macOS_ @@ -1671,63 +1523,77 @@ Same as `webContents.showDefinitionForSelection()`. #### `win.setIcon(icon)` _Windows_ _Linux_ -* `icon` [NativeImage](native-image.md) | String +* `icon` [NativeImage](native-image.md) | string Changes window icon. #### `win.setWindowButtonVisibility(visible)` _macOS_ -* `visible` Boolean +* `visible` boolean Sets whether the window traffic light buttons should be visible. -This cannot be called when `titleBarStyle` is set to `customButtonsOnHover`. +#### `win.setAutoHideMenuBar(hide)` _Windows_ _Linux_ -#### `win.setAutoHideMenuBar(hide)` - -* `hide` Boolean +* `hide` boolean Sets whether the window menu bar should hide itself automatically. Once set the menu bar will only show when users press the single `Alt` key. If the menu bar is already visible, calling `setAutoHideMenuBar(true)` won't hide it immediately. -#### `win.isMenuBarAutoHide()` +#### `win.isMenuBarAutoHide()` _Windows_ _Linux_ -Returns `Boolean` - Whether menu bar automatically hides itself. +Returns `boolean` - Whether menu bar automatically hides itself. #### `win.setMenuBarVisibility(visible)` _Windows_ _Linux_ -* `visible` Boolean +* `visible` boolean Sets whether the menu bar should be visible. If the menu bar is auto-hide, users can still bring up the menu bar by pressing the single `Alt` key. -#### `win.isMenuBarVisible()` +#### `win.isMenuBarVisible()` _Windows_ _Linux_ + +Returns `boolean` - Whether the menu bar is visible. + +#### `win.isSnapped()` _Windows_ -Returns `Boolean` - Whether the menu bar is visible. +Returns `boolean` - whether the window is arranged via [Snap.](https://support.microsoft.com/en-us/windows/snap-your-windows-885a9b1e-a983-a3b1-16cd-c531795e6241) -#### `win.setVisibleOnAllWorkspaces(visible[, options])` +The window is snapped via buttons shown when the mouse is hovered over window +maximize button, or by dragging it to the edges of the screen. -* `visible` Boolean +#### `win.setVisibleOnAllWorkspaces(visible[, options])` _macOS_ _Linux_ + +* `visible` boolean * `options` Object (optional) - * `visibleOnFullScreen` Boolean (optional) _macOS_ - Sets whether - the window should be visible above fullscreen windows + * `visibleOnFullScreen` boolean (optional) _macOS_ - Sets whether + the window should be visible above fullscreen windows. + * `skipTransformProcessType` boolean (optional) _macOS_ - Calling + setVisibleOnAllWorkspaces will by default transform the process + type between UIElementApplication and ForegroundApplication to + ensure the correct behavior. However, this will hide the window + and dock for a short time every time it is called. If your window + is already of type UIElementApplication, you can bypass this + transformation by passing true to skipTransformProcessType. Sets whether the window should be visible on all workspaces. -**Note:** This API does nothing on Windows. +> [!NOTE] +> This API does nothing on Windows. -#### `win.isVisibleOnAllWorkspaces()` +#### `win.isVisibleOnAllWorkspaces()` _macOS_ _Linux_ -Returns `Boolean` - Whether the window is visible on all workspaces. +Returns `boolean` - Whether the window is visible on all workspaces. -**Note:** This API always returns false on Windows. +> [!NOTE] +> This API always returns false on Windows. #### `win.setIgnoreMouseEvents(ignore[, options])` -* `ignore` Boolean +* `ignore` boolean * `options` Object (optional) - * `forward` Boolean (optional) _macOS_ _Windows_ - If true, forwards mouse move + * `forward` boolean (optional) _macOS_ _Windows_ - If true, forwards mouse move messages to Chromium, enabling mouse related events such as `mouseleave`. Only used when `ignore` is true. If `ignore` is false, forwarding is always disabled regardless of this value. @@ -1740,23 +1606,38 @@ events. #### `win.setContentProtection(enable)` _macOS_ _Windows_ -* `enable` Boolean +* `enable` boolean Prevents the window contents from being captured by other apps. -On macOS it sets the NSWindow's sharingType to NSWindowSharingNone. -On Windows it calls SetWindowDisplayAffinity with `WDA_EXCLUDEFROMCAPTURE`. +On Windows, it calls [`SetWindowDisplayAffinity`](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowdisplayaffinity) with `WDA_EXCLUDEFROMCAPTURE`. For Windows 10 version 2004 and up the window will be removed from capture entirely, older Windows versions behave as if `WDA_MONITOR` is applied capturing a black window. +On macOS, it sets the `NSWindow`'s +[`sharingType`](https://developer.apple.com/documentation/appkit/nswindow/sharingtype-swift.property?language=objc) +to +[`NSWindowSharingNone`](https://developer.apple.com/documentation/appkit/nswindow/sharingtype-swift.enum/none?language=objc). +Unfortunately, due to an intentional change in macOS, newer Mac applications that use +`ScreenCaptureKit` will capture your window despite `win.setContentProtection(true)`. +See [here](https://github.com/electron/electron/issues/48258#issuecomment-3269893618). + +#### `win.isContentProtected()` _macOS_ _Windows_ + +Returns `boolean` - whether or not content protection is currently enabled. + #### `win.setFocusable(focusable)` _macOS_ _Windows_ -* `focusable` Boolean +* `focusable` boolean Changes whether the window can be focused. On macOS it does not remove the focus from the window. +#### `win.isFocusable()` _macOS_ _Windows_ + +Returns `boolean` - Whether the window can be focused. + #### `win.setParentWindow(parent)` * `parent` BrowserWindow | null @@ -1766,7 +1647,7 @@ current window into a top-level window. #### `win.getParentWindow()` -Returns `BrowserWindow` - The parent window. +Returns `BrowserWindow | null` - The parent window or `null` if there is no parent. #### `win.getChildWindows()` @@ -1774,7 +1655,7 @@ Returns `BrowserWindow[]` - All child windows. #### `win.setAutoHideCursor(autoHide)` _macOS_ -* `autoHide` Boolean +* `autoHide` boolean Controls whether to hide cursor when typing. @@ -1788,6 +1669,10 @@ tabs in the window. Selects the next tab when native tabs are enabled and there are other tabs in the window. +#### `win.showAllTabs()` _macOS_ + +Shows or hides the tab overview when native tabs are enabled. + #### `win.mergeAllWindows()` _macOS_ Merges all windows into one window with multiple tabs when native tabs @@ -1809,28 +1694,45 @@ there is only one tab in the current window. Adds a window as a tab on this window, after the tab for the window instance. -#### `win.setVibrancy(type)` _macOS_ +#### `win.setVibrancy(type[, options])` _macOS_ -* `type` String | null - Can be `appearance-based`, `light`, `dark`, `titlebar`, - `selection`, `menu`, `popover`, `sidebar`, `medium-light`, `ultra-dark`, `header`, `sheet`, `window`, `hud`, `fullscreen-ui`, `tooltip`, `content`, `under-window`, or `under-page`. See +* `type` string | null - Can be `titlebar`, `selection`, `menu`, `popover`, `sidebar`, `header`, `sheet`, `window`, `hud`, `fullscreen-ui`, `tooltip`, `content`, `under-window`, or `under-page`. See the [macOS documentation][vibrancy-docs] for more details. +* `options` Object (optional) + * `animationDuration` number (optional) - if greater than zero, the change to vibrancy will be animated over the given duration (in milliseconds). Adds a vibrancy effect to the browser window. Passing `null` or an empty string -will remove the vibrancy effect on the window. +will remove the vibrancy effect on the window. The `animationDuration` parameter only + animates fading in or fading out the vibrancy effect. Animating between + different types of vibrancy is not supported. + +#### `win.setBackgroundMaterial(material)` _Windows_ + +* `material` string + * `auto` - Let the Desktop Window Manager (DWM) automatically decide the system-drawn backdrop material for this window. This is the default. + * `none` - Don't draw any system backdrop. + * `mica` - Draw the backdrop material effect corresponding to a long-lived window. + * `acrylic` - Draw the backdrop material effect corresponding to a transient window. + * `tabbed` - Draw the backdrop material effect corresponding to a window with a tabbed title bar. -Note that `appearance-based`, `light`, `dark`, `medium-light`, and `ultra-dark` have been -deprecated and will be removed in an upcoming version of macOS. +This method sets the browser window's system-drawn background material, including behind the non-client area. -#### `win.setTrafficLightPosition(position)` _macOS_ +See the [Windows documentation](https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwm_systembackdrop_type) for more details. -* `position` [Point](structures/point.md) +> [!NOTE] +> This method is only supported on Windows 11 22H2 and up. -Set a custom position for the traffic light buttons. Can only be used with `titleBarStyle` set to `hidden`. +#### `win.setWindowButtonPosition(position)` _macOS_ -#### `win.getTrafficLightPosition()` _macOS_ +* `position` [Point](structures/point.md) | null -Returns `Point` - The current position for the traffic light buttons. Can only be used with `titleBarStyle` -set to `hidden`. +Set a custom position for the traffic light buttons in frameless window. +Passing `null` will reset the position to default. + +#### `win.getWindowButtonPosition()` _macOS_ + +Returns `Point | null` - The custom position for the traffic light buttons in +frameless window, `null` will be returned when there is no custom position. #### `win.setTouchBar(touchBar)` _macOS_ @@ -1838,44 +1740,83 @@ set to `hidden`. Sets the touchBar layout for the current window. Specifying `null` or `undefined` clears the touch bar. This method only has an effect if the -machine has a touch bar and is running on macOS 10.12.1+. +machine has a touch bar. -**Note:** The TouchBar API is currently experimental and may change or be -removed in future Electron releases. +> [!NOTE] +> The TouchBar API is currently experimental and may change or be +> removed in future Electron releases. -#### `win.setBrowserView(browserView)` _Experimental_ +#### `win.setBrowserView(browserView)` _Experimental_ _Deprecated_ * `browserView` [BrowserView](browser-view.md) | null - Attach `browserView` to `win`. If there are other `BrowserView`s attached, they will be removed from this window. -#### `win.getBrowserView()` _Experimental_ +> [!WARNING] +> The `BrowserView` class is deprecated, and replaced by the new +> [`WebContentsView`](web-contents-view.md) class. + +#### `win.getBrowserView()` _Experimental_ _Deprecated_ Returns `BrowserView | null` - The `BrowserView` attached to `win`. Returns `null` if one is not attached. Throws an error if multiple `BrowserView`s are attached. -#### `win.addBrowserView(browserView)` _Experimental_ +> [!WARNING] +> The `BrowserView` class is deprecated, and replaced by the new +> [`WebContentsView`](web-contents-view.md) class. + +#### `win.addBrowserView(browserView)` _Experimental_ _Deprecated_ * `browserView` [BrowserView](browser-view.md) Replacement API for setBrowserView supporting work with multi browser views. -#### `win.removeBrowserView(browserView)` _Experimental_ +> [!WARNING] +> The `BrowserView` class is deprecated, and replaced by the new +> [`WebContentsView`](web-contents-view.md) class. + +#### `win.removeBrowserView(browserView)` _Experimental_ _Deprecated_ * `browserView` [BrowserView](browser-view.md) -#### `win.getBrowserViews()` _Experimental_ +> [!WARNING] +> The `BrowserView` class is deprecated, and replaced by the new +> [`WebContentsView`](web-contents-view.md) class. + +#### `win.setTopBrowserView(browserView)` _Experimental_ _Deprecated_ + +* `browserView` [BrowserView](browser-view.md) + +Raises `browserView` above other `BrowserView`s attached to `win`. +Throws an error if `browserView` is not attached to `win`. + +> [!WARNING] +> The `BrowserView` class is deprecated, and replaced by the new +> [`WebContentsView`](web-contents-view.md) class. + +#### `win.getBrowserViews()` _Experimental_ _Deprecated_ + +Returns `BrowserView[]` - a sorted by z-index array of all BrowserViews that have been attached +with `addBrowserView` or `setBrowserView`. The top-most BrowserView is the last element of the array. + +> [!WARNING] +> The `BrowserView` class is deprecated, and replaced by the new +> [`WebContentsView`](web-contents-view.md) class. + +#### `win.setTitleBarOverlay(options)` _Windows_ _Linux_ + +* `options` Object + * `color` String (optional) - The CSS color of the Window Controls Overlay when enabled. + * `symbolColor` String (optional) - The CSS color of the symbols on the Window Controls Overlay when enabled. + * `height` Integer (optional) - The height of the title bar and Window Controls Overlay in pixels. -Returns `BrowserView[]` - an array of all BrowserViews that have been attached -with `addBrowserView` or `setBrowserView`. +On a window with Window Controls Overlay already enabled, this method updates the style of the title bar overlay. -**Note:** The BrowserView API is currently experimental and may change or be -removed in future Electron releases. +On Linux, the `symbolColor` is automatically calculated to have minimum accessible contrast to the `color` if not explicitly set. -[runtime-enabled-features]: https://cs.chromium.org/chromium/src/third_party/blink/renderer/platform/runtime_enabled_features.json5?l=70 [page-visibility-api]: https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API [quick-look]: https://en.wikipedia.org/wiki/Quick_Look [vibrancy-docs]: https://developer.apple.com/documentation/appkit/nsvisualeffectview?preferredLanguage=objc [window-levels]: https://developer.apple.com/documentation/appkit/nswindow/level -[chrome-content-scripts]: https://developer.chrome.com/extensions/content_scripts#execution-environment [event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter +[window-session-end-event]:../api/structures/window-session-end-event.md diff --git a/docs/api/client-request.md b/docs/api/client-request.md index 865f733d78474..0205346319d05 100644 --- a/docs/api/client-request.md +++ b/docs/api/client-request.md @@ -2,52 +2,73 @@ > Make HTTP/HTTPS requests. -Process: [Main](../glossary.md#main-process) +Process: [Main](../glossary.md#main-process), [Utility](../glossary.md#utility-process)<br /> +_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ `ClientRequest` implements the [Writable Stream](https://nodejs.org/api/stream.html#stream_writable_streams) interface and is therefore an [EventEmitter][event-emitter]. ### `new ClientRequest(options)` -* `options` (Object | String) - If `options` is a String, it is interpreted as +* `options` (Object | string) - If `options` is a string, it is interpreted as the request URL. If it is an object, it is expected to fully specify an HTTP request via the following properties: - * `method` String (optional) - The HTTP request method. Defaults to the GET + * `method` string (optional) - The HTTP request method. Defaults to the GET method. - * `url` String (optional) - The request URL. Must be provided in the absolute + * `url` string (optional) - The request URL. Must be provided in the absolute form with the protocol scheme specified as http or https. + * `headers` Record\<string, string | string[]\> (optional) - Headers to be sent + with the request. * `session` Session (optional) - The [`Session`](session.md) instance with which the request is associated. - * `partition` String (optional) - The name of the [`partition`](session.md) + * `partition` string (optional) - The name of the [`partition`](session.md) with which the request is associated. Defaults to the empty string. The `session` option supersedes `partition`. Thus if a `session` is explicitly specified, `partition` is ignored. - * `credentials` String (optional) - Can be `include` or `omit`. Whether to - send [credentials](https://fetch.spec.whatwg.org/#credentials) with this + * `bypassCustomProtocolHandlers` boolean (optional) - When set to `true`, + custom protocol handlers registered for the request's URL scheme will not be + called. This allows forwarding an intercepted request to the built-in + handler. [webRequest](web-request.md) handlers will still be triggered + when bypassing custom protocols. Defaults to `false`. + * `credentials` string (optional) - Can be `include`, `omit` or + `same-origin`. Whether to send + [credentials](https://fetch.spec.whatwg.org/#credentials) with this request. If set to `include`, credentials from the session associated with the request will be used. If set to `omit`, credentials will not be sent with the request (and the `'login'` event will not be triggered in the - event of a 401). This matches the behavior of the + event of a 401). If set to `same-origin`, `origin` must also be specified. + This matches the behavior of the [fetch](https://fetch.spec.whatwg.org/#concept-request-credentials-mode) option of the same name. If this option is not specified, authentication data from the session will be sent, and cookies will not be sent (unless `useSessionCookies` is set). - * `useSessionCookies` Boolean (optional) - Whether to send cookies with this + * `useSessionCookies` boolean (optional) - Whether to send cookies with this request from the provided session. If `credentials` is specified, this option has no effect. Default is `false`. - * `protocol` String (optional) - Can be `http:` or `https:`. The protocol + * `protocol` string (optional) - Can be `http:` or `https:`. The protocol scheme in the form 'scheme:'. Defaults to 'http:'. - * `host` String (optional) - The server host provided as a concatenation of + * `host` string (optional) - The server host provided as a concatenation of the hostname and the port number 'hostname:port'. - * `hostname` String (optional) - The server host name. + * `hostname` string (optional) - The server host name. * `port` Integer (optional) - The server's listening port number. - * `path` String (optional) - The path part of the request URL. - * `redirect` String (optional) - Can be `follow`, `error` or `manual`. The + * `path` string (optional) - The path part of the request URL. + * `redirect` string (optional) - Can be `follow`, `error` or `manual`. The redirect mode for this request. When mode is `error`, any redirection will be aborted. When mode is `manual` the redirection will be cancelled unless [`request.followRedirect`](#requestfollowredirect) is invoked synchronously during the [`redirect`](#event-redirect) event. Defaults to `follow`. - * `origin` String (optional) - The origin URL of the request. + * `origin` string (optional) - The origin URL of the request. + * `referrerPolicy` string (optional) - can be "", `no-referrer`, + `no-referrer-when-downgrade`, `origin`, `origin-when-cross-origin`, + `unsafe-url`, `same-origin`, `strict-origin`, or + `strict-origin-when-cross-origin`. Defaults to + `strict-origin-when-cross-origin`. + * `cache` string (optional) - can be `default`, `no-store`, `reload`, + `no-cache`, `force-cache` or `only-if-cached`. + * `priority` string (optional) - can be `throttled`, `idle`, `lowest`, + `low`, `medium`, or `highest`. Defaults to `idle`. + * `priorityIncremental` boolean (optional) - the incremental loading flag as part + of HTTP extensible priorities (RFC 9218). Default is `true`. `options` properties such as `protocol`, `host`, `hostname`, `port` and `path` strictly follow the Node.js model as described in the @@ -55,7 +76,7 @@ strictly follow the Node.js model as described in the For instance, we could have created the same request to 'github.com' as follows: -```JavaScript +```js const request = net.request({ method: 'GET', protocol: 'https:', @@ -71,30 +92,30 @@ const request = net.request({ Returns: -* `response` IncomingMessage - An object representing the HTTP response message. +* `response` [IncomingMessage](incoming-message.md) - An object representing the HTTP response message. #### Event: 'login' Returns: * `authInfo` Object - * `isProxy` Boolean - * `scheme` String - * `host` String + * `isProxy` boolean + * `scheme` string + * `host` string * `port` Integer - * `realm` String + * `realm` string * `callback` Function - * `username` String (optional) - * `password` String (optional) + * `username` string (optional) + * `password` string (optional) Emitted when an authenticating proxy is asking for user credentials. The `callback` function is expected to be called back with user credentials: -* `username` String -* `password` String +* `username` string +* `password` string -```JavaScript +```js @ts-type={request:Electron.ClientRequest} request.on('login', (authInfo, callback) => { callback('username', 'password') }) @@ -103,9 +124,9 @@ request.on('login', (authInfo, callback) => { Providing empty credentials will cancel the request and report an authentication error on the response object: -```JavaScript +```js @ts-type={request:Electron.ClientRequest} request.on('response', (response) => { - console.log(`STATUS: ${response.statusCode}`); + console.log(`STATUS: ${response.statusCode}`) response.on('error', (error) => { console.log(`ERROR: ${JSON.stringify(error)}`) }) @@ -146,9 +167,9 @@ event indicates that no more events will be emitted on either the `request` or Returns: * `statusCode` Integer -* `method` String -* `redirectUrl` String -* `responseHeaders` Record<String, String[]> +* `method` string +* `redirectUrl` string +* `responseHeaders` Record\<string, string[]\> Emitted when the server returns a redirect response (e.g. 301 Moved Permanently). Calling [`request.followRedirect`](#requestfollowredirect) will @@ -160,7 +181,7 @@ continue with the redirection. If this event is handled, #### `request.chunkedEncoding` -A `Boolean` specifying whether the request will use HTTP chunked transfer encoding +A `boolean` specifying whether the request will use HTTP chunked transfer encoding or not. Defaults to false. The property is readable and writable, however it can be set only before the first write operation as the HTTP headers are not yet put on the wire. Trying to set the `chunkedEncoding` property after the first write @@ -174,17 +195,17 @@ internally buffered inside Electron process memory. #### `request.setHeader(name, value)` -* `name` String - An extra HTTP header name. -* `value` String - An extra HTTP header value. +* `name` string - An extra HTTP header name. +* `value` string - An extra HTTP header value. Adds an extra HTTP header. The header name will be issued as-is without lowercasing. It can be called only before first write. Calling this method after -the first write will throw an error. If the passed value is not a `String`, its +the first write will throw an error. If the passed value is not a `string`, its `toString()` method will be called to obtain the final value. Certain headers are restricted from being set by apps. These headers are listed below. More information on restricted headers can be found in -[Chromium's header utils](https://source.chromium.org/chromium/chromium/src/+/master:services/network/public/cpp/header_util.cc;drc=1562cab3f1eda927938f8f4a5a91991fefde66d3;bpv=1;bpt=1;l=22). +[Chromium's header utils](https://source.chromium.org/chromium/chromium/src/+/main:services/network/public/cpp/header_util.cc;drc=1562cab3f1eda927938f8f4a5a91991fefde66d3;bpv=1;bpt=1;l=22). * `Content-Length` * `Host` @@ -198,22 +219,22 @@ Additionally, setting the `Connection` header to the value `upgrade` is also dis #### `request.getHeader(name)` -* `name` String - Specify an extra header name. +* `name` string - Specify an extra header name. -Returns `String` - The value of a previously set extra header name. +Returns `string` - The value of a previously set extra header name. #### `request.removeHeader(name)` -* `name` String - Specify an extra header name. +* `name` string - Specify an extra header name. Removes a previously set extra header name. This method can be called only before first write. Trying to call it after the first write will throw an error. #### `request.write(chunk[, encoding][, callback])` -* `chunk` (String | Buffer) - A chunk of the request body's data. If it is a +* `chunk` (string | Buffer) - A chunk of the request body's data. If it is a string, it is converted into a Buffer using the specified encoding. -* `encoding` String (optional) - Used to convert string chunks into Buffer +* `encoding` string (optional) - Used to convert string chunks into Buffer objects. Defaults to 'utf-8'. * `callback` Function (optional) - Called after the write operation ends. @@ -229,10 +250,12 @@ it is not allowed to add or remove a custom header. #### `request.end([chunk][, encoding][, callback])` -* `chunk` (String | Buffer) (optional) -* `encoding` String (optional) +* `chunk` (string | Buffer) (optional) +* `encoding` string (optional) * `callback` Function (optional) +Returns `this`. + Sends the last chunk of the request data. Subsequent write or end operations will not be allowed. The `finish` event is emitted just after the end operation. @@ -241,7 +264,7 @@ will not be allowed. The `finish` event is emitted just after the end operation. Cancels an ongoing HTTP transaction. If the request has already emitted the `close` event, the abort operation will have no effect. Otherwise an ongoing event will emit `abort` and `close` events. Additionally, if there is an ongoing -response object,it will emit the `aborted` event. +response object, it will emit the `aborted` event. #### `request.followRedirect()` @@ -252,9 +275,9 @@ event. Returns `Object`: -* `active` Boolean - Whether the request is currently active. If this is false +* `active` boolean - Whether the request is currently active. If this is false no other properties will be set -* `started` Boolean - Whether the upload has started. If this is false both +* `started` boolean - Whether the upload has started. If this is false both `current` and `total` will be set to 0. * `current` Integer - The number of bytes that have been uploaded so far * `total` Integer - The number of bytes that will be uploaded this request diff --git a/docs/api/clipboard.md b/docs/api/clipboard.md index 1a673260bd166..c64ddf355b158 100644 --- a/docs/api/clipboard.md +++ b/docs/api/clipboard.md @@ -1,16 +1,34 @@ # clipboard +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/48877 + description: "Using the `clipboard` API directly in the renderer process is deprecated." + breaking-changes-header: deprecated-clipboard-api-access-from-renderer-processes +``` +--> + > Perform copy and paste operations on the system clipboard. -Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process) +Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process) _Deprecated_ (non-sandboxed only) + +> [!NOTE] +> Using the `clipboard` API from the renderer process is deprecated. + +> [!IMPORTANT] +> If you want to call this API from a renderer process, +> place the API call in your preload script and +> [expose](../tutorial/context-isolation.md#after-context-isolation-enabled) it using the +> [`contextBridge`](context-bridge.md) API. On Linux, there is also a `selection` clipboard. To manipulate it you need to pass `selection` to each method: -```javascript +```js const { clipboard } = require('electron') -clipboard.writeText('Example String', 'selection') +clipboard.writeText('Example string', 'selection') console.log(clipboard.readText('selection')) ``` @@ -18,13 +36,14 @@ console.log(clipboard.readText('selection')) The `clipboard` module has the following methods: -**Note:** Experimental APIs are marked as such and could be removed in future. +> [!NOTE] +> Experimental APIs are marked as such and could be removed in future. ### `clipboard.readText([type])` -* `type` String (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux. +* `type` string (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux. -Returns `String` - The content in the clipboard as plain text. +Returns `string` - The content in the clipboard as plain text. ```js const { clipboard } = require('electron') @@ -38,8 +57,8 @@ console.log(text) ### `clipboard.writeText(text[, type])` -* `text` String -* `type` String (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux. +* `text` string +* `type` string (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux. Writes the `text` into the clipboard as plain text. @@ -52,9 +71,9 @@ clipboard.writeText(text) ### `clipboard.readHTML([type])` -* `type` String (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux. +* `type` string (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux. -Returns `String` - The content in the clipboard as markup. +Returns `string` - The content in the clipboard as markup. ```js const { clipboard } = require('electron') @@ -68,35 +87,35 @@ console.log(html) ### `clipboard.writeHTML(markup[, type])` -* `markup` String -* `type` String (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux. +* `markup` string +* `type` string (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux. Writes `markup` to the clipboard. ```js const { clipboard } = require('electron') -clipboard.writeHTML('<b>Hi</b') +clipboard.writeHTML('<b>Hi</b>') ``` ### `clipboard.readImage([type])` -* `type` String (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux. +* `type` string (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux. Returns [`NativeImage`](native-image.md) - The image content in the clipboard. ### `clipboard.writeImage(image[, type])` * `image` [NativeImage](native-image.md) -* `type` String (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux. +* `type` string (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux. Writes `image` to the clipboard. ### `clipboard.readRTF([type])` -* `type` String (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux. +* `type` string (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux. -Returns `String` - The content in the clipboard as RTF. +Returns `string` - The content in the clipboard as RTF. ```js const { clipboard } = require('electron') @@ -110,8 +129,8 @@ console.log(rtf) ### `clipboard.writeRTF(text[, type])` -* `text` String -* `type` String (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux. +* `text` string +* `type` string (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux. Writes the `text` into the clipboard in RTF. @@ -126,58 +145,56 @@ clipboard.writeRTF(rtf) Returns `Object`: -* `title` String -* `url` String +* `title` string +* `url` string Returns an Object containing `title` and `url` keys representing the bookmark in the clipboard. The `title` and `url` values will be empty strings when the -bookmark is unavailable. +bookmark is unavailable. The `title` value will always be empty on Windows. ### `clipboard.writeBookmark(title, url[, type])` _macOS_ _Windows_ -* `title` String -* `url` String -* `type` String (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux. +* `title` string - Unused on Windows +* `url` string +* `type` string (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux. -Writes the `title` and `url` into the clipboard as a bookmark. +Writes the `title` (macOS only) and `url` into the clipboard as a bookmark. -**Note:** Most apps on Windows don't support pasting bookmarks into them so -you can use `clipboard.write` to write both a bookmark and fallback text to the -clipboard. +> [!NOTE] +> Most apps on Windows don't support pasting bookmarks into them so +> you can use `clipboard.write` to write both a bookmark and fallback text to the +> clipboard. ```js const { clipboard } = require('electron') -clipboard.writeBookmark({ - text: 'https://electronjs.org', - bookmark: 'Electron Homepage' -}) +clipboard.writeBookmark('Electron Homepage', 'https://electronjs.org') ``` ### `clipboard.readFindText()` _macOS_ -Returns `String` - The text on the find pasteboard, which is the pasteboard that holds information about the current state of the active application’s find panel. +Returns `string` - The text on the find pasteboard, which is the pasteboard that holds information about the current state of the active application’s find panel. This method uses synchronous IPC when called from the renderer process. The cached value is reread from the find pasteboard whenever the application is activated. ### `clipboard.writeFindText(text)` _macOS_ -* `text` String +* `text` string Writes the `text` into the find pasteboard (the pasteboard that holds information about the current state of the active application’s find panel) as plain text. This method uses synchronous IPC when called from the renderer process. ### `clipboard.clear([type])` -* `type` String (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux. +* `type` string (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux. Clears the clipboard content. ### `clipboard.availableFormats([type])` -* `type` String (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux. +* `type` string (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux. -Returns `String[]` - An array of supported formats for the clipboard `type`. +Returns `string[]` - An array of supported formats for the clipboard `type`. ```js const { clipboard } = require('electron') @@ -189,28 +206,32 @@ console.log(formats) ### `clipboard.has(format[, type])` _Experimental_ -* `format` String -* `type` String (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux. +* `format` string +* `type` string (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux. -Returns `Boolean` - Whether the clipboard supports the specified `format`. +Returns `boolean` - Whether the clipboard supports the specified `format`. ```js const { clipboard } = require('electron') -const hasFormat = clipboard.has('<p>selection</p>') +const hasFormat = clipboard.has('public/utf8-plain-text') console.log(hasFormat) -// 'true' or 'false +// 'true' or 'false' ``` ### `clipboard.read(format)` _Experimental_ -* `format` String +* `format` string + +Returns `string` - Reads `format` type from the clipboard. -Returns `String` - Reads `format` type from the clipboard. +`format` should contain valid ASCII characters and have `/` separator. +`a/c`, `a/bc` are valid formats while `/abc`, `abc/`, `a/`, `/a`, `a` +are not valid. ### `clipboard.readBuffer(format)` _Experimental_ -* `format` String +* `format` string Returns `Buffer` - Reads `format` type from the clipboard. @@ -218,19 +239,19 @@ Returns `Buffer` - Reads `format` type from the clipboard. const { clipboard } = require('electron') const buffer = Buffer.from('this is binary', 'utf8') -clipboard.writeBuffer('public.utf8-plain-text', buffer) +clipboard.writeBuffer('public/utf8-plain-text', buffer) -const ret = clipboard.readBuffer('public.utf8-plain-text') +const ret = clipboard.readBuffer('public/utf8-plain-text') -console.log(buffer.equals(out)) +console.log(buffer.equals(ret)) // true ``` ### `clipboard.writeBuffer(format, buffer[, type])` _Experimental_ -* `format` String +* `format` string * `buffer` Buffer -* `type` String (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux. +* `type` string (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux. Writes the `buffer` into the clipboard as `format`. @@ -238,18 +259,18 @@ Writes the `buffer` into the clipboard as `format`. const { clipboard } = require('electron') const buffer = Buffer.from('writeBuffer', 'utf8') -clipboard.writeBuffer('public.utf8-plain-text', buffer) +clipboard.writeBuffer('public/utf8-plain-text', buffer) ``` ### `clipboard.write(data[, type])` * `data` Object - * `text` String (optional) - * `html` String (optional) + * `text` string (optional) + * `html` string (optional) * `image` [NativeImage](native-image.md) (optional) - * `rtf` String (optional) - * `bookmark` String (optional) - The title of the URL at `text`. -* `type` String (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux. + * `rtf` string (optional) + * `bookmark` string (optional) - The title of the URL at `text`. +* `type` string (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux. Writes `data` to the clipboard. diff --git a/docs/api/command-line-switches.md b/docs/api/command-line-switches.md index 4d9deec60945c..42b8db00e16de 100644 --- a/docs/api/command-line-switches.md +++ b/docs/api/command-line-switches.md @@ -6,8 +6,9 @@ You can use [app.commandLine.appendSwitch][append-switch] to append them in your app's main script before the [ready][ready] event of the [app][app] module is emitted: -```javascript +```js const { app } = require('electron') + app.commandLine.appendSwitch('remote-debugging-port', '8315') app.commandLine.appendSwitch('host-rules', 'MAP * 127.0.0.1') @@ -38,7 +39,7 @@ Without `*` prefix the URL has to match exactly. ### --disable-ntlm-v2 -Disables NTLM v2 for posix platforms, no effect elsewhere. +Disables NTLM v2 for POSIX platforms, no effect elsewhere. ### --disable-http-cache @@ -48,6 +49,10 @@ Disables the disk cache for HTTP requests. Disable HTTP/2 and SPDY/3.1 protocols. +### --disable-geolocation _macOS_ + +Disables the Geolocation API. Permission requests for geolocation will be denied internally regardless of the decision made by a handler set via `session.setPermissionRequestHandler`. This functionality is currently implemented only for macOS. Has no effect on other platforms. + ### --disable-renderer-backgrounding Prevents Chromium from lowering the priority of invisible pages' renderer @@ -61,26 +66,31 @@ throttling in one window, you can take the hack of Forces the maximum disk space to be used by the disk cache, in bytes. -### --enable-api-filtering-logging +### --enable-logging\[=file] + +Prints Chromium's logging to stderr (or a log file). + +The `ELECTRON_ENABLE_LOGGING` environment variable has the same effect as +passing `--enable-logging`. -Enables caller stack logging for the following APIs (filtering events): +Passing `--enable-logging` will result in logs being printed on stderr. +Passing `--enable-logging=file` will result in logs being saved to the file +specified by `--log-file=...`, or to `electron_debug.log` in the user-data +directory if `--log-file` is not specified. -- `desktopCapturer.getSources()` / `desktop-capturer-get-sources` -- `remote.require()` / `remote-require` -- `remote.getGlobal()` / `remote-get-builtin` -- `remote.getBuiltin()` / `remote-get-global` -- `remote.getCurrentWindow()` / `remote-get-current-window` -- `remote.getCurrentWebContents()` / `remote-get-current-web-contents` +> [!NOTE] +> On Windows, logs from child processes cannot be sent to stderr. +> Logging to a file is the most reliable way to collect logs on Windows. -### --enable-logging +See also `--log-file`, `--log-level`, `--v`, and `--vmodule`. -Prints Chromium's logging into console. +### --force-fieldtrials=`trials` -This switch can not be used in `app.commandLine.appendSwitch` since it is parsed -earlier than user's app is loaded, but you can set the `ELECTRON_ENABLE_LOGGING` -environment variable to achieve the same effect. +Field trials to be forcefully enabled or disabled. -### --host-rules=`rules` +For example: `WebRTC-Audio-Red-For-Opus/Enabled/` + +### --host-rules=`rules` _Deprecated_ A comma-separated list of `rules` that control how hostnames are mapped. @@ -98,9 +108,23 @@ These mappings apply to the endpoint host in a net request (the TCP connect and host resolver in a direct connection, and the `CONNECT` in an HTTP proxy connection, and the endpoint host in a `SOCKS` proxy connection). +**Deprecated:** Use the `--host-resolver-rules` switch instead. + ### --host-resolver-rules=`rules` -Like `--host-rules` but these `rules` only apply to the host resolver. +A comma-separated list of `rules` that control how hostnames are mapped. + +For example: + +* `MAP * 127.0.0.1` Forces all hostnames to be mapped to 127.0.0.1 +* `MAP *.google.com proxy` Forces all google.com subdomains to be resolved to + "proxy". +* `MAP test.com [::1]:77` Forces "test.com" to resolve to IPv6 loopback. Will + also force the port of the resulting socket address to be 77. +* `MAP * baz, EXCLUDE www.google.com` Remaps everything to "baz", except for + "www.google.com". + +These `rules` only apply to the host resolver. ### --ignore-certificate-errors @@ -112,23 +136,56 @@ Ignore the connections limit for `domains` list separated by `,`. ### --js-flags=`flags` -Specifies the flags passed to the Node.js engine. It has to be passed when starting -Electron if you want to enable the `flags` in the main process. +Specifies the flags passed to the [V8 engine](https://v8.dev). In order to enable the `flags` in the main process, +this switch must be passed on startup. ```sh $ electron --js-flags="--harmony_proxies --harmony_collections" your-app ``` -See the [Node.js documentation][node-cli] or run `node --help` in your terminal for a list of available flags. Additionally, run `node --v8-options` to see a list of flags that specifically refer to Node.js's V8 JavaScript engine. +Run `node --v8-options` or `electron --js-flags="--help"` in your terminal for the list of available flags. These can be used to enable early-stage JavaScript features, or log and manipulate garbage collection, among other things. + +For example, to trace V8 optimization and deoptimization: + +```sh +$ electron --js-flags="--trace-opt --trace-deopt" your-app +``` ### --lang Set a custom locale. +### --log-file=`path` + +If `--enable-logging` is specified, logs will be written to the given path. The +parent directory must exist. + +Setting the `ELECTRON_LOG_FILE` environment variable is equivalent to passing +this flag. If both are present, the command-line switch takes precedence. + ### --log-net-log=`path` Enables net log events to be saved and writes them to `path`. +### --log-level=`N` + +Sets the verbosity of logging when used together with `--enable-logging`. +`N` should be one of [Chrome's LogSeverities][severities]. + +Note that two complementary logging mechanisms in Chromium -- `LOG()` +and `VLOG()` -- are controlled by different switches. `--log-level` +controls `LOG()` messages, while `--v` and `--vmodule` control `VLOG()` +messages. So you may want to use a combination of these three switches +depending on the granularity you want and what logging calls are made +by the code you're trying to watch. + +See [Chromium Logging source][logging] for more information on how +`LOG()` and `VLOG()` interact. Loosely speaking, `VLOG()` can be thought +of as sub-levels / per-module levels inside `LOG(INFO)` to control the +firehose of `LOG(INFO)` data. + +See also `--enable-logging`, `--log-level`, `--v`, and `--vmodule`. + ### --no-proxy-server Don't use a proxy server and always make direct connections. Overrides any other @@ -136,9 +193,15 @@ proxy server flags that are passed. ### --no-sandbox -Disables Chromium sandbox, which is now enabled by default. +Disables the Chromium [sandbox](https://www.chromium.org/developers/design-documents/sandbox). +Forces renderer process and Chromium helper processes to run un-sandboxed. Should only be used for testing. +### --no-stdio-init + +Disable stdio initialization during node initialization. +Used to avoid node initialization crash when the nul device is disabled on Windows platform. + ### --proxy-bypass-list=`hosts` Instructs Electron to bypass the proxy server for the given semi-colon-separated @@ -147,8 +210,9 @@ list of hosts. This flag has an effect only if used in tandem with For example: -```javascript +```js const { app } = require('electron') + app.commandLine.appendSwitch('proxy-bypass-list', '<local>;*.google.com;*foo.com;1.2.3.4:5678') ``` @@ -179,6 +243,8 @@ positive values are used for V-logging levels. This switch only works when `--enable-logging` is also passed. +See also `--enable-logging`, `--log-level`, and `--vmodule`. + ### --vmodule=`pattern` Gives the per-module maximal V-logging levels to override the value given by @@ -191,6 +257,8 @@ logging level for all code in the source files under a `foo/bar` directory. This switch only works when `--enable-logging` is also passed. +See also `--enable-logging`, `--log-level`, and `--v`. + ### --force_high_performance_gpu Force using discrete GPU when there are multiple GPUs available. @@ -199,25 +267,39 @@ Force using discrete GPU when there are multiple GPUs available. Force using integrated GPU when there are multiple GPUs available. +### --xdg-portal-required-version=`version` + +Sets the minimum required version of XDG portal implementation to `version` +in order to use the portal backend for file dialogs on linux. File dialogs +will fallback to using gtk or kde depending on the desktop environment when +the required version is unavailable. Current default is set to `3`. + ## Node.js Flags Electron supports some of the [CLI flags][node-cli] supported by Node.js. -**Note:** Passing unsupported command line switches to Electron when it is not running in `ELECTRON_RUN_AS_NODE` will have no effect. +> [!NOTE] +> Passing unsupported command line switches to Electron when it is not running in `ELECTRON_RUN_AS_NODE` will have no effect. -### --inspect-brk[=[host:]port] +### `--inspect-brk[=[host:]port]` Activate inspector on host:port and break at start of user script. Default host:port is 127.0.0.1:9229. Aliased to `--debug-brk=[host:]port`. -### --inspect-port=[host:]port +#### `--inspect-brk-node[=[host:]port]` + +Activate inspector on `host:port` and break at start of the first internal +JavaScript script executed when the inspector is available. +Default `host:port` is `127.0.0.1:9229`. + +### `--inspect-port=[host:]port` Set the `host:port` to be used when the inspector is activated. Useful when activating the inspector by sending the SIGUSR1 signal. Default host is `127.0.0.1`. Aliased to `--debug-port=[host:]port`. -### --inspect[=[host:]port] +### `--inspect[=[host:]port]` Activate inspector on `host:port`. Default is `127.0.0.1:9229`. @@ -227,15 +309,85 @@ See the [Debugging the Main Process][debugging-main-process] guide for more deta Aliased to `--debug[=[host:]port`. -### --inspect-publish-uid=stderr,http +### `--inspect-publish-uid=stderr,http` Specify ways of the inspector web socket url exposure. -By default inspector websocket url is available in stderr and under /json/list endpoint on http://host:port/json/list. +By default inspector websocket url is available in stderr and under /json/list endpoint on `http://host:port/json/list`. + +### `--experimental-network-inspection` + +Enable support for DevTools network inspector events, for visibility into requests made by the nodejs `http` and `https` modules. + +### `--no-deprecation` + +Silence deprecation warnings. + +### `--throw-deprecation` + +Throw errors for deprecations. + +### `--trace-deprecation` + +Print stack traces for deprecations. + +### `--trace-warnings` + +Print stack traces for process warnings (including deprecations). + +### `--dns-result-order=order` + +Set the default value of the `verbatim` parameter in the Node.js [`dns.lookup()`](https://nodejs.org/api/dns.html#dnslookuphostname-options-callback) and [`dnsPromises.lookup()`](https://nodejs.org/api/dns.html#dnspromiseslookuphostname-options) functions. The value could be: + +* `ipv4first`: sets default `verbatim` `false`. +* `verbatim`: sets default `verbatim` `true`. + +The default is `verbatim` and `dns.setDefaultResultOrder()` have higher priority than `--dns-result-order`. + +### `--diagnostic-dir=directory` + +Set the directory to which all Node.js diagnostic output files are written. Defaults to current working directory. + +Affects the default output directory of [v8.setHeapSnapshotNearHeapLimit](https://nodejs.org/docs/latest/api/v8.html#v8setheapsnapshotnearheaplimitlimit). + +### `--no-experimental-global-navigator` + +Disable exposition of [Navigator API][] on the global scope from Node.js. + +### `--experimental-transform-types` + +Enables the [transformation](https://nodejs.org/api/typescript.html#type-stripping) +of TypeScript-only syntax into JavaScript code. + +## Chromium Flags + +There isn't a documented list of all Chromium switches, but there are a few ways to find them. + +The easiest way is through Chromium's flags page, which you can access at `about://flags`. These flags don't directly match switch names, but they show up in the process's command-line arguments. + +To see these arguments, enable a flag in `about://flags`, then go to `about://version` in Chromium. You'll find a list of command-line arguments, including `--flag-switches-begin --your --list --flag-switches-end`, which contains the list of your flag enabled switches. + +Most flags are included as part of `--enable-features=`, but some are standalone switches, like `--enable-experimental-web-platform-features`. + +A complete list of flags exists in [Chromium's flag metadata page](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/flag-metadata.json), but this list includes platform, environment and GPU specific, expired and potentially non-functional flags, so many of them might not always work in every situation. + +Keep in mind that standalone switches can sometimes be split into individual features, so there's no fully complete list of switches. + +Finally, you'll need to ensure that the version of Chromium in Electron matches the version of the browser you're using to cross-reference the switches. + +### Chromium features relevant to Electron apps + +* `AlwaysLogLOAFURL`: enables script attribution for + [`long-animation-frame`](https://developer.mozilla.org/en-US/docs/Web/API/Performance_API/Long_animation_frame_timing) + `PerformanceObserver` events for non-http(s), non-data, non-blob URLs (such as `file:` or custom + protocol URLs). [app]: app.md [append-switch]: command-line.md#commandlineappendswitchswitch-value -[ready]: app.md#event-ready -[play-silent-audio]: https://github.com/atom/atom/pull/9485/files [debugging-main-process]: ../tutorial/debugging-main-process.md +[logging]: https://source.chromium.org/chromium/chromium/src/+/main:base/logging.h [node-cli]: https://nodejs.org/api/cli.html +[play-silent-audio]: https://github.com/atom/atom/pull/9485/files +[ready]: app.md#event-ready +[severities]: https://source.chromium.org/chromium/chromium/src/+/main:base/logging.h?q=logging::LogSeverity&ss=chromium +[Navigator API]: https://github.com/nodejs/node/blob/main/doc/api/globals.md#navigator diff --git a/docs/api/command-line.md b/docs/api/command-line.md index 8823dfbe0c4ec..e424ba1f1c498 100644 --- a/docs/api/command-line.md +++ b/docs/api/command-line.md @@ -2,12 +2,14 @@ > Manipulate the command line arguments for your app that Chromium reads -Process: [Main](../glossary.md#main-process) +Process: [Main](../glossary.md#main-process)<br /> +_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ The following example shows how to check if the `--disable-gpu` flag is set. -```javascript +```js const { app } = require('electron') + app.commandLine.hasSwitch('disable-gpu') ``` @@ -19,36 +21,91 @@ document. #### `commandLine.appendSwitch(switch[, value])` -* `switch` String - A command-line switch, without the leading `--` -* `value` String (optional) - A value for the given switch +* `switch` string - A command-line switch, without the leading `--`. +* `value` string (optional) - A value for the given switch. Append a switch (with optional `value`) to Chromium's command line. -**Note:** This will not affect `process.argv`. The intended usage of this function is to -control Chromium's behavior. +> [!NOTE] +> This will not affect `process.argv`. The intended usage of this function is to +> control Chromium's behavior. + +```js +const { app } = require('electron') + +app.commandLine.appendSwitch('remote-debugging-port', '8315') +``` #### `commandLine.appendArgument(value)` -* `value` String - The argument to append to the command line +* `value` string - The argument to append to the command line. Append an argument to Chromium's command line. The argument will be quoted correctly. Switches will precede arguments regardless of appending order. If you're appending an argument like `--switch=value`, consider using `appendSwitch('switch', 'value')` instead. -**Note:** This will not affect `process.argv`. The intended usage of this function is to -control Chromium's behavior. +```js +const { app } = require('electron') + +app.commandLine.appendArgument('--enable-experimental-web-platform-features') +``` + +> [!NOTE] +> This will not affect `process.argv`. The intended usage of this function is to +> control Chromium's behavior. #### `commandLine.hasSwitch(switch)` -* `switch` String - A command-line switch +* `switch` string - A command-line switch. -Returns `Boolean` - Whether the command-line switch is present. +Returns `boolean` - Whether the command-line switch is present. + +```js +const { app } = require('electron') + +app.commandLine.appendSwitch('remote-debugging-port', '8315') +const hasPort = app.commandLine.hasSwitch('remote-debugging-port') +console.log(hasPort) // true +``` #### `commandLine.getSwitchValue(switch)` -* `switch` String - A command-line switch +* `switch` string - A command-line switch. + +Returns `string` - The command-line switch value. -Returns `String` - The command-line switch value. +This function is meant to obtain Chromium command line switches. It is not +meant to be used for application-specific command line arguments. For the +latter, please use `process.argv`. + +```js +const { app } = require('electron') + +app.commandLine.appendSwitch('remote-debugging-port', '8315') +const portValue = app.commandLine.getSwitchValue('remote-debugging-port') +console.log(portValue) // '8315' +``` + +> [!NOTE] +> When the switch is not present or has no value, it returns empty string. + +#### `commandLine.removeSwitch(switch)` + +* `switch` string - A command-line switch. + +Removes the specified switch from Chromium's command line. + +```js +const { app } = require('electron') + +app.commandLine.appendSwitch('remote-debugging-port', '8315') +console.log(app.commandLine.hasSwitch('remote-debugging-port')) // true + +app.commandLine.removeSwitch('remote-debugging-port') +console.log(app.commandLine.hasSwitch('remote-debugging-port')) // false +``` -**Note:** When the switch is not present or has no value, it returns empty string. +> [!NOTE] +> This will not affect `process.argv`. The intended usage of this function is to +> control Chromium's behavior. diff --git a/docs/api/content-tracing.md b/docs/api/content-tracing.md index 0789325304b68..1217f024bbcbe 100644 --- a/docs/api/content-tracing.md +++ b/docs/api/content-tracing.md @@ -7,16 +7,17 @@ Process: [Main](../glossary.md#main-process) This module does not include a web interface. To view recorded traces, use [trace viewer][], available at `chrome://tracing` in Chrome. -**Note:** You should not use this module until the `ready` event of the app -module is emitted. +> [!NOTE] +> You should not use this module until the `ready` event of the app +> module is emitted. -```javascript +```js const { app, contentTracing } = require('electron') app.whenReady().then(() => { (async () => { await contentTracing.startRecording({ - include_categories: ['*'] + included_categories: ['*'] }) console.log('Tracing started') await new Promise(resolve => setTimeout(resolve, 5000)) @@ -32,17 +33,37 @@ The `contentTracing` module has the following methods: ### `contentTracing.getCategories()` -Returns `Promise<String[]>` - resolves with an array of category groups once all child processes have acknowledged the `getCategories` request +<!-- +```YAML history +changes: + - pr-url: https://github.com/electron/electron/pull/16583 + description: "This method now returns a Promise instead of using a callback function." + breaking-changes-header: api-changed-callback-based-versions-of-promisified-apis +``` +--> + +Returns `Promise<string[]>` - resolves with an array of category groups once all child processes have acknowledged the `getCategories` request Get a set of category groups. The category groups can change as new code paths -are reached. See also the [list of built-in tracing -categories](https://chromium.googlesource.com/chromium/src/+/master/base/trace_event/builtin_categories.h). +are reached. See also the +[list of built-in tracing categories](https://chromium.googlesource.com/chromium/src/+/main/base/trace_event/builtin_categories.h). > **NOTE:** Electron adds a non-default tracing category called `"electron"`. > This category can be used to capture Electron-specific tracing events. ### `contentTracing.startRecording(options)` +<!-- +```YAML history +changes: + - pr-url: https://github.com/electron/electron/pull/13914 + description: "The `options` parameter now accepts `TraceConfig` in addition to `TraceCategoriesAndOptions`." + - pr-url: https://github.com/electron/electron/pull/16584 + description: "This function now returns a callback`Promise<void>`." + breaking-changes-header: api-changed-callback-based-versions-of-promisified-apis +``` +--> + * `options` ([TraceConfig](structures/trace-config.md) | [TraceCategoriesAndOptions](structures/trace-categories-and-options.md)) Returns `Promise<void>` - resolved once all child processes have acknowledged the `startRecording` request. @@ -57,9 +78,20 @@ only one trace operation can be in progress at a time. ### `contentTracing.stopRecording([resultFilePath])` -* `resultFilePath` String (optional) +<!-- +```YAML history +changes: + - pr-url: https://github.com/electron/electron/pull/16584 + description: "This method now returns a Promise instead of using a callback function." + breaking-changes-header: api-changed-callback-based-versions-of-promisified-apis + - pr-url: https://github.com/electron/electron/pull/18411 + description: "The `resultFilePath` parameter is now optional." +``` +--> + +* `resultFilePath` string (optional) -Returns `Promise<String>` - resolves with a path to a file that contains the traced data once all child processes have acknowledged the `stopRecording` request +Returns `Promise<string>` - resolves with a path to a file that contains the traced data once all child processes have acknowledged the `stopRecording` request Stop recording on all processes. @@ -75,12 +107,82 @@ will be returned in the promise. ### `contentTracing.getTraceBufferUsage()` +<!-- +```YAML history +changes: + - pr-url: https://github.com/electron/electron/pull/16600 + description: "This method now returns a Promise instead of using a callback function." + breaking-changes-header: api-changed-callback-based-versions-of-promisified-apis +``` +--> + Returns `Promise<Object>` - Resolves with an object containing the `value` and `percentage` of trace buffer maximum usage -* `value` Number -* `percentage` Number +* `value` number +* `percentage` number Get the maximum usage across processes of trace buffer as a percentage of the full state. +### `contentTracing.enableHeapProfiling([options])` _Experimental_ + +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/50826 +``` +--> + +* `options` ([EnableHeapProfilingOptions](structures/enable-heap-profiling-options.md)) (optional) + +Returns `Promise<void>` - Resolves once heap profiling has been enabled. + +Enable [heap profiling](https://chromium.googlesource.com/chromium/src/+/lkgr/docs/memory-infra/heap_profiler.md) +for MemoryInfra traces. Equivalent to the `--memlog` switch in Chrome. + +Only takes effect if the `disabled-by-default-memory-infra` category is included. + +Needs to be called before `contentTracing.startRecording()`. + +Usage: + +```js +const { contentTracing } = require('electron') + +async function recordTrace () { + await contentTracing.enableHeapProfiling() + await contentTracing.startRecording({ + included_categories: ['disabled-by-default-memory-infra'], + excluded_categories: ['*'], + memory_dump_config: { + triggers: [ + { mode: 'detailed', periodic_interval_ms: 1000 } + ] + } + }) + + await new Promise(resolve => setTimeout(resolve, 5000)) + + const filePath = await contentTracing.stopRecording() +} +``` + +To view the recorded heap dumps: + +1. Download the breakpad symbols for your Electron version from the Electron GitHub + [releases](https://github.com/electron/electron/releases) +2. Clone the [Electron source code](../development/build-instructions-gn.md) +3. In your Chromium checkout for Electron, run this command to symbolicate the heap dump: + + ```bash + python3 third_party/catapult/tracing/bin/symbolize_trace --use-breakpad-symbols --breakpad-symbols-directory /path/to/breakpad_symbols /path/to/trace.json + ``` + +4. Open the symbolicated trace in `chrome://tracing` (the Perfetto UI does not support memory dumps + yet) +5. Click on one of the `M` symbols +6. Click on a `☰` triple bar icon (e.g., in the `malloc` column) + +<img src="../images/viewing-heap-dumps.png" alt="Screenshot showing how to view a heapdump in Chromium's tracing view" /> + [trace viewer]: https://chromium.googlesource.com/catapult/+/HEAD/tracing/README.md diff --git a/docs/api/context-bridge.md b/docs/api/context-bridge.md index c87f3a4291e6f..6eb7dd2a2bcc8 100644 --- a/docs/api/context-bridge.md +++ b/docs/api/context-bridge.md @@ -1,12 +1,21 @@ # contextBridge +<!-- +```YAML history +changes: + - pr-url: https://github.com/electron/electron/pull/40330 + description: "`ipcRenderer` can no longer be sent over the `contextBridge`" + breaking-changes-header: behavior-changed-ipcrenderer-can-no-longer-be-sent-over-the-contextbridge +``` +--> + > Create a safe, bi-directional, synchronous bridge across isolated contexts Process: [Renderer](../glossary.md#renderer-process) An example of exposing an API to a renderer from an isolated preload script is given below: -```javascript +```js // Preload (Isolated World) const { contextBridge, ipcRenderer } = require('electron') @@ -18,7 +27,7 @@ contextBridge.exposeInMainWorld( ) ``` -```javascript +```js @ts-nocheck // Renderer (Main World) window.electron.doThing() @@ -33,33 +42,53 @@ page you load in your renderer executes code in this world. ### Isolated World -When `contextIsolation` is enabled in your `webPreferences`, your `preload` scripts run in an +When `contextIsolation` is enabled in your `webPreferences` (this is the default behavior since Electron 12.0.0), your `preload` scripts run in an "Isolated World". You can read more about context isolation and what it affects in the -[security](../tutorial/security.md#3-enable-context-isolation-for-remote-content) docs. +[security](../tutorial/security.md#3-enable-context-isolation) docs. ## Methods The `contextBridge` module has the following methods: -### `contextBridge.exposeInMainWorld(apiKey, api)` _Experimental_ +### `contextBridge.exposeInMainWorld(apiKey, api)` + +* `apiKey` string - The key to inject the API onto `window` with. The API will be accessible on `window[apiKey]`. +* `api` any - Your API, more information on what this API can be and how it works is available below. + +### `contextBridge.exposeInIsolatedWorld(worldId, apiKey, api)` + +* `worldId` Integer - The ID of the world to inject the API into. `0` is the default world, `999` is the world used by Electron's `contextIsolation` feature. Using 999 would expose the object for preload context. We recommend using 1000+ while creating isolated world. +* `apiKey` string - The key to inject the API onto `window` with. The API will be accessible on `window[apiKey]`. +* `api` any - Your API, more information on what this API can be and how it works is available below. -* `apiKey` String - The key to inject the API onto `window` with. The API will be accessible on `window[apiKey]`. -* `api` Record<String, any> - Your API object, more information on what this API can be and how it works is available below. +### `contextBridge.executeInMainWorld(executionScript)` _Experimental_ + +<!-- TODO(samuelmaddock): add generics to map the `args` types to the `func` params --> + +* `executionScript` Object + * `func` (...args: any[]) => any - A JavaScript function to execute. This function will be serialized which means + that any bound parameters and execution context will be lost. + * `args` any[] (optional) - An array of arguments to pass to the provided function. These + arguments will be copied between worlds in accordance with + [the table of supported types.](#parameter--error--return-type-support) + +Returns `any` - A copy of the resulting value from executing the function in the main world. +[Refer to the table](#parameter--error--return-type-support) on how values are copied between worlds. ## Usage -### API Objects +### API -The `api` object provided to [`exposeInMainWorld`](#contextbridgeexposeinmainworldapikey-api-experimental) must be an object -whose keys are strings and values are a `Function`, `String`, `Number`, `Array`, `Boolean`, or another nested object that meets the same conditions. +The `api` provided to [`exposeInMainWorld`](#contextbridgeexposeinmainworldapikey-api) must be a `Function`, `string`, `number`, `Array`, `boolean`, or an object +whose keys are strings and values are a `Function`, `string`, `number`, `Array`, `boolean`, or another nested object that meets the same conditions. `Function` values are proxied to the other context and all other values are **copied** and **frozen**. Any data / primitives sent in -the API object become immutable and updates on either side of the bridge do not result in an update on the other side. +the API become immutable and updates on either side of the bridge do not result in an update on the other side. -An example of a complex API object is shown below: +An example of a complex API is shown below: -```javascript -const { contextBridge } = require('electron') +```js +const { contextBridge, ipcRenderer } = require('electron') contextBridge.exposeInMainWorld( 'electron', @@ -84,6 +113,26 @@ contextBridge.exposeInMainWorld( ) ``` +An example of `exposeInIsolatedWorld` is shown below: + +```js +const { contextBridge, ipcRenderer } = require('electron') + +contextBridge.exposeInIsolatedWorld( + 1004, + 'electron', + { + doThing: () => ipcRenderer.send('do-a-thing') + } +) +``` + +```js @ts-nocheck +// Renderer (In isolated world id1004) + +window.electron.doThing() +``` + ### API Functions `Function` values that you bind through the `contextBridge` are proxied through Electron to ensure that contexts remain isolated. This @@ -97,15 +146,58 @@ has been included below for completeness: | Type | Complexity | Parameter Support | Return Value Support | Limitations | | ---- | ---------- | ----------------- | -------------------- | ----------- | -| `String` | Simple | ✅ | ✅ | N/A | -| `Number` | Simple | ✅ | ✅ | N/A | -| `Boolean` | Simple | ✅ | ✅ | N/A | +| `string` | Simple | ✅ | ✅ | N/A | +| `number` | Simple | ✅ | ✅ | N/A | +| `boolean` | Simple | ✅ | ✅ | N/A | | `Object` | Complex | ✅ | ✅ | Keys must be supported using only "Simple" types in this table. Values must be supported in this table. Prototype modifications are dropped. Sending custom classes will copy values but not the prototype. | | `Array` | Complex | ✅ | ✅ | Same limitations as the `Object` type | -| `Error` | Complex | ✅ | ✅ | Errors that are thrown are also copied, this can result in the message and stack trace of the error changing slightly due to being thrown in a different context | -| `Promise` | Complex | ✅ | ✅ | Promises are only proxied if they are the return value or exact parameter. Promises nested in arrays or objects will be dropped. | +| `Error` | Complex | ✅ | ✅ | Errors that are thrown are also copied, this can result in the message and stack trace of the error changing slightly due to being thrown in a different context, and any custom properties on the Error object [will be lost](https://github.com/electron/electron/issues/25596) | +| `Promise` | Complex | ✅ | ✅ | N/A | | `Function` | Complex | ✅ | ✅ | Prototype modifications are dropped. Sending classes or constructors will not work. | | [Cloneable Types](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm) | Simple | ✅ | ✅ | See the linked document on cloneable types | +| `Element` | Complex | ✅ | ✅ | Prototype modifications are dropped. Sending custom elements will not work. | +| `Blob` | Complex | ✅ | ✅ | N/A | +| `VideoFrame` | Complex | ✅ | ✅ | N/A | | `Symbol` | N/A | ❌ | ❌ | Symbols cannot be copied across contexts so they are dropped | If the type you care about is not in the above table, it is probably not supported. + +### Exposing ipcRenderer + +Attempting to send the entire `ipcRenderer` module as an object over the `contextBridge` will result in +an empty object on the receiving side of the bridge. Sending over `ipcRenderer` in full can let any +code send any message, which is a security footgun. To interact through `ipcRenderer`, provide a safe wrapper +like below: + +```js +// Preload (Isolated World) +contextBridge.exposeInMainWorld('electron', { + onMyEventName: (callback) => ipcRenderer.on('MyEventName', (e, ...args) => callback(args)) +}) +``` + +```js @ts-nocheck +// Renderer (Main World) +window.electron.onMyEventName(data => { /* ... */ }) +``` + +### Exposing Node Global Symbols + +The `contextBridge` can be used by the preload script to give your renderer access to Node APIs. +The table of supported types described above also applies to Node APIs that you expose through `contextBridge`. +Please note that many Node APIs grant access to local system resources. +Be very cautious about which globals and APIs you expose to untrusted remote content. + +```js +const { contextBridge } = require('electron') + +const crypto = require('node:crypto') + +contextBridge.exposeInMainWorld('nodeCrypto', { + sha256sum (data) { + const hash = crypto.createHash('sha256') + hash.update(data) + return hash.digest('hex') + } +}) +``` diff --git a/docs/api/cookies.md b/docs/api/cookies.md index 4eab77d4d5996..b85d6635d1369 100644 --- a/docs/api/cookies.md +++ b/docs/api/cookies.md @@ -2,14 +2,15 @@ > Query and modify a session's cookies. -Process: [Main](../glossary.md#main-process) +Process: [Main](../glossary.md#main-process)<br /> +_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ Instances of the `Cookies` class are accessed by using `cookies` property of a `Session`. For example: -```javascript +```js const { session } = require('electron') // Query all cookies. @@ -21,7 +22,7 @@ session.defaultSession.cookies.get({}) }) // Query all cookies associated with a specific url. -session.defaultSession.cookies.get({ url: 'http://www.github.com' }) +session.defaultSession.cookies.get({ url: 'https://www.github.com' }) .then((cookies) => { console.log(cookies) }).catch((error) => { @@ -30,7 +31,7 @@ session.defaultSession.cookies.get({ url: 'http://www.github.com' }) // Set a cookie with the given cookie data; // may overwrite equivalent cookies if they exist. -const cookie = { url: 'http://www.github.com', name: 'dummy_name', value: 'dummy' } +const cookie = { url: 'https://www.github.com', name: 'dummy_name', value: 'dummy' } session.defaultSession.cookies.set(cookie) .then(() => { // success @@ -45,17 +46,24 @@ The following events are available on instances of `Cookies`: #### Event: 'changed' +Returns: + * `event` Event * `cookie` [Cookie](structures/cookie.md) - The cookie that was changed. -* `cause` String - The cause of the change with one of the following values: - * `explicit` - The cookie was changed directly by a consumer's action. +* `cause` string - The cause of the change with one of the following values: + * `inserted` - The cookie was inserted. + * `inserted-no-change-overwrite` - The newly inserted cookie overwrote a cookie but + did not result in any change. For example, inserting an identical cookie will produce this cause. + * `inserted-no-value-change-overwrite` - The newly inserted cookie overwrote a cookie but + did not result in any value change, but it's web observable (e.g. updates the expiry). + * `explicit` - The cookie was deleted directly by a consumer's action. * `overwrite` - The cookie was automatically removed due to an insert operation that overwrote it. * `expired` - The cookie was automatically removed as it expired. * `evicted` - The cookie was automatically evicted during garbage collection. * `expired-overwrite` - The cookie was overwritten with an already-expired expiration date. -* `removed` Boolean - `true` if the cookie was removed, `false` otherwise. +* `removed` boolean - `true` if the cookie was removed, `false` otherwise. Emitted when a cookie is changed because it was added, edited, removed, or expired. @@ -67,14 +75,15 @@ The following methods are available on instances of `Cookies`: #### `cookies.get(filter)` * `filter` Object - * `url` String (optional) - Retrieves cookies which are associated with + * `url` string (optional) - Retrieves cookies which are associated with `url`. Empty implies retrieving cookies of all URLs. - * `name` String (optional) - Filters cookies by name. - * `domain` String (optional) - Retrieves cookies whose domains match or are + * `name` string (optional) - Filters cookies by name. + * `domain` string (optional) - Retrieves cookies whose domains match or are subdomains of `domains`. - * `path` String (optional) - Retrieves cookies whose path matches `path`. - * `secure` Boolean (optional) - Filters cookies by their Secure property. - * `session` Boolean (optional) - Filters out session or persistent cookies. + * `path` string (optional) - Retrieves cookies whose path matches `path`. + * `secure` boolean (optional) - Filters cookies by their Secure property. + * `session` boolean (optional) - Filters out session or persistent cookies. + * `httpOnly` boolean (optional) - Filters cookies by httpOnly. Returns `Promise<Cookie[]>` - A promise which resolves an array of cookie objects. @@ -84,35 +93,39 @@ the response. #### `cookies.set(details)` * `details` Object - * `url` String - The URL to associate the cookie with. The promise will be rejected if the URL is invalid. - * `name` String (optional) - The name of the cookie. Empty by default if omitted. - * `value` String (optional) - The value of the cookie. Empty by default if omitted. - * `domain` String (optional) - The domain of the cookie; this will be normalized with a preceding dot so that it's also valid for subdomains. Empty by default if omitted. - * `path` String (optional) - The path of the cookie. Empty by default if omitted. - * `secure` Boolean (optional) - Whether the cookie should be marked as Secure. Defaults to - false. - * `httpOnly` Boolean (optional) - Whether the cookie should be marked as HTTP only. + * `url` string - The URL to associate the cookie with. The promise will be rejected if the URL is invalid. + * `name` string (optional) - The name of the cookie. Empty by default if omitted. + * `value` string (optional) - The value of the cookie. Empty by default if omitted. + * `domain` string (optional) - The domain of the cookie; this will be normalized with a preceding dot so that it's also valid for subdomains. Empty by default if omitted. + * `path` string (optional) - The path of the cookie. Empty by default if omitted. + * `secure` boolean (optional) - Whether the cookie should be marked as Secure. Defaults to + false unless [Same Site=None](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite#samesitenone_requires_secure) attribute is used. + * `httpOnly` boolean (optional) - Whether the cookie should be marked as HTTP only. Defaults to false. * `expirationDate` Double (optional) - The expiration date of the cookie as the number of seconds since the UNIX epoch. If omitted then the cookie becomes a session cookie and will not be retained between sessions. - * `sameSite` String (optional) - The [Same Site](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#SameSite_cookies) policy to apply to this cookie. Can be `unspecified`, `no_restriction`, `lax` or `strict`. Default is `no_restriction`. + * `sameSite` string (optional) - The [Same Site](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#SameSite_cookies) policy to apply to this cookie. Can be `unspecified`, `no_restriction`, `lax` or `strict`. Default is `lax`. -Returns `Promise<void>` - A promise which resolves when the cookie has been set +Returns `Promise<void>` - A promise which resolves when the cookie has been set. Sets a cookie with `details`. #### `cookies.remove(url, name)` -* `url` String - The URL associated with the cookie. -* `name` String - The name of cookie to remove. +* `url` string - The URL associated with the cookie. +* `name` string - The name of cookie to remove. -Returns `Promise<void>` - A promise which resolves when the cookie has been removed +Returns `Promise<void>` - A promise which resolves when the cookie has been removed. -Removes the cookies matching `url` and `name` +Removes the cookies matching `url` and `name`. #### `cookies.flushStore()` -Returns `Promise<void>` - A promise which resolves when the cookie store has been flushed +Returns `Promise<void>` - A promise which resolves when the cookie store has been flushed. Writes any unwritten cookies data to disk. + +Cookies written by any method will not be written to disk immediately, but will be written every 30 seconds or 512 operations. + +Calling this method can cause the cookie to be written to disk immediately. diff --git a/docs/api/corner-smoothing-css.md b/docs/api/corner-smoothing-css.md new file mode 100644 index 0000000000000..f9c1ec53dc3b0 --- /dev/null +++ b/docs/api/corner-smoothing-css.md @@ -0,0 +1,76 @@ +## CSS Rule: `-electron-corner-smoothing` + +> Smoothes out the corner rounding of the `border-radius` CSS rule. + +The rounded corners of elements with [the `border-radius` CSS rule](https://developer.mozilla.org/en-US/docs/Web/CSS/border-radius) can be smoothed out using the `-electron-corner-smoothing` CSS rule. This smoothness is very similar to Apple's "continuous" rounded corners in SwiftUI and Figma's "corner smoothing" control on design elements. + +![There is a black rectangle on the left using simple rounded corners, and a blue rectangle on the right using smooth rounded corners. In between those rectangles is a magnified view of the same corner from both rectangles overlapping to show the subtle difference in shape.](../images/corner-smoothing-summary.svg) + +Integrating with the operating system and its design language is important to many desktop applications. The shape of a rounded corner can be a subtle detail to many users. However, aligning closely to the system's design language that users are familiar with makes the application's design feel familiar too. Beyond matching the design language of macOS, designers may decide to use smoother round corners for many other reasons. + +`-electron-corner-smoothing` affects the shape of borders, outlines, and shadows on the target element. Mirroring the behavior of `border-radius`, smoothing will gradually back off if an element's size is too small for the chosen value. + +The `-electron-corner-smoothing` CSS rule is **only implemented for Electron** and has no effect in browsers. Avoid using this rule outside of Electron. This CSS rule is considered experimental and may require migration in the future if replaced by a CSS standard. + +### Example + +The following example shows the effect of corner smoothing at different percents. + +```css +.box { + width: 128px; + height: 128px; + background-color: cornflowerblue; + border-radius: 24px; + -electron-corner-smoothing: var(--percent); /* Column header in table below. */ +} +``` + +| 0% | 30% | 60% | 100% | +| --- | --- | --- | --- | +| ![A rectangle with round corners at 0% smoothness](../images/corner-smoothing-example-0.svg) | ![A rectangle with round corners at 30% smoothness](../images/corner-smoothing-example-30.svg) | ![A rectangle with round corners at 60% smoothness](../images/corner-smoothing-example-60.svg) | ![A rectangle with round corners at 100% smoothness](../images/corner-smoothing-example-100.svg) | + +### Matching the system UI + +Use the `system-ui` keyword to match the smoothness to the OS design language. + +```css +.box { + width: 128px; + height: 128px; + background-color: cornflowerblue; + border-radius: 24px; + -electron-corner-smoothing: system-ui; /* Match the system UI design. */ +} +``` + +| OS: | macOS | Windows, Linux | +| --- | --- | --- | +| Value: | `60%` | `0%` | +| Example: | ![A rectangle with round corners whose smoothness matches macOS](../images/corner-smoothing-example-60.svg) | ![A rectangle with round corners whose smoothness matches Windows and Linux](../images/corner-smoothing-example-0.svg) | + +### Controlling availability + +This CSS rule can be disabled using the Blink feature flag `ElectronCSSCornerSmoothing`. + +```js +const myWindow = new BrowserWindow({ + // [...] + webPreferences: { + disableBlinkFeatures: 'ElectronCSSCornerSmoothing' // Disables the `-electron-corner-smoothing` CSS rule + } +}) +``` + +### Formal reference + +* **Initial value**: `0%` +* **Inherited**: No +* **Animatable**: No +* **Computed value**: As specified + +```css +-electron-corner-smoothing = + <percentage [0,100]> | + system-ui +``` diff --git a/docs/api/crash-reporter.md b/docs/api/crash-reporter.md index e81729e4632d5..4954d37c4c615 100644 --- a/docs/api/crash-reporter.md +++ b/docs/api/crash-reporter.md @@ -4,10 +4,16 @@ Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process) +> [!IMPORTANT] +> If you want to call this API from a renderer process with context isolation enabled, +> place the API call in your preload script and +> [expose](../tutorial/context-isolation.md#after-context-isolation-enabled) it using the +> [`contextBridge`](context-bridge.md) API. + The following is an example of setting up Electron to automatically submit crash reports to a remote server: -```javascript +```js const { crashReporter } = require('electron') crashReporter.start({ submitURL: 'https://your-domain.com/url-to-submit' }) @@ -16,59 +22,27 @@ crashReporter.start({ submitURL: 'https://your-domain.com/url-to-submit' }) For setting up a server to accept and process crash reports, you can use following projects: -* [socorro](https://github.com/mozilla/socorro) +* [socorro](https://github.com/mozilla-services/socorro) * [mini-breakpad-server](https://github.com/electron/mini-breakpad-server) +> [!NOTE] +> Electron uses Crashpad, not Breakpad, to collect and upload +> crashes, but for the time being, the [upload protocol is the same](https://chromium.googlesource.com/crashpad/crashpad/+/HEAD/doc/overview_design.md#Upload-to-collection-server). + Or use a 3rd party hosted solution: * [Backtrace](https://backtrace.io/electron/) * [Sentry](https://docs.sentry.io/clients/electron) * [BugSplat](https://www.bugsplat.com/docs/platforms/electron) +* [Bugsnag](https://docs.bugsnag.com/platforms/electron/) Crash reports are stored temporarily before being uploaded in a directory -underneath the app's user data directory (called 'Crashpad' on Windows and Mac, -or 'Crash Reports' on Linux). You can override this directory by calling -`app.setPath('crashDumps', '/path/to/crashes')` before starting the crash -reporter. - -On Windows and macOS, Electron uses -[crashpad](https://chromium.googlesource.com/crashpad/crashpad/+/master/README.md) -to monitor and report crashes. On Linux, Electron uses -[breakpad](https://chromium.googlesource.com/breakpad/breakpad/+/master/). This -is an implementation detail driven by Chromium, and it may change in future. In -particular, crashpad is newer and will likely eventually replace breakpad on -all platforms. - -### Note about Node child processes on Linux - -If you are using the Node.js `child_process` module and want to report crashes -from those processes on Linux, there is an extra step you will need to take to -properly initialize the crash reporter in the child process. This is not -necessary on Mac or Windows, as those platforms use Crashpad, which -automatically monitors child processes. - -Since `require('electron')` is not available in Node child processes, the -following APIs are available on the `process` object in Node child processes. -Note that, on Linux, each Node child process has its own separate instance of -the breakpad crash reporter. This is dissimilar to renderer child processes, -which have a "stub" breakpad reporter which returns information to the main -process for reporting. - -#### `process.crashReporter.start(options)` - -See [`crashReporter.start()`](#crashreporterstartoptions). - -#### `process.crashReporter.getParameters()` +underneath the app's user data directory, called 'Crashpad'. You can override +this directory by calling `app.setPath('crashDumps', '/path/to/crashes')` +before starting the crash reporter. -See [`crashReporter.getParameters()`](#crashreportergetparameters). - -#### `process.crashReporter.addExtraParameter(key, value)` - -See [`crashReporter.addExtraParameter(key, value)`](#crashreporteraddextraparameterkey-value). - -#### `process.crashReporter.removeExtraParameter(key)` - -See [`crashReporter.removeExtraParameter(key)`](#crashreporterremoveextraparameterkey). +Electron uses [crashpad](https://chromium.googlesource.com/crashpad/crashpad/+/refs/heads/main/README.md) +to monitor and report crashes. ## Methods @@ -76,29 +50,46 @@ The `crashReporter` module has the following methods: ### `crashReporter.start(options)` +<!-- +```YAML history +changes: + - pr-url: https://github.com/electron/electron/pull/23062 + description: "Added `rateLimit` and `compress` options." + - pr-url: https://github.com/electron/electron/pull/23265 + description: "Deprecated calling this method in the renderer process." + breaking-changes-header: deprecated-crashreporter-methods-in-the-renderer-process + - pr-url: https://github.com/electron/electron/pull/25288 + description: "Default value of `compress` option changed from `false` to `true`." + breaking-changes-header: default-changed-crashreporterstart-compress-true- + - pr-url: https://github.com/electron/electron/pull/28105 + description: "The `submitURL` parameter is now optional when `uploadToServer` is `false`." +``` +--> + * `options` Object - * `submitURL` String - URL that crash reports will be sent to as POST. - * `productName` String (optional) - Defaults to `app.name`. - * `companyName` String (optional) _Deprecated_ - Deprecated alias for + * `submitURL` string (optional) - URL that crash reports will be sent to as + POST. Required unless `uploadToServer` is `false`. + * `productName` string (optional) - Defaults to `app.name`. + * `companyName` string (optional) _Deprecated_ - Deprecated alias for `{ globalExtra: { _companyName: ... } }`. - * `uploadToServer` Boolean (optional) - Whether crash reports should be sent + * `uploadToServer` boolean (optional) - Whether crash reports should be sent to the server. If false, crash reports will be collected and stored in the crashes directory, but not uploaded. Default is `true`. - * `ignoreSystemCrashHandler` Boolean (optional) - If true, crashes generated + * `ignoreSystemCrashHandler` boolean (optional) - If true, crashes generated in the main process will not be forwarded to the system crash handler. Default is `false`. - * `rateLimit` Boolean (optional) _macOS_ _Windows_ - If true, limit the + * `rateLimit` boolean (optional) _macOS_ _Windows_ - If true, limit the number of crashes uploaded to 1/hour. Default is `false`. - * `compress` Boolean (optional) - If true, crash reports will be compressed + * `compress` boolean (optional) - If true, crash reports will be compressed and uploaded with `Content-Encoding: gzip`. Default is `true`. - * `extra` Record<String, String> (optional) - Extra string key/value + * `extra` Record\<string, string\> (optional) - Extra string key/value annotations that will be sent along with crash reports that are generated in the main process. Only string values are supported. Crashes generated in - child processes will not contain these extra + child processes will not include these extra parameters. To add extra parameters to crash reports generated from child processes, call [`addExtraParameter`](#crashreporteraddextraparameterkey-value) from the child process. - * `globalExtra` Record<String, String> (optional) - Extra string key/value + * `globalExtra` Record\<string, string\> (optional) - Extra string key/value annotations that will be sent along with any crash reports generated in any process. These annotations cannot be changed once the crash reporter has been started. If a key is present in both the global extra parameters and @@ -116,64 +107,102 @@ before `app.on('ready')`. If the crash reporter is not initialized at the time a renderer process is created, then that renderer process will not be monitored by the crash reporter. -**Note:** You can test out the crash reporter by generating a crash using -`process.crash()`. +> [!NOTE] +> You can test out the crash reporter by generating a crash using +> `process.crash()`. -**Note:** If you need to send additional/updated `extra` parameters after your -first call `start` you can call `addExtraParameter`. +> [!NOTE] +> If you need to send additional/updated `extra` parameters after your +> first call `start` you can call `addExtraParameter`. -**Note:** Parameters passed in `extra`, `globalExtra` or set with -`addExtraParameter` have limits on the length of the keys and values. Key names -must be at most 39 bytes long, and values must be no longer than 127 bytes. -Keys with names longer than the maximum will be silently ignored. Key values -longer than the maximum length will be truncated. +> [!NOTE] +> Parameters passed in `extra`, `globalExtra` or set with +> `addExtraParameter` have limits on the length of the keys and values. Key names +> must be at most 39 bytes long, and values must be no longer than 127 bytes. +> Keys with names longer than the maximum will be silently ignored. Key values +> longer than the maximum length will be truncated. -**Note:** Calling this method from the renderer process is deprecated. +> [!NOTE] +> This method is only available in the main process. ### `crashReporter.getLastCrashReport()` -Returns [`CrashReport`](structures/crash-report.md) - The date and ID of the +<!-- +```YAML history +changes: + - pr-url: https://github.com/electron/electron/pull/23265 + description: "Deprecated calling this method in the renderer process." + breaking-changes-header: deprecated-crashreporter-methods-in-the-renderer-process +``` +--> + +Returns [`CrashReport | null`](structures/crash-report.md) - The date and ID of the last crash report. Only crash reports that have been uploaded will be returned; even if a crash report is present on disk it will not be returned until it is uploaded. In the case that there are no uploaded reports, `null` is returned. -**Note:** Calling this method from the renderer process is deprecated. +> [!NOTE] +> This method is only available in the main process. ### `crashReporter.getUploadedReports()` +<!-- +```YAML history +changes: + - pr-url: https://github.com/electron/electron/pull/23265 + description: "Deprecated calling this method in the renderer process." + breaking-changes-header: deprecated-crashreporter-methods-in-the-renderer-process +``` +--> + Returns [`CrashReport[]`](structures/crash-report.md): Returns all uploaded crash reports. Each report contains the date and uploaded ID. -**Note:** Calling this method from the renderer process is deprecated. +> [!NOTE] +> This method is only available in the main process. ### `crashReporter.getUploadToServer()` -Returns `Boolean` - Whether reports should be submitted to the server. Set through +<!-- +```YAML history +changes: + - pr-url: https://github.com/electron/electron/pull/23265 + description: "Deprecated calling this method in the renderer process." + breaking-changes-header: deprecated-crashreporter-methods-in-the-renderer-process +``` +--> + +Returns `boolean` - Whether reports should be submitted to the server. Set through the `start` method or `setUploadToServer`. -**Note:** Calling this method from the renderer process is deprecated. +> [!NOTE] +> This method is only available in the main process. ### `crashReporter.setUploadToServer(uploadToServer)` -* `uploadToServer` Boolean - Whether reports should be submitted to the server. +<!-- +```YAML history +changes: + - pr-url: https://github.com/electron/electron/pull/23265 + description: "Deprecated calling this method in the renderer process." + breaking-changes-header: deprecated-crashreporter-methods-in-the-renderer-process +``` +--> + +* `uploadToServer` boolean - Whether reports should be submitted to the server. This would normally be controlled by user preferences. This has no effect if called before `start` is called. -**Note:** Calling this method from the renderer process is deprecated. - -### `crashReporter.getCrashesDirectory()` _Deprecated_ - -Returns `String` - The directory where crashes are temporarily stored before being uploaded. - -**Note:** This method is deprecated, use `app.getPath('crashDumps')` instead. +> [!NOTE] +> This method is only available in the main process. ### `crashReporter.addExtraParameter(key, value)` -* `key` String - Parameter key, must be no longer than 39 bytes. -* `value` String - Parameter value, must be no longer than 127 bytes. +* `key` string - Parameter key, must be no longer than 39 bytes. +* `value` string - Parameter value, must be no longer than 127 bytes. Set an extra parameter to be sent with the crash report. The values specified here will be sent in addition to any values set via the `extra` option when @@ -186,42 +215,63 @@ with crashes from renderer or other child processes. Similarly, adding extra parameters in a renderer process will not result in those parameters being sent with crashes that occur in other renderer processes or in the main process. -**Note:** Parameters have limits on the length of the keys and values. Key -names must be no longer than 39 bytes, and values must be no longer than 20320 -bytes. Keys with names longer than the maximum will be silently ignored. Key -values longer than the maximum length will be truncated. - -**Note:** On linux values that are longer than 127 bytes will be chunked into -multiple keys, each 127 bytes in length. E.g. `addExtraParameter('foo', 'a'.repeat(130))` -will result in two chunked keys `foo__1` and `foo__2`, the first will contain -the first 127 bytes and the second will contain the remaining 3 bytes. On -your crash reporting backend you should stitch together keys in this format. +> [!NOTE] +> Parameters have limits on the length of the keys and values. Key +> names must be no longer than 39 bytes, and values must be no longer than 20320 +> bytes. Keys with names longer than the maximum will be silently ignored. Key +> values longer than the maximum length will be truncated. ### `crashReporter.removeExtraParameter(key)` -* `key` String - Parameter key, must be no longer than 39 bytes. +* `key` string - Parameter key, must be no longer than 39 bytes. Remove an extra parameter from the current set of parameters. Future crashes will not include this parameter. ### `crashReporter.getParameters()` -Returns `Record<String, String>` - The current 'extra' parameters of the crash reporter. +Returns `Record<string, string>` - The current 'extra' parameters of the crash reporter. + +## In Node child processes + +Since `require('electron')` is not available in Node child processes, the +following APIs are available on the `process` object in Node child processes. + +#### `process.crashReporter.start(options)` + +See [`crashReporter.start()`](#crashreporterstartoptions). + +Note that if the crash reporter is started in the main process, it will +automatically monitor child processes, so it should not be started in the child +process. Only use this method if the main process does not initialize the crash +reporter. + +#### `process.crashReporter.getParameters()` + +See [`crashReporter.getParameters()`](#crashreportergetparameters). + +#### `process.crashReporter.addExtraParameter(key, value)` + +See [`crashReporter.addExtraParameter(key, value)`](#crashreporteraddextraparameterkey-value). + +#### `process.crashReporter.removeExtraParameter(key)` + +See [`crashReporter.removeExtraParameter(key)`](#crashreporterremoveextraparameterkey). ## Crash Report Payload The crash reporter will send the following data to the `submitURL` as a `multipart/form-data` `POST`: -* `ver` String - The version of Electron. -* `platform` String - e.g. 'win32'. -* `process_type` String - e.g. 'renderer'. -* `guid` String - e.g. '5e1286fc-da97-479e-918b-6bfb0c3d1c72'. -* `_version` String - The version in `package.json`. -* `_productName` String - The product name in the `crashReporter` `options` +* `ver` string - The version of Electron. +* `platform` string - e.g. 'win32'. +* `process_type` string - e.g. 'renderer'. +* `guid` string - e.g. '5e1286fc-da97-479e-918b-6bfb0c3d1c72'. +* `_version` string - The version in `package.json`. +* `_productName` string - The product name in the `crashReporter` `options` object. -* `prod` String - Name of the underlying product. In this case Electron. -* `_companyName` String - The company name in the `crashReporter` `options` +* `prod` string - Name of the underlying product. In this case Electron. +* `_companyName` string - The company name in the `crashReporter` `options` object. * `upload_file_minidump` File - The crash report in the format of `minidump`. * All level one properties of the `extra` object in the `crashReporter` diff --git a/docs/api/debugger.md b/docs/api/debugger.md index 1d97921937662..c29673f3d4840 100644 --- a/docs/api/debugger.md +++ b/docs/api/debugger.md @@ -2,13 +2,15 @@ > An alternate transport for Chrome's remote debugging protocol. -Process: [Main](../glossary.md#main-process) +Process: [Main](../glossary.md#main-process)<br /> +_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ Chrome Developer Tools has a [special binding][rdp] available at JavaScript runtime that allows interacting with pages and instrumenting them. -```javascript +```js const { BrowserWindow } = require('electron') + const win = new BrowserWindow() try { @@ -39,38 +41,37 @@ win.webContents.debugger.sendCommand('Network.enable') Returns: * `event` Event -* `reason` String - Reason for detaching debugger. +* `reason` string - Reason for detaching debugger. Emitted when the debugging session is terminated. This happens either when -`webContents` is closed or devtools is invoked for the attached `webContents`. +`webContents` is closed or DevTools is invoked for the attached `webContents`. #### Event: 'message' Returns: * `event` Event -* `method` String - Method name. +* `method` string - Method name. * `params` any - Event parameters defined by the 'parameters' attribute in the remote debugging protocol. -* `sessionId` String - Unique identifier of attached debugging session, +* `sessionId` string - Unique identifier of attached debugging session, will match the value sent from `debugger.sendCommand`. Emitted whenever the debugging target issues an instrumentation event. [rdp]: https://chromedevtools.github.io/devtools-protocol/ -[`webContents.findInPage`]: web-contents.md#contentsfindinpagetext-options ### Instance Methods #### `debugger.attach([protocolVersion])` -* `protocolVersion` String (optional) - Requested debugging protocol version. +* `protocolVersion` string (optional) - Requested debugging protocol version. Attaches the debugger to the `webContents`. #### `debugger.isAttached()` -Returns `Boolean` - Whether a debugger is attached to the `webContents`. +Returns `boolean` - Whether a debugger is attached to the `webContents`. #### `debugger.detach()` @@ -78,10 +79,10 @@ Detaches the debugger from the `webContents`. #### `debugger.sendCommand(method[, commandParams, sessionId])` -* `method` String - Method name, should be one of the methods defined by the +* `method` string - Method name, should be one of the methods defined by the [remote debugging protocol][rdp]. * `commandParams` any (optional) - JSON object with request parameters. -* `sessionId` String (optional) - send command to the target with associated +* `sessionId` string (optional) - send command to the target with associated debugging session id. The initial value can be obtained by sending [Target.attachToTarget][attachToTarget] message. diff --git a/docs/api/desktop-capturer.md b/docs/api/desktop-capturer.md index 236ae73666ca9..fb1bfb1eb4d27 100644 --- a/docs/api/desktop-capturer.md +++ b/docs/api/desktop-capturer.md @@ -1,76 +1,78 @@ # desktopCapturer > Access information about media sources that can be used to capture audio and -> video from the desktop using the [`navigator.mediaDevices.getUserMedia`] API. +> video from the desktop using the [`navigator.mediaDevices.getUserMedia`][] API. -Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process) +Process: [Main](../glossary.md#main-process) The following example shows how to capture video from a desktop window whose title is `Electron`: -```javascript -// In the renderer process. -const { desktopCapturer } = require('electron') - -desktopCapturer.getSources({ types: ['window', 'screen'] }).then(async sources => { - for (const source of sources) { - if (source.name === 'Electron') { - try { - const stream = await navigator.mediaDevices.getUserMedia({ - audio: false, - video: { - mandatory: { - chromeMediaSource: 'desktop', - chromeMediaSourceId: source.id, - minWidth: 1280, - maxWidth: 1280, - minHeight: 720, - maxHeight: 720 - } - } - }) - handleStream(stream) - } catch (e) { - handleError(e) - } - return - } - } +```js +// main.js +const { app, BrowserWindow, desktopCapturer, session } = require('electron') + +app.whenReady().then(() => { + const mainWindow = new BrowserWindow() + + session.defaultSession.setDisplayMediaRequestHandler((request, callback) => { + desktopCapturer.getSources({ types: ['screen'] }).then((sources) => { + // Grant access to the first screen found. + callback({ video: sources[0], audio: 'loopback' }) + }) + // If true, use the system picker if available. + // Note: this is currently experimental. If the system picker + // is available, it will be used and the media request handler + // will not be invoked. + }, { useSystemPicker: true }) + + mainWindow.loadFile('index.html') }) +``` -function handleStream (stream) { - const video = document.querySelector('video') - video.srcObject = stream - video.onloadedmetadata = (e) => video.play() -} +```js +// renderer.js +const startButton = document.getElementById('startButton') +const stopButton = document.getElementById('stopButton') +const video = document.querySelector('video') + +startButton.addEventListener('click', () => { + navigator.mediaDevices.getDisplayMedia({ + audio: true, + video: { + width: 320, + height: 240, + frameRate: 30 + } + }).then(stream => { + video.srcObject = stream + video.onloadedmetadata = (e) => video.play() + }).catch(e => console.log(e)) +}) -function handleError (e) { - console.log(e) -} +stopButton.addEventListener('click', () => { + video.pause() +}) ``` -To capture video from a source provided by `desktopCapturer` the constraints -passed to [`navigator.mediaDevices.getUserMedia`] must include -`chromeMediaSource: 'desktop'`, and `audio: false`. +```html +<!-- index.html --> +<html> +<meta http-equiv="content-security-policy" content="script-src 'self' 'unsafe-inline'" /> + <body> + <button id="startButton" class="button">Start</button> + <button id="stopButton" class="button">Stop</button> + <video width="320" height="240" autoplay></video> + <script src="renderer.js"></script> + </body> +</html> +``` -To capture both audio and video from the entire desktop the constraints passed -to [`navigator.mediaDevices.getUserMedia`] must include `chromeMediaSource: 'desktop'`, -for both `audio` and `video`, but should not include a `chromeMediaSourceId` constraint. +See [`navigator.mediaDevices.getDisplayMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia) for more information. -```javascript -const constraints = { - audio: { - mandatory: { - chromeMediaSource: 'desktop' - } - }, - video: { - mandatory: { - chromeMediaSource: 'desktop' - } - } -} -``` +> [!NOTE] +> `navigator.mediaDevices.getDisplayMedia` does not permit the use of `deviceId` for +> selection of a source - see [specification](https://w3c.github.io/mediacapture-screen-share/#constraints). ## Methods @@ -78,27 +80,81 @@ The `desktopCapturer` module has the following methods: ### `desktopCapturer.getSources(options)` +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/2963 +changes: + - pr-url: https://github.com/electron/electron/pull/16427 + description: "This method now returns a Promise instead of using a callback function." + breaking-changes-header: api-changed-callback-based-versions-of-promisified-apis +``` +--> + * `options` Object - * `types` String[] - An array of Strings that lists the types of desktop sources - to be captured, available types are `screen` and `window`. + * `types` string[] - An array of strings that lists the types of desktop sources + to be captured, available types can be `screen` and `window`. * `thumbnailSize` [Size](structures/size.md) (optional) - The size that the media source thumbnail should be scaled to. Default is `150` x `150`. Set width or height to 0 when you do not need the thumbnails. This will save the processing time required for capturing the content of each window and screen. - * `fetchWindowIcons` Boolean (optional) - Set to true to enable fetching window icons. The default + * `fetchWindowIcons` boolean (optional) - Set to true to enable fetching window icons. The default value is false. When false the appIcon property of the sources return null. Same if a source has the type screen. Returns `Promise<DesktopCapturerSource[]>` - Resolves with an array of [`DesktopCapturerSource`](structures/desktop-capturer-source.md) objects, each `DesktopCapturerSource` represents a screen or an individual window that can be captured. -**Note** Capturing the screen contents requires user consent on macOS 10.15 Catalina or higher, -which can detected by [`systemPreferences.getMediaAccessStatus`]. +> [!NOTE] +<!-- markdownlint-disable-next-line MD032 --> +> * Capturing audio requires `NSAudioCaptureUsageDescription` Info.plist key on macOS 14.2 Sonoma and higher - [read more](#macos-versions-142-or-higher). +> * Capturing the screen contents requires user consent on macOS 10.15 Catalina or higher, which can detected by [`systemPreferences.getMediaAccessStatus`][]. [`navigator.mediaDevices.getUserMedia`]: https://developer.mozilla.org/en/docs/Web/API/MediaDevices/getUserMedia [`systemPreferences.getMediaAccessStatus`]: system-preferences.md#systempreferencesgetmediaaccessstatusmediatype-windows-macos ## Caveats -`navigator.mediaDevices.getUserMedia` does not work on macOS for audio capture due to a fundamental limitation whereby apps that want to access the system's audio require a [signed kernel extension](https://developer.apple.com/library/archive/documentation/Security/Conceptual/System_Integrity_Protection_Guide/KernelExtensions/KernelExtensions.html). Chromium, and by extension Electron, does not provide this. +### Linux + +`desktopCapturer.getSources(options)` only returns a single source on Linux when using Pipewire. + +PipeWire supports a single capture for both screens and windows. If you request the window and screen type, the selected source will be returned as a window capture. + +### macOS versions 14.2 or higher + +`NSAudioCaptureUsageDescription` Info.plist key must be added in order for audio to be captured by +`desktopCapturer`. If instead you are running Electron from another program like a terminal or IDE +then that parent program must contain the Info.plist key. + +This is in order to facillitate use of Apple's new [CoreAudio Tap API](https://developer.apple.com/documentation/CoreAudio/capturing-system-audio-with-core-audio-taps#Configure-the-sample-code-project) by Chromium. + +> [!WARNING] +> Failure of `desktopCapturer` to start an audio stream due to `NSAudioCaptureUsageDescription` +> permission not present will still create a dead audio stream however no warnings or errors are +> displayed. + +As of Electron `v39.0.0-beta.4`, Chromium [made Apple's new `CoreAudio Tap API` the default](https://source.chromium.org/chromium/chromium/src/+/ad17e8f8b93d5f34891b06085d373a668918255e) +for desktop audio capture. There is no fallback to the older `Screen & System Audio Recording` +permissions system even if [CoreAudio Tap API](https://developer.apple.com/documentation/CoreAudio/capturing-system-audio-with-core-audio-taps) stream creation fails. + +If you need to continue using `Screen & System Audio Recording` permissions for `desktopCapturer` +on macOS versions 14.2 and later, you can apply a Chromium feature flag to force use of that older +permissions system: + +```js +// main.js (right beneath your require/import statments) +app.commandLine.appendSwitch('disable-features', 'MacCatapLoopbackAudioForScreenShare') +``` + +### macOS versions 12.7.6 or lower + +`navigator.mediaDevices.getUserMedia` does not work on macOS versions 12.7.6 and prior for audio +capture due to a fundamental limitation whereby apps that want to access the system's audio require +a [signed kernel extension](https://developer.apple.com/library/archive/documentation/Security/Conceptual/System_Integrity_Protection_Guide/KernelExtensions/KernelExtensions.html). +Chromium, and by extension Electron, does not provide this. Only in macOS 13 and onwards does Apple +provide APIs to capture desktop audio without the need for a signed kernel extension. -It is possible to circumvent this limitation by capturing system audio with another macOS app like Soundflower and passing it through a virtual audio input device. This virtual device can then be queried with `navigator.mediaDevices.getUserMedia`. +It is possible to circumvent this limitation by capturing system audio with another macOS app like +[BlackHole](https://existential.audio/blackhole/) or [Soundflower](https://rogueamoeba.com/freebies/soundflower/) +and passing it through a virtual audio input device. This virtual device can then be queried +with `navigator.mediaDevices.getUserMedia`. diff --git a/docs/api/dialog.md b/docs/api/dialog.md index 483ff271d2372..a5ade687b26d4 100644 --- a/docs/api/dialog.md +++ b/docs/api/dialog.md @@ -6,8 +6,9 @@ Process: [Main](../glossary.md#main-process) An example of showing a dialog to select multiple files: -```javascript +```js const { dialog } = require('electron') + console.log(dialog.showOpenDialog({ properties: ['openFile', 'multiSelections'] })) ``` @@ -15,21 +16,31 @@ console.log(dialog.showOpenDialog({ properties: ['openFile', 'multiSelections'] The `dialog` module has the following methods: -### `dialog.showOpenDialogSync([browserWindow, ]options)` +### `dialog.showOpenDialogSync([window, ]options)` + +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/16973 +``` +--> -* `browserWindow` [BrowserWindow](browser-window.md) (optional) +* `window` [BaseWindow](base-window.md) (optional) * `options` Object - * `title` String (optional) - * `defaultPath` String (optional) - * `buttonLabel` String (optional) - Custom label for the confirmation button, when + * `title` string (optional) + * `defaultPath` string (optional) - Absolute directory path, absolute file + path, or file name to use by default. If not provided, the dialog will + default to the user's Downloads folder, or their home directory if Downloads + doesn't exist. + * `buttonLabel` string (optional) - Custom label for the confirmation button, when left empty the default label will be used. * `filters` [FileFilter[]](structures/file-filter.md) (optional) - * `properties` String[] (optional) - Contains which features the dialog should + * `properties` string[] (optional) - Contains which features the dialog should use. The following values are supported: * `openFile` - Allow files to be selected. * `openDirectory` - Allow directories to be selected. * `multiSelections` - Allow multiple paths to be selected. - * `showHiddenFiles` - Show hidden files in dialog. + * `showHiddenFiles` _macOS_ _Windows_ _Deprecated_ - Show hidden files in dialog. Deprecated on Linux. * `createDirectory` _macOS_ - Allow creating new directories from dialog. * `promptToCreate` _Windows_ - Prompt for creation if the file path entered in the dialog does not exist. This does not actually create the file at @@ -41,18 +52,20 @@ The `dialog` module has the following methods: * `treatPackageAsDirectory` _macOS_ - Treat packages, such as `.app` folders, as a directory instead of a file. * `dontAddToRecent` _Windows_ - Do not add the item being opened to the recent documents list. - * `message` String (optional) _macOS_ - Message to display above input + * `message` string (optional) _macOS_ - Message to display above input boxes. - * `securityScopedBookmarks` Boolean (optional) _macOS_ _mas_ - Create [security scoped bookmarks](https://developer.apple.com/library/content/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW16) when packaged for the Mac App Store. + * `securityScopedBookmarks` boolean (optional) _macOS_ _mas_ - Create [security scoped bookmarks](https://developer.apple.com/library/content/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW16) when packaged for the Mac App Store. -Returns `String[] | undefined`, the file paths chosen by the user; if the dialog is cancelled it returns `undefined`. +Returns `string[] | undefined`, the file paths chosen by the user; if the dialog is cancelled it returns `undefined`. -The `browserWindow` argument allows the dialog to attach itself to a parent window, making it modal. +The `window` argument allows the dialog to attach itself to a parent window, making it modal. The `filters` specifies an array of file types that can be displayed or selected when you want to limit the user to a specific type. For example: -```javascript +<!-- eslint-skip --> + +```js { filters: [ { name: 'Images', extensions: ['jpg', 'png', 'gif'] }, @@ -67,32 +80,51 @@ The `extensions` array should contain extensions without wildcards or dots (e.g. `'png'` is good but `'.png'` and `'*.png'` are bad). To show all files, use the `'*'` wildcard (no other wildcard is supported). -**Note:** On Windows and Linux an open dialog can not be both a file selector -and a directory selector, so if you set `properties` to -`['openFile', 'openDirectory']` on these platforms, a directory selector will be -shown. +> [!NOTE] +> On Windows and Linux an open dialog can not be both a file selector +> and a directory selector, so if you set `properties` to +> `['openFile', 'openDirectory']` on these platforms, a directory selector will be +> shown. -```js +```js @ts-type={mainWindow:Electron.BaseWindow} dialog.showOpenDialogSync(mainWindow, { properties: ['openFile', 'openDirectory'] }) ``` -### `dialog.showOpenDialog([browserWindow, ]options)` +> [!NOTE] +> On Linux `defaultPath` is not supported when using portal file chooser +> dialogs unless the portal backend is version 4 or higher. You can use `--xdg-portal-required-version` +> [command-line switch](./command-line-switches.md#--xdg-portal-required-versionversion) +> to force gtk or kde dialogs. -* `browserWindow` [BrowserWindow](browser-window.md) (optional) +### `dialog.showOpenDialog([window, ]options)` + +<!-- +```YAML history +changes: + - pr-url: https://github.com/electron/electron/pull/16973 + description: "This method now returns a Promise instead of using a callback function." + breaking-changes-header: api-changed-callback-based-versions-of-promisified-apis +``` +--> + +* `window` [BaseWindow](base-window.md) (optional) * `options` Object - * `title` String (optional) - * `defaultPath` String (optional) - * `buttonLabel` String (optional) - Custom label for the confirmation button, when + * `title` string (optional) + * `defaultPath` string (optional) - Absolute directory path, absolute file + path, or file name to use by default. If not provided, the dialog will + default to the user's Downloads folder, or their home directory if Downloads + doesn't exist. + * `buttonLabel` string (optional) - Custom label for the confirmation button, when left empty the default label will be used. * `filters` [FileFilter[]](structures/file-filter.md) (optional) - * `properties` String[] (optional) - Contains which features the dialog should + * `properties` string[] (optional) - Contains which features the dialog should use. The following values are supported: * `openFile` - Allow files to be selected. * `openDirectory` - Allow directories to be selected. * `multiSelections` - Allow multiple paths to be selected. - * `showHiddenFiles` - Show hidden files in dialog. + * `showHiddenFiles` _macOS_ _Windows_ _Deprecated_ - Show hidden files in dialog. Deprecated on Linux. * `createDirectory` _macOS_ - Allow creating new directories from dialog. * `promptToCreate` _Windows_ - Prompt for creation if the file path entered in the dialog does not exist. This does not actually create the file at @@ -104,22 +136,24 @@ dialog.showOpenDialogSync(mainWindow, { * `treatPackageAsDirectory` _macOS_ - Treat packages, such as `.app` folders, as a directory instead of a file. * `dontAddToRecent` _Windows_ - Do not add the item being opened to the recent documents list. - * `message` String (optional) _macOS_ - Message to display above input + * `message` string (optional) _macOS_ - Message to display above input boxes. - * `securityScopedBookmarks` Boolean (optional) _macOS_ _mas_ - Create [security scoped bookmarks](https://developer.apple.com/library/content/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW16) when packaged for the Mac App Store. + * `securityScopedBookmarks` boolean (optional) _macOS_ _mas_ - Create [security scoped bookmarks](https://developer.apple.com/library/content/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW16) when packaged for the Mac App Store. Returns `Promise<Object>` - Resolve with an object containing the following: -* `canceled` Boolean - whether or not the dialog was canceled. -* `filePaths` String[] - An array of file paths chosen by the user. If the dialog is cancelled this will be an empty array. -* `bookmarks` String[] (optional) _macOS_ _mas_ - An array matching the `filePaths` array of base64 encoded strings which contains security scoped bookmark data. `securityScopedBookmarks` must be enabled for this to be populated. (For return values, see [table here](#bookmarks-array).) +* `canceled` boolean - whether or not the dialog was canceled. +* `filePaths` string[] - An array of file paths chosen by the user. If the dialog is cancelled this will be an empty array. +* `bookmarks` string[] (optional) _macOS_ _mas_ - An array matching the `filePaths` array of base64 encoded strings which contains security scoped bookmark data. `securityScopedBookmarks` must be enabled for this to be populated. (For return values, see [table here](#bookmarks-array).) -The `browserWindow` argument allows the dialog to attach itself to a parent window, making it modal. +The `window` argument allows the dialog to attach itself to a parent window, making it modal. The `filters` specifies an array of file types that can be displayed or selected when you want to limit the user to a specific type. For example: -```javascript +<!-- eslint-skip --> + +```js { filters: [ { name: 'Images', extensions: ['jpg', 'png', 'gif'] }, @@ -134,12 +168,13 @@ The `extensions` array should contain extensions without wildcards or dots (e.g. `'png'` is good but `'.png'` and `'*.png'` are bad). To show all files, use the `'*'` wildcard (no other wildcard is supported). -**Note:** On Windows and Linux an open dialog can not be both a file selector -and a directory selector, so if you set `properties` to -`['openFile', 'openDirectory']` on these platforms, a directory selector will be -shown. +> [!NOTE] +> On Windows and Linux an open dialog can not be both a file selector +> and a directory selector, so if you set `properties` to +> `['openFile', 'openDirectory']` on these platforms, a directory selector will be +> shown. -```js +```js @ts-type={mainWindow:Electron.BaseWindow} dialog.showOpenDialog(mainWindow, { properties: ['openFile', 'openDirectory'] }).then(result => { @@ -150,104 +185,135 @@ dialog.showOpenDialog(mainWindow, { }) ``` -### `dialog.showSaveDialogSync([browserWindow, ]options)` +> [!NOTE] +> On Linux `defaultPath` is not supported when using portal file chooser +> dialogs unless the portal backend is version 4 or higher. You can use `--xdg-portal-required-version` +> [command-line switch](./command-line-switches.md#--xdg-portal-required-versionversion) +> to force gtk or kde dialogs. + +### `dialog.showSaveDialogSync([window, ]options)` -* `browserWindow` [BrowserWindow](browser-window.md) (optional) +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/17054 +``` +--> + +* `window` [BaseWindow](base-window.md) (optional) * `options` Object - * `title` String (optional) - * `defaultPath` String (optional) - Absolute directory path, absolute file - path, or file name to use by default. - * `buttonLabel` String (optional) - Custom label for the confirmation button, when + * `title` string (optional) - The dialog title. Cannot be displayed on some _Linux_ desktop environments. + * `defaultPath` string (optional) - Absolute directory path, absolute file + path, or file name to use by default. If not provided, the dialog will + default to the user's Downloads folder, or their home directory if Downloads + doesn't exist. + * `buttonLabel` string (optional) - Custom label for the confirmation button, when left empty the default label will be used. * `filters` [FileFilter[]](structures/file-filter.md) (optional) - * `message` String (optional) _macOS_ - Message to display above text fields. - * `nameFieldLabel` String (optional) _macOS_ - Custom label for the text + * `message` string (optional) _macOS_ - Message to display above text fields. + * `nameFieldLabel` string (optional) _macOS_ - Custom label for the text displayed in front of the filename text field. - * `showsTagField` Boolean (optional) _macOS_ - Show the tags input box, + * `showsTagField` boolean (optional) _macOS_ - Show the tags input box, defaults to `true`. - * `properties` String[] (optional) - * `showHiddenFiles` - Show hidden files in dialog. + * `properties` string[] (optional) + * `showHiddenFiles` _macOS_ _Windows_ _Deprecated_ - Show hidden files in dialog. Deprecated on Linux. * `createDirectory` _macOS_ - Allow creating new directories from dialog. * `treatPackageAsDirectory` _macOS_ - Treat packages, such as `.app` folders, as a directory instead of a file. * `showOverwriteConfirmation` _Linux_ - Sets whether the user will be presented a confirmation dialog if the user types a file name that already exists. * `dontAddToRecent` _Windows_ - Do not add the item being saved to the recent documents list. - * `securityScopedBookmarks` Boolean (optional) _macOS_ _mas_ - Create a [security scoped bookmark](https://developer.apple.com/library/content/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW16) when packaged for the Mac App Store. If this option is enabled and the file doesn't already exist a blank file will be created at the chosen path. + * `securityScopedBookmarks` boolean (optional) _macOS_ _mas_ - Create a [security scoped bookmark](https://developer.apple.com/library/content/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW16) when packaged for the Mac App Store. If this option is enabled and the file doesn't already exist a blank file will be created at the chosen path. -Returns `String | undefined`, the path of the file chosen by the user; if the dialog is cancelled it returns `undefined`. +Returns `string`, the path of the file chosen by the user; if the dialog is cancelled it returns an empty string. -The `browserWindow` argument allows the dialog to attach itself to a parent window, making it modal. +The `window` argument allows the dialog to attach itself to a parent window, making it modal. The `filters` specifies an array of file types that can be displayed, see `dialog.showOpenDialog` for an example. -### `dialog.showSaveDialog([browserWindow, ]options)` +### `dialog.showSaveDialog([window, ]options)` + +<!-- +```YAML history +changes: + - pr-url: https://github.com/electron/electron/pull/17054 + description: "This method now returns a Promise instead of using a callback function." + breaking-changes-header: api-changed-callback-based-versions-of-promisified-apis +``` +--> -* `browserWindow` [BrowserWindow](browser-window.md) (optional) +* `window` [BaseWindow](base-window.md) (optional) * `options` Object - * `title` String (optional) - * `defaultPath` String (optional) - Absolute directory path, absolute file - path, or file name to use by default. - * `buttonLabel` String (optional) - Custom label for the confirmation button, when + * `title` string (optional) - The dialog title. Cannot be displayed on some _Linux_ desktop environments. + * `defaultPath` string (optional) - Absolute directory path, absolute file + path, or file name to use by default. If not provided, the dialog will + default to the user's Downloads folder, or their home directory if Downloads + doesn't exist. + * `buttonLabel` string (optional) - Custom label for the confirmation button, when left empty the default label will be used. * `filters` [FileFilter[]](structures/file-filter.md) (optional) - * `message` String (optional) _macOS_ - Message to display above text fields. - * `nameFieldLabel` String (optional) _macOS_ - Custom label for the text + * `message` string (optional) _macOS_ - Message to display above text fields. + * `nameFieldLabel` string (optional) _macOS_ - Custom label for the text displayed in front of the filename text field. - * `showsTagField` Boolean (optional) _macOS_ - Show the tags input box, defaults to `true`. - * `properties` String[] (optional) - * `showHiddenFiles` - Show hidden files in dialog. + * `showsTagField` boolean (optional) _macOS_ - Show the tags input box, defaults to `true`. + * `properties` string[] (optional) + * `showHiddenFiles` _macOS_ _Windows_ _Deprecated_ - Show hidden files in dialog. Deprecated on Linux. * `createDirectory` _macOS_ - Allow creating new directories from dialog. * `treatPackageAsDirectory` _macOS_ - Treat packages, such as `.app` folders, as a directory instead of a file. * `showOverwriteConfirmation` _Linux_ - Sets whether the user will be presented a confirmation dialog if the user types a file name that already exists. * `dontAddToRecent` _Windows_ - Do not add the item being saved to the recent documents list. - * `securityScopedBookmarks` Boolean (optional) _macOS_ _mas_ - Create a [security scoped bookmark](https://developer.apple.com/library/content/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW16) when packaged for the Mac App Store. If this option is enabled and the file doesn't already exist a blank file will be created at the chosen path. + * `securityScopedBookmarks` boolean (optional) _macOS_ _mas_ - Create a [security scoped bookmark](https://developer.apple.com/library/content/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW16) when packaged for the Mac App Store. If this option is enabled and the file doesn't already exist a blank file will be created at the chosen path. Returns `Promise<Object>` - Resolve with an object containing the following: -* `canceled` Boolean - whether or not the dialog was canceled. -* `filePath` String (optional) - If the dialog is canceled, this will be `undefined`. -* `bookmark` String (optional) _macOS_ _mas_ - Base64 encoded string which contains the security scoped bookmark data for the saved file. `securityScopedBookmarks` must be enabled for this to be present. (For return values, see [table here](#bookmarks-array).) +* `canceled` boolean - whether or not the dialog was canceled. +* `filePath` string - If the dialog is canceled, this will be an empty string. +* `bookmark` string (optional) _macOS_ _mas_ - Base64 encoded string which contains the security scoped bookmark data for the saved file. `securityScopedBookmarks` must be enabled for this to be present. (For return values, see [table here](#bookmarks-array).) -The `browserWindow` argument allows the dialog to attach itself to a parent window, making it modal. +The `window` argument allows the dialog to attach itself to a parent window, making it modal. The `filters` specifies an array of file types that can be displayed, see `dialog.showOpenDialog` for an example. -**Note:** On macOS, using the asynchronous version is recommended to avoid issues when -expanding and collapsing the dialog. +> [!NOTE] +> On macOS, using the asynchronous version is recommended to avoid issues when +> expanding and collapsing the dialog. -### `dialog.showMessageBoxSync([browserWindow, ]options)` +### `dialog.showMessageBoxSync([window, ]options)` -* `browserWindow` [BrowserWindow](browser-window.md) (optional) +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/17298 +``` +--> + +* `window` [BaseWindow](base-window.md) (optional) * `options` Object - * `message` String - Content of the message box. - * `type` String (optional) - Can be `"none"`, `"info"`, `"error"`, `"question"` or - `"warning"`. On Windows, `"question"` displays the same icon as `"info"`, unless - you set an icon using the `"icon"` option. On macOS, both `"warning"` and - `"error"` display the same warning icon. - * `buttons` String[] (optional) - Array of texts for buttons. On Windows, an empty array + * `message` string - Content of the message box. + * `type` string (optional) - Can be `none`, `info`, `error`, `question` or + `warning`. On Windows, `question` displays the same icon as `info`, unless + you set an icon using the `icon` option. On macOS, both `warning` and + `error` display the same warning icon. + * `buttons` string[] (optional) - Array of texts for buttons. On Windows, an empty array will result in one button labeled "OK". * `defaultId` Integer (optional) - Index of the button in the buttons array which will be selected by default when the message box opens. - * `title` String (optional) - Title of the message box, some platforms will not show it. - * `detail` String (optional) - Extra information of the message. - * `checkboxLabel` String (optional) - If provided, the message box will - include a checkbox with the given label. - * `checkboxChecked` Boolean (optional) - Initial checked state of the - checkbox. `false` by default. - * `icon` ([NativeImage](native-image.md) | String) (optional) + * `title` string (optional) - Title of the message box, some platforms will not show it. + * `detail` string (optional) - Extra information of the message. + * `icon` ([NativeImage](native-image.md) | string) (optional) + * `textWidth` Integer (optional) _macOS_ - Custom width of the text in the message box. * `cancelId` Integer (optional) - The index of the button to be used to cancel the dialog, via the `Esc` key. By default this is assigned to the first button with "cancel" or "no" as the label. If no such labeled buttons exist and this option is not set, `0` will be used as the return value. - * `noLink` Boolean (optional) - On Windows Electron will try to figure out which one of + * `noLink` boolean (optional) - On Windows Electron will try to figure out which one of the `buttons` are common buttons (like "Cancel" or "Yes"), and show the others as command links in the dialog. This can make the dialog appear in the style of modern Windows apps. If you don't like this behavior, you can set `noLink` to `true`. - * `normalizeAccessKeys` Boolean (optional) - Normalize the keyboard access keys + * `normalizeAccessKeys` boolean (optional) - Normalize the keyboard access keys across platforms. Default is `false`. Enabling this assumes `&` is used in the button labels for the placement of the keyboard shortcut access key and labels will be converted so they work correctly on each platform, `&` @@ -261,39 +327,58 @@ Returns `Integer` - the index of the clicked button. Shows a message box, it will block the process until the message box is closed. It returns the index of the clicked button. -The `browserWindow` argument allows the dialog to attach itself to a parent window, making it modal. -If `browserWindow` is not shown dialog will not be attached to it. In such case it will be displayed as an independent window. - -### `dialog.showMessageBox([browserWindow, ]options)` +The `window` argument allows the dialog to attach itself to a parent window, making it modal. +If `window` is not shown dialog will not be attached to it. In such case it will be displayed as an independent window. + +### `dialog.showMessageBox([window, ]options)` + +<!-- +```YAML history +changes: + - pr-url: https://github.com/electron/electron/pull/17298 + description: "This method now returns a Promise instead of using a callback function." + breaking-changes-header: api-changed-callback-based-versions-of-promisified-apis + - pr-url: https://github.com/electron/electron/pull/26102 + description: "Added the `signal` option." + - pr-url: https://github.com/electron/electron/pull/30474 + description: "Added the `textWidth` option." +``` +--> -* `browserWindow` [BrowserWindow](browser-window.md) (optional) +* `window` [BaseWindow](base-window.md) (optional) * `options` Object - * `message` String - Content of the message box. - * `type` String (optional) - Can be `"none"`, `"info"`, `"error"`, `"question"` or - `"warning"`. On Windows, `"question"` displays the same icon as `"info"`, unless - you set an icon using the `"icon"` option. On macOS, both `"warning"` and - `"error"` display the same warning icon. - * `buttons` String[] (optional) - Array of texts for buttons. On Windows, an empty array + * `message` string - Content of the message box. + * `type` string (optional) - Can be `none`, `info`, `error`, `question` or + `warning`. On Windows, `question` displays the same icon as `info`, unless + you set an icon using the `icon` option. On macOS, both `warning` and + `error` display the same warning icon. + * `buttons` string[] (optional) - Array of texts for buttons. On Windows, an empty array will result in one button labeled "OK". * `defaultId` Integer (optional) - Index of the button in the buttons array which will be selected by default when the message box opens. - * `title` String (optional) - Title of the message box, some platforms will not show it. - * `detail` String (optional) - Extra information of the message. - * `checkboxLabel` String (optional) - If provided, the message box will + * `signal` AbortSignal (optional) - Pass an instance of [AbortSignal][] to + optionally close the message box, the message box will behave as if it was + cancelled by the user. On macOS, `signal` does not work with message boxes + that do not have a parent window, since those message boxes run + synchronously due to platform limitations. + * `title` string (optional) - Title of the message box, some platforms will not show it. + * `detail` string (optional) - Extra information of the message. + * `checkboxLabel` string (optional) - If provided, the message box will include a checkbox with the given label. - * `checkboxChecked` Boolean (optional) - Initial checked state of the + * `checkboxChecked` boolean (optional) - Initial checked state of the checkbox. `false` by default. - * `icon` [NativeImage](native-image.md) (optional) + * `icon` ([NativeImage](native-image.md) | string) (optional) + * `textWidth` Integer (optional) _macOS_ - Custom width of the text in the message box. * `cancelId` Integer (optional) - The index of the button to be used to cancel the dialog, via the `Esc` key. By default this is assigned to the first button with "cancel" or "no" as the label. If no such labeled buttons exist and this option is not set, `0` will be used as the return value. - * `noLink` Boolean (optional) - On Windows Electron will try to figure out which one of + * `noLink` boolean (optional) - On Windows Electron will try to figure out which one of the `buttons` are common buttons (like "Cancel" or "Yes"), and show the others as command links in the dialog. This can make the dialog appear in the style of modern Windows apps. If you don't like this behavior, you can set `noLink` to `true`. - * `normalizeAccessKeys` Boolean (optional) - Normalize the keyboard access keys + * `normalizeAccessKeys` boolean (optional) - Normalize the keyboard access keys across platforms. Default is `false`. Enabling this assumes `&` is used in the button labels for the placement of the keyboard shortcut access key and labels will be converted so they work correctly on each platform, `&` @@ -304,50 +389,61 @@ If `browserWindow` is not shown dialog will not be attached to it. In such case Returns `Promise<Object>` - resolves with a promise containing the following properties: -* `response` Number - The index of the clicked button. -* `checkboxChecked` Boolean - The checked state of the checkbox if +* `response` number - The index of the clicked button. +* `checkboxChecked` boolean - The checked state of the checkbox if `checkboxLabel` was set. Otherwise `false`. Shows a message box. -The `browserWindow` argument allows the dialog to attach itself to a parent window, making it modal. +The `window` argument allows the dialog to attach itself to a parent window, making it modal. ### `dialog.showErrorBox(title, content)` -* `title` String - The title to display in the error box. -* `content` String - The text content to display in the error box. +* `title` string - The title to display in the error box. +* `content` string - The text content to display in the error box. Displays a modal dialog that shows an error message. This API can be called safely before the `ready` event the `app` module emits, it is usually used to report errors in early stage of startup. If called -before the app `ready`event on Linux, the message will be emitted to stderr, +before the app `ready` event on Linux, the message will be emitted to stderr, and no GUI dialog will appear. -### `dialog.showCertificateTrustDialog([browserWindow, ]options)` _macOS_ _Windows_ +### `dialog.showCertificateTrustDialog([window, ]options)` _macOS_ _Windows_ -* `browserWindow` [BrowserWindow](browser-window.md) (optional) +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/9099 +changes: + - pr-url: https://github.com/electron/electron/pull/17181 + description: "This method now returns a Promise instead of using a callback function." + breaking-changes-header: api-changed-callback-based-versions-of-promisified-apis +``` +--> + +* `window` [BaseWindow](base-window.md) (optional) * `options` Object * `certificate` [Certificate](structures/certificate.md) - The certificate to trust/import. - * `message` String - The message to display to the user. + * `message` string - The message to display to the user. Returns `Promise<void>` - resolves when the certificate trust dialog is shown. On macOS, this displays a modal dialog that shows a message and certificate information, and gives the user the option of trusting/importing the -certificate. If you provide a `browserWindow` argument the dialog will be +certificate. If you provide a `window` argument the dialog will be attached to the parent window, making it modal. On Windows the options are more limited, due to the Win32 APIs used: * The `message` argument is not used, as the OS provides its own confirmation dialog. -* The `browserWindow` argument is ignored since it is not possible to make +* The `window` argument is ignored since it is not possible to make this confirmation dialog modal. ## Bookmarks array -`showOpenDialog`, `showOpenDialogSync`, `showSaveDialog`, and `showSaveDialogSync` will return a `bookmarks` array. +`showOpenDialog` and `showSaveDialog` resolve to an object with a `bookmarks` field. This field is an array of Base64 encoded strings that contain the [security scoped bookmark](https://developer.apple.com/library/content/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW16) data for the saved file. The `securityScopedBookmarks` option must be enabled for this to be present. | Build Type | securityScopedBookmarks boolean | Return Type | Return Value | |------------|---------------------------------|:-----------:|--------------------------------| @@ -359,8 +455,10 @@ On Windows the options are more limited, due to the Win32 APIs used: ## Sheets On macOS, dialogs are presented as sheets attached to a window if you provide -a [`BrowserWindow`](browser-window.md) reference in the `browserWindow` parameter, or modals if no +a [`BaseWindow`](base-window.md) reference in the `window` parameter, or modals if no window is provided. -You can call `BrowserWindow.getCurrentWindow().setSheetOffset(offset)` to change +You can call `BaseWindow.getCurrentWindow().setSheetOffset(offset)` to change the offset from the window frame where sheets are attached. + +[AbortSignal]: https://nodejs.org/api/globals.html#globals_class_abortsignal diff --git a/docs/api/dock.md b/docs/api/dock.md index 2f1b12bff9d16..6ea2ac956cda0 100644 --- a/docs/api/dock.md +++ b/docs/api/dock.md @@ -2,20 +2,17 @@ > Control your app in the macOS dock -Process: [Main](../glossary.md#main-process) +Process: [Main](../glossary.md#main-process)<br /> +_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ -The following example shows how to bounce your icon on the dock. - -```javascript -const { app } = require('electron') -app.dock.bounce() -``` +> [!TIP] +> See also: [A detailed guide about how to implement Dock menus](../tutorial/macos-dock.md). ### Instance Methods #### `dock.bounce([type])` _macOS_ -* `type` String (optional) - Can be `critical` or `informational`. The default is +* `type` string (optional) - Can be `critical` or `informational`. The default is `informational` Returns `Integer` - an ID representing the request. @@ -27,7 +24,8 @@ When `informational` is passed, the dock icon will bounce for one second. However, the request remains active until either the application becomes active or the request is canceled. -**Nota Bene:** This method can only be used while the app is not focused; when the app is focused it will return -1. +> [!NOTE] +> This method can only be used while the app is not focused; when the app is focused it will return -1. #### `dock.cancelBounce(id)` _macOS_ @@ -37,31 +35,37 @@ Cancel the bounce of `id`. #### `dock.downloadFinished(filePath)` _macOS_ -* `filePath` String +* `filePath` string Bounces the Downloads stack if the filePath is inside the Downloads folder. #### `dock.setBadge(text)` _macOS_ -* `text` String +* `text` string Sets the string to be displayed in the dock’s badging area. +> [!IMPORTANT] +> You need to ensure that your application has the permission to display notifications for this method to work. + #### `dock.getBadge()` _macOS_ -Returns `String` - The badge string of the dock. +Returns `string` - The badge string of the dock. #### `dock.hide()` _macOS_ Hides the dock icon. +> [!IMPORTANT] +> **Known issue:** Calling `dock.hide()` within one second of a previous call will have no effect. As a workaround, ensure at least one second has elapsed between calls — for example, by deferring with a `setTimeout` of 1100ms or more after a previous call. + #### `dock.show()` _macOS_ Returns `Promise<void>` - Resolves when the dock icon is shown. #### `dock.isVisible()` _macOS_ -Returns `Boolean` - Whether the dock icon is visible. +Returns `boolean` - Whether the dock icon is visible. #### `dock.setMenu(menu)` _macOS_ @@ -75,6 +79,8 @@ Returns `Menu | null` - The application's [dock menu][dock-menu]. #### `dock.setIcon(image)` _macOS_ -* `image` ([NativeImage](native-image.md) | String) +* `image` ([NativeImage](native-image.md) | string) Sets the `image` associated with this dock icon. + +[dock-menu]: https://developer.apple.com/design/human-interface-guidelines/dock-menus diff --git a/docs/api/download-item.md b/docs/api/download-item.md index d6cbeb6df364a..253c722f090f4 100644 --- a/docs/api/download-item.md +++ b/docs/api/download-item.md @@ -2,15 +2,17 @@ > Control file downloads from remote sources. -Process: [Main](../glossary.md#main-process) +Process: [Main](../glossary.md#main-process)<br /> +_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ `DownloadItem` is an [EventEmitter][event-emitter] that represents a download item in Electron. It is used in `will-download` event of `Session` class, and allows users to control the download item. -```javascript +```js // In the main process. const { BrowserWindow } = require('electron') + const win = new BrowserWindow() win.webContents.session.on('will-download', (event, item, webContents) => { // Set the save path, making Electron not to prompt a save dialog. @@ -44,7 +46,7 @@ win.webContents.session.on('will-download', (event, item, webContents) => { Returns: * `event` Event -* `state` String - Can be `progressing` or `interrupted`. +* `state` string - Can be `progressing` or `interrupted`. Emitted when the download has been updated and is not done. @@ -58,7 +60,7 @@ The `state` can be one of following: Returns: * `event` Event -* `state` String - Can be `completed`, `cancelled` or `interrupted`. +* `state` string - Can be `completed`, `cancelled` or `interrupted`. Emitted when the download is in a terminal state. This includes a completed download, a cancelled download (via `downloadItem.cancel()`), and interrupted @@ -76,7 +78,7 @@ The `downloadItem` object has the following methods: #### `downloadItem.setSavePath(path)` -* `path` String - Set the save file path of the download item. +* `path` string - Set the save file path of the download item. The API is only available in session's `will-download` callback function. If `path` doesn't exist, Electron will try to make the directory recursively. @@ -85,7 +87,7 @@ routine to determine the save path; this usually prompts a save dialog. #### `downloadItem.getSavePath()` -Returns `String` - The save path of the download item. This will be either the path +Returns `string` - The save path of the download item. This will be either the path set via `downloadItem.setSavePath(path)` or the path selected from the shown save dialog. @@ -108,17 +110,18 @@ Pauses the download. #### `downloadItem.isPaused()` -Returns `Boolean` - Whether the download is paused. +Returns `boolean` - Whether the download is paused. #### `downloadItem.resume()` Resumes the download that has been paused. -**Note:** To enable resumable downloads the server you are downloading from must support range requests and provide both `Last-Modified` and `ETag` header values. Otherwise `resume()` will dismiss previously received bytes and restart the download from the beginning. +> [!NOTE] +> To enable resumable downloads the server you are downloading from must support range requests and provide both `Last-Modified` and `ETag` header values. Otherwise `resume()` will dismiss previously received bytes and restart the download from the beginning. #### `downloadItem.canResume()` -Returns `Boolean` - Whether the download can resume. +Returns `boolean` - Whether the download can resume. #### `downloadItem.cancel()` @@ -126,23 +129,28 @@ Cancels the download operation. #### `downloadItem.getURL()` -Returns `String` - The origin URL where the item is downloaded from. +Returns `string` - The origin URL where the item is downloaded from. #### `downloadItem.getMimeType()` -Returns `String` - The files mime type. +Returns `string` - The files mime type. #### `downloadItem.hasUserGesture()` -Returns `Boolean` - Whether the download has user gesture. +Returns `boolean` - Whether the download has user gesture. #### `downloadItem.getFilename()` -Returns `String` - The file name of the download item. +Returns `string` - The file name of the download item. + +> [!NOTE] +> The file name is not always the same as the actual one saved in local +> disk. If user changes the file name in a prompted download saving dialog, the +> actual name of saved file will be different. -**Note:** The file name is not always the same as the actual one saved in local -disk. If user changes the file name in a prompted download saving dialog, the -actual name of saved file will be different. +#### `downloadItem.getCurrentBytesPerSecond()` + +Returns `Integer` - The current download speed in bytes per second. #### `downloadItem.getTotalBytes()` @@ -154,40 +162,49 @@ If the size is unknown, it returns 0. Returns `Integer` - The received bytes of the download item. +#### `downloadItem.getPercentComplete()` + +Returns `Integer` - The download completion in percent. + #### `downloadItem.getContentDisposition()` -Returns `String` - The Content-Disposition field from the response +Returns `string` - The Content-Disposition field from the response header. #### `downloadItem.getState()` -Returns `String` - The current state. Can be `progressing`, `completed`, `cancelled` or `interrupted`. +Returns `string` - The current state. Can be `progressing`, `completed`, `cancelled` or `interrupted`. -**Note:** The following methods are useful specifically to resume a -`cancelled` item when session is restarted. +> [!NOTE] +> The following methods are useful specifically to resume a +> `cancelled` item when session is restarted. #### `downloadItem.getURLChain()` -Returns `String[]` - The complete URL chain of the item including any redirects. +Returns `string[]` - The complete URL chain of the item including any redirects. #### `downloadItem.getLastModifiedTime()` -Returns `String` - Last-Modified header value. +Returns `string` - Last-Modified header value. #### `downloadItem.getETag()` -Returns `String` - ETag header value. +Returns `string` - ETag header value. #### `downloadItem.getStartTime()` Returns `Double` - Number of seconds since the UNIX epoch when the download was started. +#### `downloadItem.getEndTime()` + +Returns `Double` - Number of seconds since the UNIX epoch when the download ended. + ### Instance Properties #### `downloadItem.savePath` -A `String` property that determines the save file path of the download item. +A `string` property that determines the save file path of the download item. The property is only available in session's `will-download` callback function. If user doesn't set the save path via the property, Electron will use the original diff --git a/docs/api/environment-variables.md b/docs/api/environment-variables.md index 12103f8eb0b8e..069e42a113fbd 100644 --- a/docs/api/environment-variables.md +++ b/docs/api/environment-variables.md @@ -51,6 +51,18 @@ Unsupported options are: --http-parser ``` +If the [`nodeOptions` fuse](../tutorial/fuses.md#nodeoptions) is disabled, `NODE_OPTIONS` will be ignored. + +### `NODE_EXTRA_CA_CERTS` + +See [Node.js cli documentation](https://github.com/nodejs/node/blob/main/doc/api/cli.md#node_extra_ca_certsfile) for details. + +```sh +export NODE_EXTRA_CA_CERTS=/path/to/cert.pem +``` + +If the [`nodeOptions` fuse](../tutorial/fuses.md#nodeoptions) is disabled, `NODE_EXTRA_CA_CERTS` will be ignored. + ### `GOOGLE_API_KEY` Geolocation support in Electron requires the use of Google Cloud Platform's @@ -59,7 +71,7 @@ geolocation webservice. To enable this feature, acquire a and place the following code in your main process file, before opening any browser windows that will make geolocation requests: -```javascript +```js process.env.GOOGLE_API_KEY = 'YOUR_KEY_HERE' ``` @@ -92,6 +104,8 @@ you would when running the normal Node.js executable, with the exception of the These flags are disabled owing to the fact that Electron uses BoringSSL instead of OpenSSL when building Node.js' `crypto` module, and so will not work as designed. +If the [`runAsNode` fuse](../tutorial/fuses.md#runasnode) is disabled, `ELECTRON_RUN_AS_NODE` will be ignored. + ### `ELECTRON_NO_ATTACH_CONSOLE` _Windows_ Don't attach to the current console session. @@ -118,7 +132,48 @@ debugging purposes. ### `ELECTRON_ENABLE_LOGGING` -Prints Chrome's internal logging to the console. +Prints Chromium's internal logging to the console. + +Setting this variable is the same as passing `--enable-logging` +on the command line. For more info, see `--enable-logging` in +[command-line switches](./command-line-switches.md#--enable-loggingfile). + +### `ELECTRON_LOG_FILE` + +Sets the file destination for Chromium's internal logging. + +Setting this variable is the same as passing `--log-file` +on the command line. For more info, see `--log-file` in +[command-line switches](./command-line-switches.md#--log-filepath). + +### `ELECTRON_DEBUG_NOTIFICATIONS` + +Adds extra logs to [`Notification`](./notification.md) lifecycles on macOS to aid in debugging. Extra logging will be displayed when new Notifications are created or activated. They will also be displayed when common actions are taken: a notification is shown, dismissed, its button is clicked, or it is replied to. + +Sample output: + +```sh +Notification created (com.github.Electron:notification:EAF7B87C-A113-43D7-8E76-F88EC9D73D44) +Notification displayed (com.github.Electron:notification:EAF7B87C-A113-43D7-8E76-F88EC9D73D44) +Notification activated (com.github.Electron:notification:EAF7B87C-A113-43D7-8E76-F88EC9D73D44) +Notification replied to (com.github.Electron:notification:EAF7B87C-A113-43D7-8E76-F88EC9D73D44) +``` + +### `ELECTRON_DEBUG_MSIX_UPDATER` + +Adds extra logs to MSIX updater operations on Windows to aid in debugging. Extra logging will be displayed when MSIX update operations are initiated, including package updates, package registration, and restart registration. This helps diagnose issues with MSIX package updates and deployments. + +Sample output: + +```sh +UpdateMsix called with URI: https://example.com/app.msix +DoUpdateMsix: Starting +Calling AddPackageByUriAsync... URI: https://example.com/app.msix +Update options - deferRegistration: true, developerMode: false, forceShutdown: false, forceTargetShutdown: false, forceUpdateFromAnyVersion: false +Waiting for deployment... +Deployment finished. +MSIX Deployment completed. +``` ### `ELECTRON_LOG_ASAR_READS` @@ -148,13 +203,22 @@ the one downloaded by `npm install`. Usage: export ELECTRON_OVERRIDE_DIST_PATH=/Users/username/projects/electron/out/Testing ``` -## Set By Electron +### `ELECTRON_INSTALL_PLATFORM` + +Manually overrides platform used by `electron` package during an install. +This can be useful if you are on one platform (e.g macOS) but want to +download binaries for another platform (e.g Windows or Linux). Usage: -Electron sets some variables in your environment at runtime. +```sh +ELECTRON_INSTALL_PLATFORM=darwin npm install +``` -### `ORIGINAL_XDG_CURRENT_DESKTOP` +### `ELECTRON_INSTALL_ARCH` -This variable is set to the value of `XDG_CURRENT_DESKTOP` that your application -originally launched with. Electron sometimes modifies the value of `XDG_CURRENT_DESKTOP` -to affect other logic within Chromium so if you want access to the _original_ value -you should look up this environment variable instead. +Manually overrides architecture used by `electron` package during an install. +This can be useful if you are on one arch (e.g `arm64`) but want to download +binaries meant for another arch. Note that this will not work under Rosetta. Usage: + +```sh +ELECTRON_INSTALL_ARCH=arm64 npm install +``` diff --git a/docs/api/extensions-api.md b/docs/api/extensions-api.md new file mode 100644 index 0000000000000..0e9a3eeda6918 --- /dev/null +++ b/docs/api/extensions-api.md @@ -0,0 +1,130 @@ +## Class: Extensions + +> Load and interact with extensions. + +Process: [Main](../glossary.md#main-process)<br /> +_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ + +Instances of the `Extensions` class are accessed by using `extensions` property of +a `Session`. + +### Instance Events + +The following events are available on instances of `Extensions`: + +#### Event: 'extension-loaded' + +Returns: + +* `event` Event +* `extension` [Extension](structures/extension.md) + +Emitted after an extension is loaded. This occurs whenever an extension is +added to the "enabled" set of extensions. This includes: + +* Extensions being loaded from `Extensions.loadExtension`. +* Extensions being reloaded: + * from a crash. + * if the extension requested it ([`chrome.runtime.reload()`](https://developer.chrome.com/extensions/runtime#method-reload)). + +#### Event: 'extension-unloaded' + +Returns: + +* `event` Event +* `extension` [Extension](structures/extension.md) + +Emitted after an extension is unloaded. This occurs when +`Session.removeExtension` is called. + +#### Event: 'extension-ready' + +Returns: + +* `event` Event +* `extension` [Extension](structures/extension.md) + +Emitted after an extension is loaded and all necessary browser state is +initialized to support the start of the extension's background page. + +### Instance Methods + +The following methods are available on instances of `Extensions`: + +#### `extensions.loadExtension(path[, options])` + +* `path` string - Path to a directory containing an unpacked Chrome extension +* `options` Object (optional) + * `allowFileAccess` boolean - Whether to allow the extension to read local files over `file://` + protocol and inject content scripts into `file://` pages. This is required e.g. for loading + DevTools extensions on `file://` URLs. Defaults to false. + +Returns `Promise<Extension>` - resolves when the extension is loaded. + +This method will raise an exception if the extension could not be loaded. If +there are warnings when installing the extension (e.g. if the extension +requests an API that Electron does not support) then they will be logged to the +console. + +Note that Electron does not support the full range of Chrome extensions APIs. +See [Supported Extensions APIs](extensions.md#supported-extensions-apis) for +more details on what is supported. + +Note that in previous versions of Electron, extensions that were loaded would +be remembered for future runs of the application. This is no longer the case: +`loadExtension` must be called on every boot of your app if you want the +extension to be loaded. + +```js +const { app, session } = require('electron') + +const path = require('node:path') + +app.whenReady().then(async () => { + await session.defaultSession.extensions.loadExtension( + path.join(__dirname, 'react-devtools'), + // allowFileAccess is required to load the DevTools extension on file:// URLs. + { allowFileAccess: true } + ) + // Note that in order to use the React DevTools extension, you'll need to + // download and unzip a copy of the extension. +}) +``` + +This API does not support loading packed (.crx) extensions. + +> [!NOTE] +> This API cannot be called before the `ready` event of the `app` module +> is emitted. + +> [!NOTE] +> Loading extensions into in-memory (non-persistent) sessions is not +> supported and will throw an error. + +#### `extensions.removeExtension(extensionId)` + +* `extensionId` string - ID of extension to remove + +Unloads an extension. + +> [!NOTE] +> This API cannot be called before the `ready` event of the `app` module +> is emitted. + +#### `extensions.getExtension(extensionId)` + +* `extensionId` string - ID of extension to query + +Returns `Extension | null` - The loaded extension with the given ID. + +> [!NOTE] +> This API cannot be called before the `ready` event of the `app` module +> is emitted. + +#### `extensions.getAllExtensions()` + +Returns `Extension[]` - A list of all loaded extensions. + +> [!NOTE] +> This API cannot be called before the `ready` event of the `app` module +> is emitted. diff --git a/docs/api/extensions.md b/docs/api/extensions.md index a8b32f6ac4133..43f7ccfb40d8a 100644 --- a/docs/api/extensions.md +++ b/docs/api/extensions.md @@ -1,13 +1,13 @@ # Chrome Extension Support -Electron supports a subset of the [Chrome Extensions -API][chrome-extensions-api-index], primarily to support DevTools extensions and -Chromium-internal extensions, but it also happens to support some other -extension capabilities. +Electron supports a subset of the [Chrome Extensions API][chrome-extensions-api-index], +primarily to support DevTools extensions and Chromium-internal extensions, +but it also happens to support some other extension capabilities. [chrome-extensions-api-index]: https://developer.chrome.com/extensions/api_index -> **Note:** Electron does not support arbitrary Chrome extensions from the +> [!NOTE] +> Electron does not support arbitrary Chrome extensions from the > store, and it is a **non-goal** of the Electron project to be perfectly > compatible with Chrome's implementation of Extensions. @@ -15,12 +15,12 @@ extension capabilities. Electron only supports loading unpacked extensions (i.e., `.crx` files do not work). Extensions are installed per-`session`. To load an extension, call -[`ses.loadExtension`](session.md#sesloadextensionpath): +[`ses.extensions.loadExtension`](extensions-api.md#extensionsloadextensionpath-options): ```js const { session } = require('electron') -session.loadExtension('path/to/unpacked/extension').then(({ id }) => { +session.defaultSession.loadExtension('path/to/unpacked/extension').then(({ id }) => { // ... }) ``` @@ -40,18 +40,41 @@ We support the following extensions APIs, with some caveats. Other APIs may additionally be supported, but support for any APIs not listed here is provisional and may be removed. +### Supported Manifest Keys + +- `name` +- `version` +- `author` +- `permissions` +- `content_scripts` +- `default_locale` +- `devtools_page` +- `short_name` +- `host_permissions` (Manifest V3) +- `manifest_version` +- `background` (Manifest V2) +- `minimum_chrome_version` + +See [Manifest file format](https://developer.chrome.com/docs/extensions/mv3/manifest/) for more information about the purpose of each possible key. + ### `chrome.devtools.inspectedWindow` All features of this API are supported. +See [official documentation](https://developer.chrome.com/docs/extensions/reference/devtools_inspectedWindow) for more information. + ### `chrome.devtools.network` All features of this API are supported. +See [official documentation](https://developer.chrome.com/docs/extensions/reference/devtools_network) for more information. + ### `chrome.devtools.panels` All features of this API are supported. +See [official documentation](https://developer.chrome.com/docs/extensions/reference/devtools_panels) for more information. + ### `chrome.extension` The following properties of `chrome.extension` are supported: @@ -63,6 +86,25 @@ The following methods of `chrome.extension` are supported: - `chrome.extension.getURL` - `chrome.extension.getBackgroundPage` +See [official documentation](https://developer.chrome.com/docs/extensions/reference/extension) for more information. + +### `chrome.management` + +The following methods of `chrome.management` are supported: + +- `chrome.management.getAll` +- `chrome.management.get` +- `chrome.management.getSelf` +- `chrome.management.getPermissionWarningsById` +- `chrome.management.getPermissionWarningsByManifest` + +The following events of `chrome.management` are supported: + +- `chrome.management.onEnabled` +- `chrome.management.onDisabled` + +See [official documentation](https://developer.chrome.com/docs/extensions/reference/management) for more information. + ### `chrome.runtime` The following properties of `chrome.runtime` are supported: @@ -78,6 +120,7 @@ The following methods of `chrome.runtime` are supported: - `chrome.runtime.getURL` - `chrome.runtime.connect` - `chrome.runtime.sendMessage` +- `chrome.runtime.reload` The following events of `chrome.runtime` are supported: @@ -88,30 +131,48 @@ The following events of `chrome.runtime` are supported: - `chrome.runtime.onConnect` - `chrome.runtime.onMessage` +See [official documentation](https://developer.chrome.com/docs/extensions/reference/runtime) for more information. + +### `chrome.scripting` + +All features of this API are supported. + +See [official documentation](https://developer.chrome.com/docs/extensions/reference/scripting) for more information. + ### `chrome.storage` -Only `chrome.storage.local` is supported; `chrome.storage.sync` and -`chrome.storage.managed` are not. +The following methods of `chrome.storage` are supported: + +- `chrome.storage.local` + +`chrome.storage.sync` and `chrome.storage.managed` are **not** supported. + +See [official documentation](https://developer.chrome.com/docs/extensions/reference/storage) for more information. ### `chrome.tabs` The following methods of `chrome.tabs` are supported: - `chrome.tabs.sendMessage` +- `chrome.tabs.reload` - `chrome.tabs.executeScript` +- `chrome.tabs.query` (partial support) + - supported properties: `url`, `title`, `audible`, `active`, `muted`. +- `chrome.tabs.update` (partial support) + - supported properties: `url`, `muted`. -> **Note:** In Chrome, passing `-1` as a tab ID signifies the "currently active +> [!NOTE] +> In Chrome, passing `-1` as a tab ID signifies the "currently active > tab". Since Electron has no such concept, passing `-1` as a tab ID is not > supported and will raise an error. -### `chrome.management` +See [official documentation](https://developer.chrome.com/docs/extensions/reference/tabs) for more information. -The following methods of `chrome.management` are supported: +### `chrome.webRequest` -- `chrome.management.getAll` -- `chrome.management.get` -- `chrome.management.getSelf` -- `chrome.management.getPermissionWarningsById` -- `chrome.management.getPermissionWarningsByManifest` -- `chrome.management.onEnabled` -- `chrome.management.onDisabled` +All features of this API are supported. + +> [!NOTE] +> Electron's [`webRequest`](web-request.md) module takes precedence over `chrome.webRequest` if there are conflicting handlers. + +See [official documentation](https://developer.chrome.com/docs/extensions/reference/webRequest) for more information. diff --git a/docs/api/file-object.md b/docs/api/file-object.md deleted file mode 100644 index ea0ec4e4ecb95..0000000000000 --- a/docs/api/file-object.md +++ /dev/null @@ -1,31 +0,0 @@ -# `File` Object - -> Use the HTML5 `File` API to work natively with files on the filesystem. - -The DOM's File interface provides abstraction around native files in order to -let users work on native files directly with the HTML5 file API. Electron has -added a `path` attribute to the `File` interface which exposes the file's real -path on filesystem. - -Example of getting a real path from a dragged-onto-the-app file: - -```html -<div id="holder"> - Drag your file here -</div> - -<script> - document.addEventListener('drop', (e) => { - e.preventDefault(); - e.stopPropagation(); - - for (const f of e.dataTransfer.files) { - console.log('File(s) you dragged here: ', f.path) - } - }); - document.addEventListener('dragover', (e) => { - e.preventDefault(); - e.stopPropagation(); - }); -</script> -``` diff --git a/docs/api/frameless-window.md b/docs/api/frameless-window.md deleted file mode 100644 index b7d893d4b257b..0000000000000 --- a/docs/api/frameless-window.md +++ /dev/null @@ -1,185 +0,0 @@ -# Frameless Window - -> Open a window without toolbars, borders, or other graphical "chrome". - -A frameless window is a window that has no -[chrome](https://developer.mozilla.org/en-US/docs/Glossary/Chrome), the parts of -the window, like toolbars, that are not a part of the web page. These are -options on the [`BrowserWindow`](browser-window.md) class. - -## Create a frameless window - -To create a frameless window, you need to set `frame` to `false` in -[BrowserWindow](browser-window.md)'s `options`: - -```javascript -const { BrowserWindow } = require('electron') -const win = new BrowserWindow({ width: 800, height: 600, frame: false }) -win.show() -``` - -### Alternatives on macOS - -There's an alternative way to specify a chromeless window. -Instead of setting `frame` to `false` which disables both the titlebar and window controls, -you may want to have the title bar hidden and your content extend to the full window size, -yet still preserve the window controls ("traffic lights") for standard window actions. -You can do so by specifying the `titleBarStyle` option: - -#### `hidden` - -Results in a hidden title bar and a full size content window, yet the title bar still has the standard window controls (“traffic lights”) in the top left. - -```javascript -const { BrowserWindow } = require('electron') -const win = new BrowserWindow({ titleBarStyle: 'hidden' }) -win.show() -``` - -#### `hiddenInset` - -Results in a hidden title bar with an alternative look where the traffic light buttons are slightly more inset from the window edge. - -```javascript -const { BrowserWindow } = require('electron') -const win = new BrowserWindow({ titleBarStyle: 'hiddenInset' }) -win.show() -``` - -#### `customButtonsOnHover` - -Uses custom drawn close, and miniaturize buttons that display -when hovering in the top left of the window. The fullscreen button -is not available due to restrictions of frameless windows as they -interface with Apple's macOS window masks. These custom buttons prevent -issues with mouse events that occur with the standard window toolbar buttons. -This option is only applicable for frameless windows. - -```javascript -const { BrowserWindow } = require('electron') -const win = new BrowserWindow({ titleBarStyle: 'customButtonsOnHover', frame: false }) -win.show() -``` - -## Transparent window - -By setting the `transparent` option to `true`, you can also make the frameless -window transparent: - -```javascript -const { BrowserWindow } = require('electron') -const win = new BrowserWindow({ transparent: true, frame: false }) -win.show() -``` - -### Limitations - -* You can not click through the transparent area. We are going to introduce an - API to set window shape to solve this, see - [our issue](https://github.com/electron/electron/issues/1335) for details. -* Transparent windows are not resizable. Setting `resizable` to `true` may make - a transparent window stop working on some platforms. -* The `blur` filter only applies to the web page, so there is no way to apply - blur effect to the content below the window (i.e. other applications open on - the user's system). -* On Windows operating systems, transparent windows will not work when DWM is - disabled. -* On Linux, users have to put `--enable-transparent-visuals --disable-gpu` in - the command line to disable GPU and allow ARGB to make transparent window, - this is caused by an upstream bug that [alpha channel doesn't work on some - NVidia drivers](https://bugs.chromium.org/p/chromium/issues/detail?id=369209) on - Linux. -* On Mac, the native window shadow will not be shown on a transparent window. - -## Click-through window - -To create a click-through window, i.e. making the window ignore all mouse -events, you can call the [win.setIgnoreMouseEvents(ignore)][ignore-mouse-events] -API: - -```javascript -const { BrowserWindow } = require('electron') -const win = new BrowserWindow() -win.setIgnoreMouseEvents(true) -``` - -### Forwarding - -Ignoring mouse messages makes the web page oblivious to mouse movement, meaning -that mouse movement events will not be emitted. On Windows operating systems an -optional parameter can be used to forward mouse move messages to the web page, -allowing events such as `mouseleave` to be emitted: - -```javascript -const { ipcRenderer } = require('electron') -const el = document.getElementById('clickThroughElement') -el.addEventListener('mouseenter', () => { - ipcRenderer.send('set-ignore-mouse-events', true, { forward: true }) -}) -el.addEventListener('mouseleave', () => { - ipcRenderer.send('set-ignore-mouse-events', false) -}) - -// Main process -const { ipcMain } = require('electron') -ipcMain.on('set-ignore-mouse-events', (event, ...args) => { - BrowserWindow.fromWebContents(event.sender).setIgnoreMouseEvents(...args) -}) -``` - -This makes the web page click-through when over `el`, and returns to normal -outside it. - -## Draggable region - -By default, the frameless window is non-draggable. Apps need to specify -`-webkit-app-region: drag` in CSS to tell Electron which regions are draggable -(like the OS's standard titlebar), and apps can also use -`-webkit-app-region: no-drag` to exclude the non-draggable area from the - draggable region. Note that only rectangular shapes are currently supported. - -Note: `-webkit-app-region: drag` is known to have problems while the developer tools are open. See this [GitHub issue](https://github.com/electron/electron/issues/3647) for more information including a workaround. - -To make the whole window draggable, you can add `-webkit-app-region: drag` as -`body`'s style: - -```html -<body style="-webkit-app-region: drag"> -</body> -``` - -And note that if you have made the whole window draggable, you must also mark -buttons as non-draggable, otherwise it would be impossible for users to click on -them: - -```css -button { - -webkit-app-region: no-drag; -} -``` - -If you're only setting a custom titlebar as draggable, you also need to make all -buttons in titlebar non-draggable. - -## Text selection - -In a frameless window the dragging behavior may conflict with selecting text. -For example, when you drag the titlebar you may accidentally select the text on -the titlebar. To prevent this, you need to disable text selection within a -draggable area like this: - -```css -.titlebar { - -webkit-user-select: none; - -webkit-app-region: drag; -} -``` - -## Context menu - -On some platforms, the draggable area will be treated as a non-client frame, so -when you right click on it a system menu will pop up. To make the context menu -behave correctly on all platforms you should never use a custom context menu on -draggable areas. - -[ignore-mouse-events]: browser-window.md#winsetignoremouseeventsignore-options diff --git a/docs/api/global-shortcut.md b/docs/api/global-shortcut.md index 78263901761d3..dd8c2195f4e99 100644 --- a/docs/api/global-shortcut.md +++ b/docs/api/global-shortcut.md @@ -8,13 +8,21 @@ The `globalShortcut` module can register/unregister a global keyboard shortcut with the operating system so that you can customize the operations for various shortcuts. -**Note:** The shortcut is global; it will work even if the app does -not have the keyboard focus. You should not use this module until the `ready` -event of the app module is emitted. - -```javascript +> [!NOTE] +> The shortcut is global; it will work even if the app does +> not have the keyboard focus. This module cannot be used before the `ready` +> event of the app module is emitted. +> Please also note that it is also possible to use Chromium's +> `GlobalShortcutsPortal` implementation, which allows apps to bind global +> shortcuts when running within a Wayland session. + +```js const { app, globalShortcut } = require('electron') +// Enable usage of Portal's globalShortcuts. This is essential for cases when +// the app runs in a Wayland session. +app.commandLine.appendSwitch('enable-features', 'GlobalShortcutsPortal') + app.whenReady().then(() => { // Register a 'CommandOrControl+X' shortcut listener. const ret = globalShortcut.register('CommandOrControl+X', () => { @@ -38,16 +46,26 @@ app.on('will-quit', () => { }) ``` +> [!TIP] +> See also: [A detailed guide on Keyboard Shortcuts](../tutorial/keyboard-shortcuts.md). + ## Methods The `globalShortcut` module has the following methods: ### `globalShortcut.register(accelerator, callback)` -* `accelerator` [Accelerator](accelerator.md) +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/534 +``` +--> + +* `accelerator` string - An [accelerator](../tutorial/keyboard-shortcuts.md#accelerators) shortcut. * `callback` Function -Returns `Boolean` - Whether or not the shortcut was registered successfully. +Returns `boolean` - Whether or not the shortcut was registered successfully. Registers a global shortcut of `accelerator`. The `callback` is called when the registered shortcut is pressed by the user. @@ -66,7 +84,14 @@ the app has been authorized as a [trusted accessibility client](https://develope ### `globalShortcut.registerAll(accelerators, callback)` -* `accelerators` String[] - an array of [Accelerator](accelerator.md)s. +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/15542 +``` +--> + +* `accelerators` string[] - An array of [accelerator](../tutorial/keyboard-shortcuts.md#accelerators) shortcuts. * `callback` Function Registers a global shortcut of all `accelerator` items in `accelerators`. The `callback` is called when any of the registered shortcuts are pressed by the user. @@ -85,9 +110,16 @@ the app has been authorized as a [trusted accessibility client](https://develope ### `globalShortcut.isRegistered(accelerator)` -* `accelerator` [Accelerator](accelerator.md) +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/534 +``` +--> + +* `accelerator` string - An [accelerator](../tutorial/keyboard-shortcuts.md#accelerators) shortcut. -Returns `Boolean` - Whether this application has registered `accelerator`. +Returns `boolean` - Whether this application has registered `accelerator`. When the accelerator is already taken by other applications, this call will still return `false`. This behavior is intended by operating systems, since they @@ -95,10 +127,55 @@ don't want applications to fight for global shortcuts. ### `globalShortcut.unregister(accelerator)` -* `accelerator` [Accelerator](accelerator.md) +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/534 +``` +--> + +* `accelerator` string - An [accelerator](../tutorial/keyboard-shortcuts.md#accelerators) shortcut. Unregisters the global shortcut of `accelerator`. ### `globalShortcut.unregisterAll()` +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/534 +``` +--> + Unregisters all of the global shortcuts. + +### `globalShortcut.setSuspended(suspended)` + +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/50425 +``` +--> + +* `suspended` boolean - Whether global shortcut handling should be suspended. + +Suspends or resumes global shortcut handling. When suspended, all registered +global shortcuts will stop listening for key presses. When resumed, all +previously registered shortcuts will begin listening again. New shortcut +registrations will fail while handling is suspended. + +This can be useful when you want to temporarily allow the user to press key +combinations without your application intercepting them, for example while +displaying a UI to rebind shortcuts. + +### `globalShortcut.isSuspended()` + +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/50425 +``` +--> + +Returns `boolean` - Whether global shortcut handling is currently suspended. diff --git a/docs/api/image-view.md b/docs/api/image-view.md new file mode 100644 index 0000000000000..80c4c8aea3d27 --- /dev/null +++ b/docs/api/image-view.md @@ -0,0 +1,87 @@ +# ImageView + +> A View that displays an image. + +Process: [Main](../glossary.md#main-process) + +This module cannot be used until the `ready` event of the `app` +module is emitted. + +Useful for showing splash screens that will be swapped for `WebContentsView`s +when the content finishes loading. + +Note that `ImageView` is experimental and may be changed or removed in the future. + +```js +const { BaseWindow, ImageView, nativeImage, WebContentsView } = require('electron') + +const path = require('node:path') + +const win = new BaseWindow({ width: 800, height: 600 }) + +// Create a "splash screen" image to display while the WebContentsView loads +const splashView = new ImageView() +const splashImage = nativeImage.createFromPath(path.join(__dirname, 'loading.png')) +splashView.setImage(splashImage) +win.setContentView(splashView) + +const webContentsView = new WebContentsView() +webContentsView.webContents.once('did-finish-load', () => { + // Now that the WebContentsView has loaded, swap out the "splash screen" ImageView + win.setContentView(webContentsView) +}) +webContentsView.webContents.loadURL('https://electronjs.org') +``` + +## Class: ImageView extends `View` + +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/46760 +``` +--> + +> A View that displays an image. + +Process: [Main](../glossary.md#main-process) + +`ImageView` inherits from [`View`](view.md). + +`ImageView` is an [EventEmitter][event-emitter]. + +> [!WARNING] +> Electron's built-in classes cannot be subclassed in user code. +> For more information, see [the FAQ](../faq.md#class-inheritance-does-not-work-with-electron-built-in-modules). + +### `new ImageView()` _Experimental_ + +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/46760 +``` +--> + +Creates an ImageView. + +### Instance Methods + +The following methods are available on instances of the `ImageView` class, in +addition to those inherited from [View](view.md): + +#### `image.setImage(image)` _Experimental_ + +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/46760 +``` +--> + +* `image` NativeImage + +Sets the image for this `ImageView`. Note that only image formats supported by +`NativeImage` can be used with an `ImageView`. + +[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter diff --git a/docs/api/in-app-purchase.md b/docs/api/in-app-purchase.md index b9af8e8e5906b..b14b4ef1ba354 100644 --- a/docs/api/in-app-purchase.md +++ b/docs/api/in-app-purchase.md @@ -1,5 +1,12 @@ # inAppPurchase +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/11292 +``` +--> + > In-app purchases on Mac App Store. Process: [Main](../glossary.md#main-process) @@ -10,29 +17,62 @@ The `inAppPurchase` module emits the following events: ### Event: 'transactions-updated' -Emitted when one or more transactions have been updated. +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/11292 +``` +--> Returns: * `event` Event * `transactions` Transaction[] - Array of [`Transaction`](structures/transaction.md) objects. +Emitted when one or more transactions have been updated. + ## Methods The `inAppPurchase` module has the following methods: -### `inAppPurchase.purchaseProduct(productID[, quantity])` +### `inAppPurchase.purchaseProduct(productID[, opts])` + +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/11292 +changes: + - pr-url: https://github.com/electron/electron/pull/17355 + description: "This method now returns a Promise instead of using a callback function." + breaking-changes-header: api-changed-callback-based-versions-of-promisified-apis + - pr-url: https://github.com/electron/electron/pull/35902 + description: "Added `username` option to `opts` parameter." +``` +--> -* `productID` String - The identifiers of the product to purchase. (The identifier of `com.example.app.product1` is `product1`). -* `quantity` Integer (optional) - The number of items the user wants to purchase. +* `productID` string +* `opts` Integer | Object (optional) - If specified as an integer, defines the quantity. + * `quantity` Integer (optional) - The number of items the user wants to purchase. + * `username` string (optional) - The string that associates the transaction with a user account on your service (applicationUsername). -Returns `Promise<Boolean>` - Returns `true` if the product is valid and added to the payment queue. +Returns `Promise<boolean>` - Returns `true` if the product is valid and added to the payment queue. You should listen for the `transactions-updated` event as soon as possible and certainly before you call `purchaseProduct`. ### `inAppPurchase.getProducts(productIDs)` -* `productIDs` String[] - The identifiers of the products to get. +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/12464 +changes: + - pr-url: https://github.com/electron/electron/pull/17355 + description: "This method now returns a Promise instead of using a callback function." + breaking-changes-header: api-changed-callback-based-versions-of-promisified-apis +``` +--> + +* `productIDs` string[] - The identifiers of the products to get. Returns `Promise<Product[]>` - Resolves with an array of [`Product`](structures/product.md) objects. @@ -40,24 +80,59 @@ Retrieves the product descriptions. ### `inAppPurchase.canMakePayments()` -Returns `Boolean` - whether a user can make a payment. +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/11292 +``` +--> + +Returns `boolean` - whether a user can make a payment. ### `inAppPurchase.restoreCompletedTransactions()` +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/21461 +``` +--> + Restores finished transactions. This method can be called either to install purchases on additional devices, or to restore purchases for an application that the user deleted and reinstalled. [The payment queue](https://developer.apple.com/documentation/storekit/skpaymentqueue?language=objc) delivers a new transaction for each previously completed transaction that can be restored. Each transaction includes a copy of the original transaction. ### `inAppPurchase.getReceiptURL()` -Returns `String` - the path to the receipt. +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/11292 +``` +--> + +Returns `string` - the path to the receipt. ### `inAppPurchase.finishAllTransactions()` +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/12464 +``` +--> + Completes all pending transactions. ### `inAppPurchase.finishTransactionByDate(date)` -* `date` String - The ISO formatted date of the transaction to finish. +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/12464 +``` +--> + +* `date` string - The ISO formatted date of the transaction to finish. Completes the pending transactions corresponding to the date. diff --git a/docs/api/incoming-message.md b/docs/api/incoming-message.md index 21dd938b32cce..5f498f40fa64c 100644 --- a/docs/api/incoming-message.md +++ b/docs/api/incoming-message.md @@ -2,7 +2,8 @@ > Handle responses to HTTP/HTTPS requests. -Process: [Main](../glossary.md#main-process) +Process: [Main](../glossary.md#main-process), [Utility](../glossary.md#utility-process)<br /> +_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ `IncomingMessage` implements the [Readable Stream](https://nodejs.org/api/stream.html#stream_readable_streams) interface and is therefore an [EventEmitter][event-emitter]. @@ -30,10 +31,10 @@ Emitted when a request has been canceled during an ongoing HTTP transaction. Returns: -`error` Error - Typically holds an error string identifying failure root cause. +* `error` Error - Typically holds an error string identifying failure root cause. Emitted when an error was encountered while streaming response data events. For -instance, if the server closes the underlying while the response is still +instance, if the server closes the underlying connection while the response is still streaming, an `error` event will be emitted on the response object and a `close` event will subsequently follow on the request object. @@ -47,7 +48,7 @@ An `Integer` indicating the HTTP response status code. #### `response.statusMessage` -A `String` representing the HTTP status message. +A `string` representing the HTTP status message. #### `response.headers` @@ -65,7 +66,7 @@ formatted as follows: #### `response.httpVersion` -A `String` indicating the HTTP protocol version number. Typical values are '1.0' +A `string` indicating the HTTP protocol version number. Typical values are '1.0' or '1.1'. Additionally `httpVersionMajor` and `httpVersionMinor` are two Integer-valued readable properties that return respectively the HTTP major and minor version numbers. @@ -79,3 +80,25 @@ An `Integer` indicating the HTTP protocol major version number. An `Integer` indicating the HTTP protocol minor version number. [event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter + +#### `response.rawHeaders` + +A `string[]` containing the raw HTTP response headers exactly as they were +received. The keys and values are in the same list. It is not a list of +tuples. So, the even-numbered offsets are key values, and the odd-numbered +offsets are the associated values. Header names are not lowercased, and +duplicates are not merged. + +```js @ts-type={response:Electron.IncomingMessage} +// Prints something like: +// +// [ 'user-agent', +// 'this is invalid because there can be only one', +// 'User-Agent', +// 'curl/7.22.0', +// 'Host', +// '127.0.0.1:8000', +// 'ACCEPT', +// '*/*' ] +console.log(response.rawHeaders) +``` diff --git a/docs/api/ipc-main-service-worker.md b/docs/api/ipc-main-service-worker.md new file mode 100644 index 0000000000000..08a9d63a98174 --- /dev/null +++ b/docs/api/ipc-main-service-worker.md @@ -0,0 +1,79 @@ +## Class: IpcMainServiceWorker + +> Communicate asynchronously from the main process to service workers. + +Process: [Main](../glossary.md#main-process) + +> [!NOTE] +> This API is a subtle variation of [`IpcMain`](ipc-main.md)—targeted for +> communicating with service workers. For communicating with web frames, +> consult the `IpcMain` documentation. + +<!-- TODO(samuelmaddock): refactor doc gen to allow generics to reduce duplication --> + +> [!WARNING] +> Electron's built-in classes cannot be subclassed in user code. +> For more information, see [the FAQ](../faq.md#class-inheritance-does-not-work-with-electron-built-in-modules). + +### Instance Methods + +#### `ipcMainServiceWorker.on(channel, listener)` + +* `channel` string +* `listener` Function + * `event` [IpcMainServiceWorkerEvent][ipc-main-service-worker-event] + * `...args` any[] + +Listens to `channel`, when a new message arrives `listener` would be called with +`listener(event, args...)`. + +#### `ipcMainServiceWorker.once(channel, listener)` + +* `channel` string +* `listener` Function + * `event` [IpcMainServiceWorkerEvent][ipc-main-service-worker-event] + * `...args` any[] + +Adds a one time `listener` function for the event. This `listener` is invoked +only the next time a message is sent to `channel`, after which it is removed. + +#### `ipcMainServiceWorker.removeListener(channel, listener)` + +* `channel` string +* `listener` Function + * `...args` any[] + +Removes the specified `listener` from the listener array for the specified +`channel`. + +#### `ipcMainServiceWorker.removeAllListeners([channel])` + +* `channel` string (optional) + +Removes listeners of the specified `channel`. + +#### `ipcMainServiceWorker.handle(channel, listener)` + +* `channel` string +* `listener` Function\<Promise\<any\> | any\> + * `event` [IpcMainServiceWorkerInvokeEvent][ipc-main-service-worker-invoke-event] + * `...args` any[] + +#### `ipcMainServiceWorker.handleOnce(channel, listener)` + +* `channel` string +* `listener` Function\<Promise\<any\> | any\> + * `event` [IpcMainServiceWorkerInvokeEvent][ipc-main-service-worker-invoke-event] + * `...args` any[] + +Handles a single `invoke`able IPC message, then removes the listener. See +`ipcMainServiceWorker.handle(channel, listener)`. + +#### `ipcMainServiceWorker.removeHandler(channel)` + +* `channel` string + +Removes any handler for `channel`, if present. + +[ipc-main-service-worker-event]:../api/structures/ipc-main-service-worker-event.md +[ipc-main-service-worker-invoke-event]:../api/structures/ipc-main-service-worker-invoke-event.md diff --git a/docs/api/ipc-main.md b/docs/api/ipc-main.md index 58a0e390c9242..b14b010f1339a 100644 --- a/docs/api/ipc-main.md +++ b/docs/api/ipc-main.md @@ -1,3 +1,10 @@ +--- +title: "ipcMain" +description: "Communicate asynchronously from the main process to renderer processes." +slug: ipc-main +hide_title: false +--- + # ipcMain > Communicate asynchronously from the main process to renderer processes. @@ -9,7 +16,9 @@ process, it handles asynchronous and synchronous messages sent from a renderer process (web page). Messages sent from a renderer will be emitted to this module. -## Sending Messages +For usage examples, check out the [IPC tutorial][]. + +## Sending messages It is also possible to send messages from the main process to the renderer process, see [webContents.send][web-contents-send] for more information. @@ -21,78 +30,82 @@ process, see [webContents.send][web-contents-send] for more information. coming from frames that aren't the main frame (e.g. iframes) whereas `event.sender.send(...)` will always send to the main frame. -An example of sending and handling messages between the render and main -processes: - -```javascript -// In main process. -const { ipcMain } = require('electron') -ipcMain.on('asynchronous-message', (event, arg) => { - console.log(arg) // prints "ping" - event.reply('asynchronous-reply', 'pong') -}) - -ipcMain.on('synchronous-message', (event, arg) => { - console.log(arg) // prints "ping" - event.returnValue = 'pong' -}) -``` - -```javascript -// In renderer process (web page). -const { ipcRenderer } = require('electron') -console.log(ipcRenderer.sendSync('synchronous-message', 'ping')) // prints "pong" - -ipcRenderer.on('asynchronous-reply', (event, arg) => { - console.log(arg) // prints "pong" -}) -ipcRenderer.send('asynchronous-message', 'ping') -``` - ## Methods -The `ipcMain` module has the following method to listen for events: +The `ipcMain` module has the following methods to listen for events: ### `ipcMain.on(channel, listener)` -* `channel` String +* `channel` string * `listener` Function - * `event` IpcMainEvent + * `event` [IpcMainEvent][ipc-main-event] * `...args` any[] Listens to `channel`, when a new message arrives `listener` would be called with `listener(event, args...)`. +### `ipcMain.off(channel, listener)` + +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/44651 +``` +--> + +* `channel` string +* `listener` Function + * `event` [IpcMainEvent][ipc-main-event] + * `...args` any[] + +Removes the specified `listener` from the listener array for the specified +`channel`. + ### `ipcMain.once(channel, listener)` -* `channel` String +* `channel` string * `listener` Function - * `event` IpcMainEvent + * `event` [IpcMainEvent][ipc-main-event] * `...args` any[] Adds a one time `listener` function for the event. This `listener` is invoked only the next time a message is sent to `channel`, after which it is removed. +### `ipcMain.addListener(channel, listener)` + +* `channel` string +* `listener` Function + * `event` [IpcMainEvent][ipc-main-event] + * `...args` any[] + +Alias for [`ipcMain.on`](#ipcmainonchannel-listener). + ### `ipcMain.removeListener(channel, listener)` -* `channel` String +* `channel` string * `listener` Function * `...args` any[] -Removes the specified `listener` from the listener array for the specified -`channel`. +Alias for [`ipcMain.off`](#ipcmainoffchannel-listener). ### `ipcMain.removeAllListeners([channel])` -* `channel` String (optional) +* `channel` string (optional) -Removes listeners of the specified `channel`. +Removes all listeners from the specified `channel`. Removes all listeners from all channels if no channel is specified. ### `ipcMain.handle(channel, listener)` -* `channel` String -* `listener` Function<Promise\<void> | any> - * `event` IpcMainInvokeEvent +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/18449 +``` +--> + +* `channel` string +* `listener` Function\<Promise\<any\> | any\> + * `event` [IpcMainInvokeEvent][ipc-main-invoke-event] * `...args` any[] Adds a handler for an `invoke`able IPC. This handler will be called whenever a @@ -102,14 +115,14 @@ If `listener` returns a Promise, the eventual result of the promise will be returned as a reply to the remote caller. Otherwise, the return value of the listener will be used as the value of the reply. -```js -// Main process +```js title='Main Process' @ts-type={somePromise:(...args:unknown[])=>Promise<unknown>} ipcMain.handle('my-invokable-ipc', async (event, ...args) => { const result = await somePromise(...args) return result }) +``` -// Renderer process +```js title='Renderer Process' @ts-type={arg1:unknown} @ts-type={arg2:unknown} async () => { const result = await ipcRenderer.invoke('my-invokable-ipc', arg1, arg2) // ... @@ -120,11 +133,23 @@ The `event` that is passed as the first argument to the handler is the same as that passed to a regular event listener. It includes information about which WebContents is the source of the invoke request. +Errors thrown through `handle` in the main process are not transparent as they +are serialized and only the `message` property from the original error is +provided to the renderer process. Please refer to +[#24427](https://github.com/electron/electron/issues/24427) for details. + ### `ipcMain.handleOnce(channel, listener)` -* `channel` String -* `listener` Function<Promise\<void> | any> - * `event` IpcMainInvokeEvent +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/18449 +``` +--> + +* `channel` string +* `listener` Function\<Promise\<any\> | any\> + * `event` [IpcMainInvokeEvent][ipc-main-invoke-event] * `...args` any[] Handles a single `invoke`able IPC message, then removes the listener. See @@ -132,20 +157,19 @@ Handles a single `invoke`able IPC message, then removes the listener. See ### `ipcMain.removeHandler(channel)` -* `channel` String - -Removes any handler for `channel`, if present. - -## IpcMainEvent object - -The documentation for the `event` object passed to the `callback` can be found -in the [`ipc-main-event`](structures/ipc-main-event.md) structure docs. +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/18449 +``` +--> -## IpcMainInvokeEvent object +* `channel` string -The documentation for the `event` object passed to `handle` callbacks can be -found in the [`ipc-main-invoke-event`](structures/ipc-main-invoke-event.md) -structure docs. +Removes any handler for `channel`, if present. +[IPC tutorial]: ../tutorial/ipc.md [event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter -[web-contents-send]: web-contents.md#contentssendchannel-args +[web-contents-send]: ../api/web-contents.md#contentssendchannel-args +[ipc-main-event]:../api/structures/ipc-main-event.md +[ipc-main-invoke-event]:../api/structures/ipc-main-invoke-event.md diff --git a/docs/api/ipc-renderer.md b/docs/api/ipc-renderer.md index 54e6d1896c97a..9438da81268d4 100644 --- a/docs/api/ipc-renderer.md +++ b/docs/api/ipc-renderer.md @@ -1,15 +1,37 @@ +--- +title: "ipcRenderer" +description: "Communicate asynchronously from a renderer process to the main process." +slug: ipc-renderer +hide_title: false +--- + # ipcRenderer +<!-- +```YAML history +changes: + - pr-url: https://github.com/electron/electron/pull/40330 + description: "`ipcRenderer` can no longer be sent over the `contextBridge`" + breaking-changes-header: behavior-changed-ipcrenderer-can-no-longer-be-sent-over-the-contextbridge +``` +--> + > Communicate asynchronously from a renderer process to the main process. Process: [Renderer](../glossary.md#renderer-process) +> [!IMPORTANT] +> If you want to call this API from a renderer process with context isolation enabled, +> place the API call in your preload script and +> [expose](../tutorial/context-isolation.md#after-context-isolation-enabled) it using the +> [`contextBridge`](context-bridge.md) API. + The `ipcRenderer` module is an [EventEmitter][event-emitter]. It provides a few methods so you can send synchronous and asynchronous messages from the render process (web page) to the main process. You can also receive replies from the main process. -See [ipcMain](ipc-main.md) for code examples. +See [IPC tutorial](../tutorial/ipc.md) for code examples. ## Methods @@ -17,61 +39,103 @@ The `ipcRenderer` module has the following method to listen for events and send ### `ipcRenderer.on(channel, listener)` -* `channel` String +* `channel` string * `listener` Function - * `event` IpcRendererEvent + * `event` [IpcRendererEvent][ipc-renderer-event] * `...args` any[] Listens to `channel`, when a new message arrives `listener` would be called with `listener(event, args...)`. +:::warning +Do not expose the `event` argument to the renderer for security reasons! Wrap any +callback that you receive from the renderer in another function like this: +`ipcRenderer.on('my-channel', (event, ...args) => callback(...args))`. +Not wrapping the callback in such a function would expose dangerous Electron APIs +to the renderer process. See the +[security guide](../tutorial/security.md#20-do-not-expose-electron-apis-to-untrusted-web-content) +for more info. +::: + +### `ipcRenderer.off(channel, listener)` + +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/39816 +``` +--> + +* `channel` string +* `listener` Function + * `event` [IpcRendererEvent][ipc-renderer-event] + * `...args` any[] + +Removes the specified `listener` from the listener array for the specified +`channel`. + ### `ipcRenderer.once(channel, listener)` -* `channel` String +* `channel` string * `listener` Function - * `event` IpcRendererEvent + * `event` [IpcRendererEvent][ipc-renderer-event] * `...args` any[] Adds a one time `listener` function for the event. This `listener` is invoked only the next time a message is sent to `channel`, after which it is removed. +### `ipcRenderer.addListener(channel, listener)` + +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/39816 +``` +--> + +* `channel` string +* `listener` Function + * `event` [IpcRendererEvent][ipc-renderer-event] + * `...args` any[] + +Alias for [`ipcRenderer.on`](#ipcrendereronchannel-listener). + ### `ipcRenderer.removeListener(channel, listener)` -* `channel` String +* `channel` string * `listener` Function + * `event` [IpcRendererEvent][ipc-renderer-event] * `...args` any[] -Removes the specified `listener` from the listener array for the specified -`channel`. +Alias for [`ipcRenderer.off`](#ipcrendereroffchannel-listener). -### `ipcRenderer.removeAllListeners(channel)` +### `ipcRenderer.removeAllListeners([channel])` -* `channel` String +* `channel` string (optional) -Removes all listeners, or those of the specified `channel`. +Removes all listeners from the specified `channel`. Removes all listeners from all channels if no channel is specified. ### `ipcRenderer.send(channel, ...args)` -* `channel` String +* `channel` string * `...args` any[] Send an asynchronous message to the main process via `channel`, along with -arguments. Arguments will be serialized with the [Structured Clone -Algorithm][SCA], just like [`window.postMessage`][], so prototype chains will not be +arguments. Arguments will be serialized with the [Structured Clone Algorithm][SCA], +just like [`window.postMessage`][], so prototype chains will not be included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an exception. > **NOTE:** Sending non-standard JavaScript types such as DOM objects or -> special Electron objects is deprecated, and will begin throwing an exception -> starting with Electron 9. - -> **NOTE:** Since the main process does not have support for DOM objects such as +> special Electron objects will throw an exception. +> +> Since the main process does not have support for DOM objects such as > `ImageBitmap`, `File`, `DOMMatrix` and so on, such objects cannot be sent over > Electron's IPC to the main process, as the main process would have no way to decode > them. Attempting to send such objects over IPC will result in an error. The main process handles it by listening for `channel` with the -[`ipcMain`](ipc-main.md) module. +[`ipcMain`](./ipc-main.md) module. If you need to transfer a [`MessagePort`][] to the main process, use [`ipcRenderer.postMessage`](#ipcrendererpostmessagechannel-message-transfer). @@ -79,32 +143,30 @@ If you want to receive a single response from the main process, like the result ### `ipcRenderer.invoke(channel, ...args)` -* `channel` String +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/18449 +``` +--> + +* `channel` string * `...args` any[] Returns `Promise<any>` - Resolves with the response from the main process. Send a message to the main process via `channel` and expect a result -asynchronously. Arguments will be serialized with the [Structured Clone -Algorithm][SCA], just like [`window.postMessage`][], so prototype chains will not be +asynchronously. Arguments will be serialized with the [Structured Clone Algorithm][SCA], +just like [`window.postMessage`][], so prototype chains will not be included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an exception. -> **NOTE**: Sending non-standard JavaScript types such as DOM objects or -> special Electron objects is deprecated, and will begin throwing an exception -> starting with Electron 9. - -> **NOTE:** Since the main process does not have support for DOM objects such as -> `ImageBitmap`, `File`, `DOMMatrix` and so on, such objects cannot be sent over -> Electron's IPC to the main process, as the main process would have no way to decode -> them. Attempting to send such objects over IPC will result in an error. - The main process should listen for `channel` with -[`ipcMain.handle()`](ipc-main.md#ipcmainhandlechannel-listener). +[`ipcMain.handle()`](./ipc-main.md#ipcmainhandlechannel-listener). For example: -```javascript +```js @ts-type={someArgument:unknown} @ts-type={doSomeWork:(arg:unknown)=>Promise<unknown>} // Renderer process ipcRenderer.invoke('some-name', someArgument).then((result) => { // ... @@ -121,39 +183,61 @@ If you need to transfer a [`MessagePort`][] to the main process, use [`ipcRender If you do not need a response to the message, consider using [`ipcRenderer.send`](#ipcrenderersendchannel-args). +> [!NOTE] +> Sending non-standard JavaScript types such as DOM objects or +> special Electron objects will throw an exception. +> +> Since the main process does not have support for DOM objects such as +> `ImageBitmap`, `File`, `DOMMatrix` and so on, such objects cannot be sent over +> Electron's IPC to the main process, as the main process would have no way to decode +> them. Attempting to send such objects over IPC will result in an error. + +> [!NOTE] +> If the handler in the main process throws an error, +> the promise returned by `invoke` will reject. +> However, the `Error` object in the renderer process +> will not be the same as the one thrown in the main process. + ### `ipcRenderer.sendSync(channel, ...args)` -* `channel` String +* `channel` string * `...args` any[] -Returns `any` - The value sent back by the [`ipcMain`](ipc-main.md) handler. +Returns `any` - The value sent back by the [`ipcMain`](./ipc-main.md) handler. Send a message to the main process via `channel` and expect a result -synchronously. Arguments will be serialized with the [Structured Clone -Algorithm][SCA], just like [`window.postMessage`][], so prototype chains will not be +synchronously. Arguments will be serialized with the [Structured Clone Algorithm][SCA], +just like [`window.postMessage`][], so prototype chains will not be included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an exception. -> **NOTE**: Sending non-standard JavaScript types such as DOM objects or -> special Electron objects is deprecated, and will begin throwing an exception -> starting with Electron 9. - -> **NOTE:** Since the main process does not have support for DOM objects such as +> **NOTE:** Sending non-standard JavaScript types such as DOM objects or +> special Electron objects will throw an exception. +> +> Since the main process does not have support for DOM objects such as > `ImageBitmap`, `File`, `DOMMatrix` and so on, such objects cannot be sent over > Electron's IPC to the main process, as the main process would have no way to decode > them. Attempting to send such objects over IPC will result in an error. -The main process handles it by listening for `channel` with [`ipcMain`](ipc-main.md) module, +The main process handles it by listening for `channel` with [`ipcMain`](./ipc-main.md) module, and replies by setting `event.returnValue`. -> :warning: **WARNING**: Sending a synchronous message will block the whole +> [!WARNING] +> Sending a synchronous message will block the whole > renderer process until the reply is received, so use this method only as a > last resort. It's much better to use the asynchronous version, -> [`invoke()`](ipc-renderer.md#ipcrendererinvokechannel-args). +> [`invoke()`](./ipc-renderer.md#ipcrendererinvokechannel-args). ### `ipcRenderer.postMessage(channel, message, [transfer])` -* `channel` String +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/22404 +``` +--> + +* `channel` string * `message` any * `transfer` MessagePort[] (optional) @@ -161,7 +245,7 @@ Send a message to the main process, optionally transferring ownership of zero or more [`MessagePort`][] objects. The transferred `MessagePort` objects will be available in the main process as -[`MessagePortMain`](message-port-main.md) objects by accessing the `ports` +[`MessagePortMain`](./message-port-main.md) objects by accessing the `ports` property of the emitted event. For example: @@ -178,31 +262,19 @@ ipcMain.on('port', (e, msg) => { }) ``` -For more information on using `MessagePort` and `MessageChannel`, see the [MDN -documentation](https://developer.mozilla.org/en-US/docs/Web/API/MessageChannel). - -### `ipcRenderer.sendTo(webContentsId, channel, ...args)` - -* `webContentsId` Number -* `channel` String -* `...args` any[] - -Sends a message to a window with `webContentsId` via `channel`. +For more information on using `MessagePort` and `MessageChannel`, see the +[MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/MessageChannel). ### `ipcRenderer.sendToHost(channel, ...args)` -* `channel` String +* `channel` string * `...args` any[] Like `ipcRenderer.send` but the event will be sent to the `<webview>` element in the host page instead of the main process. -## Event object - -The documentation for the `event` object passed to the `callback` can be found -in the [`ipc-renderer-event`](structures/ipc-renderer-event.md) structure docs. - [event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter [SCA]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm [`window.postMessage`]: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage [`MessagePort`]: https://developer.mozilla.org/en-US/docs/Web/API/MessagePort +[ipc-renderer-event]: ./structures/ipc-renderer-event.md diff --git a/docs/api/locales.md b/docs/api/locales.md deleted file mode 100644 index a45fdbcbe5774..0000000000000 --- a/docs/api/locales.md +++ /dev/null @@ -1,142 +0,0 @@ -# Locales - -> Locale values returned by `app.getLocale()`. - -Electron uses Chromium's `l10n_util` library to fetch the locale. Possible -values are listed below: - -| Language Code | Language Name | -|---------------|---------------| -| af | Afrikaans | -| am | Amharic | -| ar | Arabic | -| az | Azerbaijani | -| be | Belarusian | -| bg | Bulgarian | -| bh | Bihari | -| bn | Bengali | -| br | Breton | -| bs | Bosnian | -| ca | Catalan | -| co | Corsican | -| cs | Czech | -| cy | Welsh | -| da | Danish | -| de | German | -| de-AT | German (Austria) | -| de-CH | German (Switzerland) | -| de-DE | German (Germany) | -| el | Greek | -| en | English | -| en-AU | English (Australia) | -| en-CA | English (Canada) | -| en-GB | English (UK) | -| en-NZ | English (New Zealand) | -| en-US | English (US) | -| en-ZA | English (South Africa) | -| eo | Esperanto | -| es | Spanish | -| es-419 | Spanish (Latin America) | -| et | Estonian | -| eu | Basque | -| fa | Persian | -| fi | Finnish | -| fil | Filipino | -| fo | Faroese | -| fr | French | -| fr-CA | French (Canada) | -| fr-CH | French (Switzerland) | -| fr-FR | French (France) | -| fy | Frisian | -| ga | Irish | -| gd | Scots Gaelic | -| gl | Galician | -| gn | Guarani | -| gu | Gujarati | -| ha | Hausa | -| haw | Hawaiian | -| he | Hebrew | -| hi | Hindi | -| hr | Croatian | -| hu | Hungarian | -| hy | Armenian | -| ia | Interlingua | -| id | Indonesian | -| is | Icelandic | -| it | Italian | -| it-CH | Italian (Switzerland) | -| it-IT | Italian (Italy) | -| ja | Japanese | -| jw | Javanese | -| ka | Georgian | -| kk | Kazakh | -| km | Cambodian | -| kn | Kannada | -| ko | Korean | -| ku | Kurdish | -| ky | Kyrgyz | -| la | Latin | -| ln | Lingala | -| lo | Laothian | -| lt | Lithuanian | -| lv | Latvian | -| mk | Macedonian | -| ml | Malayalam | -| mn | Mongolian | -| mo | Moldavian | -| mr | Marathi | -| ms | Malay | -| mt | Maltese | -| nb | Norwegian (Bokmal) | -| ne | Nepali | -| nl | Dutch | -| nn | Norwegian (Nynorsk) | -| no | Norwegian | -| oc | Occitan | -| om | Oromo | -| or | Oriya | -| pa | Punjabi | -| pl | Polish | -| ps | Pashto | -| pt | Portuguese | -| pt-BR | Portuguese (Brazil) | -| pt-PT | Portuguese (Portugal) | -| qu | Quechua | -| rm | Romansh | -| ro | Romanian | -| ru | Russian | -| sd | Sindhi | -| sh | Serbo-Croatian | -| si | Sinhalese | -| sk | Slovak | -| sl | Slovenian | -| sn | Shona | -| so | Somali | -| sq | Albanian | -| sr | Serbian | -| st | Sesotho | -| su | Sundanese | -| sv | Swedish | -| sw | Swahili | -| ta | Tamil | -| te | Telugu | -| tg | Tajik | -| th | Thai | -| ti | Tigrinya | -| tk | Turkmen | -| to | Tonga | -| tr | Turkish | -| tt | Tatar | -| tw | Twi | -| ug | Uighur | -| uk | Ukrainian | -| ur | Urdu | -| uz | Uzbek | -| vi | Vietnamese | -| xh | Xhosa | -| yi | Yiddish | -| yo | Yoruba | -| zh | Chinese | -| zh-CN | Chinese (Simplified) | -| zh-TW | Chinese (Traditional) | -| zu | Zulu | diff --git a/docs/api/menu-item.md b/docs/api/menu-item.md index 74055d52cdc41..7458069f0cdc8 100644 --- a/docs/api/menu-item.md +++ b/docs/api/menu-item.md @@ -1,3 +1,5 @@ +# MenuItem + ## Class: MenuItem > Add items to native application menus and context menus. @@ -6,121 +8,64 @@ Process: [Main](../glossary.md#main-process) See [`Menu`](menu.md) for examples. +> [!WARNING] +> Electron's built-in classes cannot be subclassed in user code. +> For more information, see [the FAQ](../faq.md#class-inheritance-does-not-work-with-electron-built-in-modules). + ### `new MenuItem(options)` * `options` Object * `click` Function (optional) - Will be called with - `click(menuItem, browserWindow, event)` when the menu item is clicked. - * `menuItem` MenuItem - * `browserWindow` [BrowserWindow](browser-window.md) | undefined - This will not be defined if no window is open. + `click(menuItem, window, event)` when the menu item is clicked. + * `menuItem` [MenuItem](menu-item.md) + * `window` [BaseWindow](base-window.md) | undefined - This will not be defined if no window is open. * `event` [KeyboardEvent](structures/keyboard-event.md) - * `role` String (optional) - Can be `undo`, `redo`, `cut`, `copy`, `paste`, `pasteAndMatchStyle`, `delete`, `selectAll`, `reload`, `forceReload`, `toggleDevTools`, `resetZoom`, `zoomIn`, `zoomOut`, `togglefullscreen`, `window`, `minimize`, `close`, `help`, `about`, `services`, `hide`, `hideOthers`, `unhide`, `quit`, `startSpeaking`, `stopSpeaking`, `zoom`, `front`, `appMenu`, `fileMenu`, `editMenu`, `viewMenu`, `shareMenu`, `recentDocuments`, `toggleTabBar`, `selectNextTab`, `selectPreviousTab`, `mergeAllWindows`, `clearRecentDocuments`, `moveTabToNewWindow` or `windowMenu` - Define the action of the menu item, when specified the - `click` property will be ignored. See [roles](#roles). - * `type` String (optional) - Can be `normal`, `separator`, `submenu`, `checkbox` or - `radio`. - * `label` String (optional) - * `sublabel` String (optional) - * `toolTip` String (optional) _macOS_ - Hover text for this menu item. - * `accelerator` [Accelerator](accelerator.md) (optional) - * `icon` ([NativeImage](native-image.md) | String) (optional) - * `enabled` Boolean (optional) - If false, the menu item will be greyed out and + * `role` string (optional) - Can be `undo`, `redo`, `cut`, `copy`, `paste`, `pasteAndMatchStyle`, `delete`, `selectAll`, `reload`, `forceReload`, `toggleDevTools`, `resetZoom`, `zoomIn`, `zoomOut`, `toggleSpellChecker`, `togglefullscreen`, `window`, `minimize`, `close`, `help`, `about`, `services`, `hide`, `hideOthers`, `unhide`, `quit`, `showSubstitutions`, `toggleSmartQuotes`, `toggleSmartDashes`, `toggleTextReplacement`, `startSpeaking`, `stopSpeaking`, `zoom`, `front`, `appMenu`, `fileMenu`, `editMenu`, `viewMenu`, `shareMenu`, `recentDocuments`, `toggleTabBar`, `selectNextTab`, `selectPreviousTab`, `showAllTabs`, `mergeAllWindows`, `clearRecentDocuments`, `moveTabToNewWindow` or `windowMenu` - Define the action of the menu item, when specified the + `click` property will be ignored. See [roles](../tutorial/menus.md#roles). + * `type` string (optional) + * `normal` + * `separator` + * `submenu` + * `checkbox` + * `radio` + * `header` - Only available on macOS 14 and up. + * `palette` - Only available on macOS 14 and up. + * `label` string (optional) + * `sublabel` string (optional) _macOS_ - Available in macOS >= 14.4 + * `toolTip` string (optional) _macOS_ - Hover text for this menu item. + * `accelerator` string (optional) - An [Accelerator](../tutorial/keyboard-shortcuts.md#accelerators) string. + * `icon` ([NativeImage](native-image.md) | string) (optional) - Can be a + [NativeImage](native-image.md) or the file path of an icon. + * `enabled` boolean (optional) - If false, the menu item will be greyed out and unclickable. - * `acceleratorWorksWhenHidden` Boolean (optional) _macOS_ - default is `true`, and when `false` will prevent the accelerator from triggering the item if the item is not visible`. - * `visible` Boolean (optional) - If false, the menu item will be entirely hidden. - * `checked` Boolean (optional) - Should only be specified for `checkbox` or `radio` type + * `acceleratorWorksWhenHidden` boolean (optional) _macOS_ - default is `true`, and when `false` will prevent the accelerator from triggering the item if the item is not visible. + * `visible` boolean (optional) - If false, the menu item will be entirely hidden. + * `checked` boolean (optional) - Should only be specified for `checkbox` or `radio` type menu items. - * `registerAccelerator` Boolean (optional) _Linux_ _Windows_ - If false, the accelerator won't be registered + * `registerAccelerator` boolean (optional) _Linux_ _Windows_ - If false, the accelerator won't be registered with the system, but it will still be displayed. Defaults to true. - * `sharingItem` SharingItem (optional) _macOS_ - The item to share when the `role` is `shareMenu`. - * `submenu` (MenuItemConstructorOptions[] | [Menu](menu.md)) (optional) - Should be specified + * `sharingItem` [SharingItem](structures/sharing-item.md) (optional) _macOS_ - The item to share when the `role` is `shareMenu`. + * `submenu` ([MenuItemConstructorOptions](#new-menuitemoptions)[] | [Menu](menu.md)) (optional) - Should be specified for `submenu` type menu items. If `submenu` is specified, the `type: 'submenu'` can be omitted. If the value is not a [`Menu`](menu.md) then it will be automatically converted to one using `Menu.buildFromTemplate`. - * `id` String (optional) - Unique within a single menu. If defined then it can be used + * `id` string (optional) - Unique within a single menu. If defined then it can be used as a reference to this item by the position attribute. - * `before` String[] (optional) - Inserts this item before the item with the specified label. If + * `before` string[] (optional) - Inserts this item before the item with the specified id. If the referenced item doesn't exist the item will be inserted at the end of the menu. Also implies that the menu item in question should be placed in the same “group” as the item. - * `after` String[] (optional) - Inserts this item after the item with the specified label. If the + * `after` string[] (optional) - Inserts this item after the item with the specified id. If the referenced item doesn't exist the item will be inserted at the end of the menu. - * `beforeGroupContaining` String[] (optional) - Provides a means for a single context menu to declare + * `beforeGroupContaining` string[] (optional) - Provides a means for a single context menu to declare the placement of their containing group before the containing group of the item - with the specified label. - * `afterGroupContaining` String[] (optional) - Provides a means for a single context menu to declare + with the specified id. + * `afterGroupContaining` string[] (optional) - Provides a means for a single context menu to declare the placement of their containing group after the containing group of the item - with the specified label. - -**Note:** `acceleratorWorksWhenHidden` is specified as being macOS-only because accelerators always work when items are hidden on Windows and Linux. The option is exposed to users to give them the option to turn it off, as this is possible in native macOS development. This property is only usable on macOS High Sierra 10.13 or newer. - -### Roles - -Roles allow menu items to have predefined behaviors. - -It is best to specify `role` for any menu item that matches a standard role, -rather than trying to manually implement the behavior in a `click` function. -The built-in `role` behavior will give the best native experience. - -The `label` and `accelerator` values are optional when using a `role` and will -default to appropriate values for each platform. - -Every menu item must have either a `role`, `label`, or in the case of a separator -a `type`. - -The `role` property can have following values: - -* `undo` -* `about` - Trigger a native about panel (custom message box on Window, which does not provide its own). -* `redo` -* `cut` -* `copy` -* `paste` -* `pasteAndMatchStyle` -* `selectAll` -* `delete` -* `minimize` - Minimize current window. -* `close` - Close current window. -* `quit` - Quit the application. -* `reload` - Reload the current window. -* `forceReload` - Reload the current window ignoring the cache. -* `toggleDevTools` - Toggle developer tools in the current window. -* `togglefullscreen` - Toggle full screen mode on the current window. -* `resetZoom` - Reset the focused page's zoom level to the original size. -* `zoomIn` - Zoom in the focused page by 10%. -* `zoomOut` - Zoom out the focused page by 10%. -* `toggleSpellChecker` - Enable/disable builtin spell checker. -* `fileMenu` - Whole default "File" menu (Close / Quit) -* `editMenu` - Whole default "Edit" menu (Undo, Copy, etc.). -* `viewMenu` - Whole default "View" menu (Reload, Toggle Developer Tools, etc.) -* `windowMenu` - Whole default "Window" menu (Minimize, Zoom, etc.). - -The following additional roles are available on _macOS_: - -* `appMenu` - Whole default "App" menu (About, Services, etc.) -* `hide` - Map to the `hide` action. -* `hideOthers` - Map to the `hideOtherApplications` action. -* `unhide` - Map to the `unhideAllApplications` action. -* `startSpeaking` - Map to the `startSpeaking` action. -* `stopSpeaking` - Map to the `stopSpeaking` action. -* `front` - Map to the `arrangeInFront` action. -* `zoom` - Map to the `performZoom` action. -* `toggleTabBar` - Map to the `toggleTabBar` action. -* `selectNextTab` - Map to the `selectNextTab` action. -* `selectPreviousTab` - Map to the `selectPreviousTab` action. -* `mergeAllWindows` - Map to the `mergeAllWindows` action. -* `moveTabToNewWindow` - Map to the `moveTabToNewWindow` action. -* `window` - The submenu is a "Window" menu. -* `help` - The submenu is a "Help" menu. -* `services` - The submenu is a ["Services"](https://developer.apple.com/documentation/appkit/nsapplication/1428608-servicesmenu?language=objc) menu. This is only intended for use in the Application Menu and is *not* the same as the "Services" submenu used in context menus in macOS apps, which is not implemented in Electron. -* `recentDocuments` - The submenu is an "Open Recent" menu. -* `clearRecentDocuments` - Map to the `clearRecentDocuments` action. -* `shareMenu` - The submenu is [share menu][ShareMenu]. The `sharingItem` property must also be set to indicate the item to share. - -When specifying a `role` on macOS, `label` and `accelerator` are the only -options that will affect the menu item. All other options will be ignored. -Lowercase `role`, e.g. `toggledevtools`, is still supported. - -**Nota Bene:** The `enabled` and `visibility` properties are not available for top-level menu items in the tray on macOS. + with the specified id. + +> [!NOTE] +> `acceleratorWorksWhenHidden` is specified as being macOS-only because accelerators always work when items are hidden on Windows and Linux. The option is exposed to users to give them the option to turn it off, as this is possible in native macOS development. ### Instance Properties @@ -128,12 +73,15 @@ The following properties are available on instances of `MenuItem`: #### `menuItem.id` -A `String` indicating the item's unique id, this property can be -dynamically changed. +A `string` indicating the item's unique id. + +This property can be dynamically changed. #### `menuItem.label` -A `String` indicating the item's visible label. +A `string` indicating the item's visible label. + +This property can be dynamically changed. #### `menuItem.click` @@ -141,53 +89,69 @@ A `Function` that is fired when the MenuItem receives a click event. It can be called with `menuItem.click(event, focusedWindow, focusedWebContents)`. * `event` [KeyboardEvent](structures/keyboard-event.md) -* `focusedWindow` [BrowserWindow](browser-window.md) +* `focusedWindow` [BaseWindow](base-window.md) * `focusedWebContents` [WebContents](web-contents.md) #### `menuItem.submenu` -A `Menu` (optional) containing the menu +A [`Menu`](menu.md) (optional) containing the menu item's submenu, if present. #### `menuItem.type` -A `String` indicating the type of the item. Can be `normal`, `separator`, `submenu`, `checkbox` or `radio`. +A `string` indicating the type of the item. Can be `normal`, `separator`, `submenu`, `checkbox`, `radio`, `header` or `palette`. + +> [!NOTE] +> `header` and `palette` are only available on macOS 14 and up. #### `menuItem.role` -A `String` (optional) indicating the item's role, if set. Can be `undo`, `redo`, `cut`, `copy`, `paste`, `pasteAndMatchStyle`, `delete`, `selectAll`, `reload`, `forceReload`, `toggleDevTools`, `resetZoom`, `zoomIn`, `zoomOut`, `togglefullscreen`, `window`, `minimize`, `close`, `help`, `about`, `services`, `hide`, `hideOthers`, `unhide`, `quit`, `startSpeaking`, `stopSpeaking`, `zoom`, `front`, `appMenu`, `fileMenu`, `editMenu`, `viewMenu`, `recentDocuments`, `toggleTabBar`, `selectNextTab`, `selectPreviousTab`, `mergeAllWindows`, `clearRecentDocuments`, `moveTabToNewWindow` or `windowMenu` +A `string` (optional) indicating the item's role, if set. Can be `undo`, `redo`, `cut`, `copy`, `paste`, `pasteAndMatchStyle`, `delete`, `selectAll`, `reload`, `forceReload`, `toggleDevTools`, `resetZoom`, `zoomIn`, `zoomOut`, `toggleSpellChecker`, `togglefullscreen`, `window`, `minimize`, `close`, `help`, `about`, `services`, `hide`, `hideOthers`, `unhide`, `quit`, `startSpeaking`, `stopSpeaking`, `zoom`, `front`, `appMenu`, `fileMenu`, `editMenu`, `viewMenu`, `shareMenu`, `recentDocuments`, `toggleTabBar`, `selectNextTab`, `selectPreviousTab`, `showAllTabs`, `mergeAllWindows`, `clearRecentDocuments`, `moveTabToNewWindow` or `windowMenu` #### `menuItem.accelerator` -A `Accelerator` (optional) indicating the item's accelerator, if set. +An [`Accelerator | null`](../tutorial/keyboard-shortcuts.md#accelerators) indicating the item's accelerator, if set. + +#### `menuItem.userAccelerator` _Readonly_ _macOS_ + +An [`Accelerator | null`](../tutorial/keyboard-shortcuts.md#accelerators) indicating the item's [user-assigned accelerator](https://developer.apple.com/documentation/appkit/nsmenuitem/1514850-userkeyequivalent?language=objc) for the menu item. + +> [!NOTE] +> This property is only initialized after the `MenuItem` has been added to a `Menu`. Either via `Menu.buildFromTemplate` or via `Menu.append()/insert()`. Accessing before initialization will just return `null`. #### `menuItem.icon` -A `NativeImage | String` (optional) indicating the -item's icon, if set. +A `NativeImage | string` (optional) indicating the item's icon, if set. + +This property can be dynamically changed. #### `menuItem.sublabel` -A `String` indicating the item's sublabel. +A `string` indicating the item's sublabel. + +This property can be dynamically changed. #### `menuItem.toolTip` _macOS_ -A `String` indicating the item's hover text. +A `string` indicating the item's hover text. #### `menuItem.enabled` -A `Boolean` indicating whether the item is enabled, this property can be -dynamically changed. +A `boolean` indicating whether the item is enabled. + +This property can be dynamically changed. #### `menuItem.visible` -A `Boolean` indicating whether the item is visible, this property can be -dynamically changed. +A `boolean` indicating whether the item is visible. + +This property can be dynamically changed. #### `menuItem.checked` -A `Boolean` indicating whether the item is checked, this property can be -dynamically changed. +A `boolean` indicating whether the item is checked. + +This property can be dynamically changed. A `checkbox` menu item will toggle the `checked` property on and off when selected. @@ -199,23 +163,21 @@ You can add a `click` function for additional behavior. #### `menuItem.registerAccelerator` -A `Boolean` indicating if the accelerator should be registered with the +A `boolean` indicating if the accelerator should be registered with the system or just displayed. This property can be dynamically changed. #### `menuItem.sharingItem` _macOS_ -A `SharingItem` indicating the item to share when the `role` is `shareMenu`. +A [`SharingItem`](structures/sharing-item.md) indicating the item to share when the `role` is `shareMenu`. This property can be dynamically changed. #### `menuItem.commandId` -A `Number` indicating an item's sequential unique id. +A `number` indicating an item's sequential unique id. #### `menuItem.menu` -A `Menu` that the item is a part of. - -[ShareMenu]: https://developer.apple.com/design/human-interface-guidelines/macos/extensions/share-extensions/ +A [`Menu`](menu.md) that the item is a part of. diff --git a/docs/api/menu.md b/docs/api/menu.md index 4aea3a9351fe8..c04526d41ec2f 100644 --- a/docs/api/menu.md +++ b/docs/api/menu.md @@ -1,9 +1,23 @@ +# Menu + ## Class: Menu -> Create native application menus and context menus. +> Create application menus and context menus. Process: [Main](../glossary.md#main-process) +The presentation of menus varies depending on the operating system: + +- Under Windows and Linux, menus are visually similar to Chromium. +- Under macOS, these will be native menus. + +> [!TIP] +> See also: [A detailed guide about how to implement menus in your application](../tutorial/menus.md). + +> [!WARNING] +> Electron's built-in classes cannot be subclassed in user code. +> For more information, see [the FAQ](../faq.md#class-inheritance-does-not-work-with-electron-built-in-modules). + ### `new Menu()` Creates a new menu. @@ -14,7 +28,7 @@ The `Menu` class has the following static methods: #### `Menu.setApplicationMenu(menu)` -* `menu` Menu | null +- `menu` [Menu](menu.md) | null Sets `menu` as the application menu on macOS. On Windows and Linux, the `menu` will be set as each window's top menu. @@ -22,39 +36,43 @@ Sets `menu` as the application menu on macOS. On Windows and Linux, the Also on Windows and Linux, you can use a `&` in the top-level item name to indicate which letter should get a generated accelerator. For example, using `&File` for the file menu would result in a generated `Alt-F` accelerator that -opens the associated menu. The indicated character in the button label gets an -underline. The `&` character is not displayed on the button label. +opens the associated menu. The indicated character in the button label then gets an +underline, and the `&` character is not displayed on the button label. + +In order to escape the `&` character in an item name, add a preceding `&`. For example, `&&File` would result in `&File` displayed on the button label. Passing `null` will suppress the default menu. On Windows and Linux, this has the additional effect of removing the menu bar from the window. -**Note:** The default menu will be created automatically if the app does not set one. -It contains standard items such as `File`, `Edit`, `View`, `Window` and `Help`. +> [!NOTE] +> The default menu will be created automatically if the app does not set one. +> It contains standard items such as `File`, `Edit`, `View`, and `Window`. #### `Menu.getApplicationMenu()` Returns `Menu | null` - The application menu, if set, or `null`, if not set. -**Note:** The returned `Menu` instance doesn't support dynamic addition or -removal of menu items. [Instance properties](#instance-properties) can still -be dynamically modified. +> [!NOTE] +> The returned `Menu` instance doesn't support dynamic addition or +> removal of menu items. [Instance properties](#instance-properties) can still +> be dynamically modified. #### `Menu.sendActionToFirstResponder(action)` _macOS_ -* `action` String +- `action` string Sends the `action` to the first responder of application. This is used for emulating default macOS menu behaviors. Usually you would use the -[`role`](menu-item.md#roles) property of a [`MenuItem`](menu-item.md). +[`role`](../tutorial/menus.md#roles) property of a [`MenuItem`](menu-item.md). See the [macOS Cocoa Event Handling Guide](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/EventOverview/EventArchitecture/EventArchitecture.html#//apple_ref/doc/uid/10000060i-CH3-SW7) for more information on macOS' native actions. #### `Menu.buildFromTemplate(template)` -* `template` (MenuItemConstructorOptions | MenuItem)[] +- `template` ([MenuItemConstructorOptions](menu-item.md#new-menuitemoptions) | [MenuItem](menu-item.md))[] -Returns `Menu` +Returns [`Menu`](menu.md) Generally, the `template` is an array of `options` for constructing a [MenuItem](menu-item.md). The usage can be referenced above. @@ -67,41 +85,50 @@ The `menu` object has the following instance methods: #### `menu.popup([options])` -* `options` Object (optional) - * `window` [BrowserWindow](browser-window.md) (optional) - Default is the focused window. - * `x` Number (optional) - Default is the current mouse cursor position. +- `options` Object (optional) + - `window` [BaseWindow](base-window.md) (optional) - Default is the focused window. + - `frame` [WebFrameMain](web-frame-main.md) (optional) - Provide the relevant frame + if you want certain OS-level features such as Writing Tools on macOS to function correctly. Typically, this should be `params.frame` from the [`context-menu` event](web-contents.md#event-context-menu) on a WebContents, or the [`focusedFrame` property](web-contents.md#contentsfocusedframe-readonly) of a WebContents. + - `x` number (optional) - Default is the current mouse cursor position. Must be declared if `y` is declared. - * `y` Number (optional) - Default is the current mouse cursor position. + - `y` number (optional) - Default is the current mouse cursor position. Must be declared if `x` is declared. - * `positioningItem` Number (optional) _macOS_ - The index of the menu item to + - `positioningItem` number (optional) _macOS_ - The index of the menu item to be positioned under the mouse cursor at the specified coordinates. Default is -1. - * `callback` Function (optional) - Called when menu is closed. + - `sourceType` string (optional) _Windows_ _Linux_ - This should map to the `menuSourceType` + provided by the `context-menu` event. It is not recommended to set this value manually, + only provide values you receive from other APIs or leave it `undefined`. + Can be `none`, `mouse`, `keyboard`, `touch`, `touchMenu`, `longPress`, `longTap`, `touchHandle`, `stylus`, `adjustSelection`, or `adjustSelectionReset`. + - `callback` Function (optional) - Called when menu is closed. -Pops up this menu as a context menu in the [`BrowserWindow`](browser-window.md). +Pops up this menu as a context menu in the [`BaseWindow`](base-window.md). -#### `menu.closePopup([browserWindow])` +> [!TIP] +> For more details, see the [Context Menu](../tutorial/context-menu.md) guide. -* `browserWindow` [BrowserWindow](browser-window.md) (optional) - Default is the focused window. +#### `menu.closePopup([window])` -Closes the context menu in the `browserWindow`. +- `window` [BaseWindow](base-window.md) (optional) - Default is the focused window. + +Closes the context menu in the `window`. #### `menu.append(menuItem)` -* `menuItem` [MenuItem](menu-item.md) +- `menuItem` [MenuItem](menu-item.md) Appends the `menuItem` to the menu. #### `menu.getMenuItemById(id)` -* `id` String +- `id` string -Returns `MenuItem | null` the item with the specified `id` +Returns [`MenuItem | null`](menu-item.md) - the item with the specified `id` #### `menu.insert(pos, menuItem)` -* `pos` Integer -* `menuItem` [MenuItem](menu-item.md) +- `pos` Integer +- `menuItem` [MenuItem](menu-item.md) Inserts the `menuItem` to the `pos` position of the menu. @@ -109,14 +136,15 @@ Inserts the `menuItem` to the `pos` position of the menu. Objects created with `new Menu` or returned by `Menu.buildFromTemplate` emit the following events: -**Note:** Some events are only available on specific operating systems and are -labeled as such. +> [!NOTE] +> Some events are only available on specific operating systems and are +> labeled as such. #### Event: 'menu-will-show' Returns: -* `event` Event +- `event` Event Emitted when `menu.popup()` is called. @@ -124,7 +152,7 @@ Emitted when `menu.popup()` is called. Returns: -* `event` Event +- `event` Event Emitted when a popup is closed either manually or with `menu.closePopup()`. @@ -134,271 +162,7 @@ Emitted when a popup is closed either manually or with `menu.closePopup()`. #### `menu.items` -A `MenuItem[]` array containing the menu's items. - -Each `Menu` consists of multiple [`MenuItem`](menu-item.md)s and each `MenuItem` -can have a submenu. - -## Examples - -An example of creating the application menu with the simple template API: - -```javascript -const { app, Menu } = require('electron') - -const isMac = process.platform === 'darwin' - -const template = [ - // { role: 'appMenu' } - ...(isMac ? [{ - label: app.name, - submenu: [ - { role: 'about' }, - { type: 'separator' }, - { role: 'services' }, - { type: 'separator' }, - { role: 'hide' }, - { role: 'hideothers' }, - { role: 'unhide' }, - { type: 'separator' }, - { role: 'quit' } - ] - }] : []), - // { role: 'fileMenu' } - { - label: 'File', - submenu: [ - isMac ? { role: 'close' } : { role: 'quit' } - ] - }, - // { role: 'editMenu' } - { - label: 'Edit', - submenu: [ - { role: 'undo' }, - { role: 'redo' }, - { type: 'separator' }, - { role: 'cut' }, - { role: 'copy' }, - { role: 'paste' }, - ...(isMac ? [ - { role: 'pasteAndMatchStyle' }, - { role: 'delete' }, - { role: 'selectAll' }, - { type: 'separator' }, - { - label: 'Speech', - submenu: [ - { role: 'startSpeaking' }, - { role: 'stopSpeaking' } - ] - } - ] : [ - { role: 'delete' }, - { type: 'separator' }, - { role: 'selectAll' } - ]) - ] - }, - // { role: 'viewMenu' } - { - label: 'View', - submenu: [ - { role: 'reload' }, - { role: 'forceReload' }, - { role: 'toggleDevTools' }, - { type: 'separator' }, - { role: 'resetZoom' }, - { role: 'zoomIn' }, - { role: 'zoomOut' }, - { type: 'separator' }, - { role: 'togglefullscreen' } - ] - }, - // { role: 'windowMenu' } - { - label: 'Window', - submenu: [ - { role: 'minimize' }, - { role: 'zoom' }, - ...(isMac ? [ - { type: 'separator' }, - { role: 'front' }, - { type: 'separator' }, - { role: 'window' } - ] : [ - { role: 'close' } - ]) - ] - }, - { - role: 'help', - submenu: [ - { - label: 'Learn More', - click: async () => { - const { shell } = require('electron') - await shell.openExternal('https://electronjs.org') - } - } - ] - } -] - -const menu = Menu.buildFromTemplate(template) -Menu.setApplicationMenu(menu) -``` - -### Render process - -To create menus initiated by the renderer process, send the required -information to the main process using IPC and have the main process display the -menu on behalf of the renderer. - -Below is an example of showing a menu when the user right clicks the page: - -```js -// renderer -window.addEventListener('contextmenu', (e) => { - e.preventDefault() - ipcRenderer.send('show-context-menu') -}) - -ipcRenderer.on('context-menu-command', (e, command) => { - // ... -}) - -// main -ipcMain.on('show-context-menu', (event) => { - const template = [ - { - label: 'Menu Item 1', - click: () => { event.sender.send('context-menu-command', 'menu-item-1') } - }, - { type: 'separator' }, - { label: 'Menu Item 2', type: 'checkbox', checked: true } - ] - const menu = Menu.buildFromTemplate(template) - menu.popup(BrowserWindow.fromWebContents(event.sender)) -}) -``` - -## Notes on macOS Application Menu - -macOS has a completely different style of application menu from Windows and -Linux. Here are some notes on making your app's menu more native-like. - -### Standard Menus - -On macOS there are many system-defined standard menus, like the [`Services`](https://developer.apple.com/documentation/appkit/nsapplication/1428608-servicesmenu?language=objc) and -`Windows` menus. To make your menu a standard menu, you should set your menu's -`role` to one of the following and Electron will recognize them and make them -become standard menus: - -* `window` -* `help` -* `services` - -### Standard Menu Item Actions - -macOS has provided standard actions for some menu items, like `About xxx`, -`Hide xxx`, and `Hide Others`. To set the action of a menu item to a standard -action, you should set the `role` attribute of the menu item. - -### Main Menu's Name - -On macOS the label of the application menu's first item is always your app's -name, no matter what label you set. To change it, modify your app bundle's -`Info.plist` file. See -[About Information Property List Files][AboutInformationPropertyListFiles] -for more information. - -## Setting Menu for Specific Browser Window (*Linux* *Windows*) - -The [`setMenu` method][setMenu] of browser windows can set the menu of certain -browser windows. - -## Menu Item Position - -You can make use of `before`, `after`, `beforeGroupContaining`, `afterGroupContaining` and `id` to control how the item will be placed when building a menu with `Menu.buildFromTemplate`. - -* `before` - Inserts this item before the item with the specified label. If the - referenced item doesn't exist the item will be inserted at the end of - the menu. Also implies that the menu item in question should be placed in the same “group” as the item. -* `after` - Inserts this item after the item with the specified label. If the - referenced item doesn't exist the item will be inserted at the end of - the menu. Also implies that the menu item in question should be placed in the same “group” as the item. -* `beforeGroupContaining` - Provides a means for a single context menu to declare - the placement of their containing group before the containing group of the item with the specified label. -* `afterGroupContaining` - Provides a means for a single context menu to declare - the placement of their containing group after the containing group of the item with the specified label. - -By default, items will be inserted in the order they exist in the template unless one of the specified positioning keywords is used. - -### Examples - -Template: - -```javascript -[ - { id: '1', label: 'one' }, - { id: '2', label: 'two' }, - { id: '3', label: 'three' }, - { id: '4', label: 'four' } -] -``` - -Menu: - -```sh -- 1 -- 2 -- 3 -- 4 -``` - -Template: - -```javascript -[ - { id: '1', label: 'one' }, - { type: 'separator' }, - { id: '3', label: 'three', beforeGroupContaining: ['1'] }, - { id: '4', label: 'four', afterGroupContaining: ['2'] }, - { type: 'separator' }, - { id: '2', label: 'two' } -] -``` - -Menu: - -```sh -- 3 -- 4 -- --- -- 1 -- --- -- 2 -``` - -Template: - -```javascript -[ - { id: '1', label: 'one', after: ['3'] }, - { id: '2', label: 'two', before: ['1'] }, - { id: '3', label: 'three' } -] -``` - -Menu: - -```sh -- --- -- 3 -- 2 -- 1 -``` - -[AboutInformationPropertyListFiles]: https://developer.apple.com/library/ios/documentation/general/Reference/InfoPlistKeyReference/Articles/AboutInformationPropertyListFiles.html -[setMenu]: https://github.com/electron/electron/blob/master/docs/api/browser-window.md#winsetmenumenu-linux-windows +A [`MenuItem[]`](menu-item.md) array containing the menu's items. + +Each `Menu` consists of multiple [`MenuItem`](menu-item.md) instances and each `MenuItem` +can nest a `Menu` into its `submenu` property. diff --git a/docs/api/message-channel-main.md b/docs/api/message-channel-main.md index 86cdce4e5099b..8e0a5e4123305 100644 --- a/docs/api/message-channel-main.md +++ b/docs/api/message-channel-main.md @@ -9,26 +9,38 @@ channel messaging. ## Class: MessageChannelMain +> Channel interface for channel messaging in the main process. + Process: [Main](../glossary.md#main-process) Example: +<!-- eslint-disable import/order --> + ```js // Main process +const { BrowserWindow, MessageChannelMain } = require('electron') + +const w = new BrowserWindow() const { port1, port2 } = new MessageChannelMain() w.webContents.postMessage('port', null, [port2]) port1.postMessage({ some: 'message' }) // Renderer process const { ipcRenderer } = require('electron') + ipcRenderer.on('port', (e) => { // e.ports is a list of ports sent along with this message - e.ports[0].on('message', (messageEvent) => { + e.ports[0].onmessage = (messageEvent) => { console.log(messageEvent.data) - }) + } }) ``` +> [!WARNING] +> Electron's built-in classes cannot be subclassed in user code. +> For more information, see [the FAQ](../faq.md#class-inheritance-does-not-work-with-electron-built-in-modules). + ### Instance Properties #### `channel.port1` diff --git a/docs/api/message-port-main.md b/docs/api/message-port-main.md index 2f75f2f996fc2..371d358f94cb0 100644 --- a/docs/api/message-port-main.md +++ b/docs/api/message-port-main.md @@ -14,7 +14,10 @@ channel messaging. ## Class: MessagePortMain -Process: [Main](../glossary.md#main-process) +> Port interface for channel messaging in the main process. + +Process: [Main](../glossary.md#main-process)<br /> +_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ ### Instance Methods @@ -53,3 +56,4 @@ Emitted when the remote end of a MessagePortMain object becomes disconnected. [`MessagePort`]: https://developer.mozilla.org/en-US/docs/Web/API/MessagePort [Channel Messaging API]: https://developer.mozilla.org/en-US/docs/Web/API/Channel_Messaging_API +[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter diff --git a/docs/api/modernization/overview.md b/docs/api/modernization/overview.md deleted file mode 100644 index ad2df400b10e3..0000000000000 --- a/docs/api/modernization/overview.md +++ /dev/null @@ -1,10 +0,0 @@ -## Modernization - -The Electron team is currently undergoing an initiative to modernize our API in a few concrete ways. These include: updating our modules to use idiomatic JS properties instead of separate `getPropertyX` and `setPropertyX`, converting callbacks to promises, and removing some other anti-patterns present in our APIs. The current status of the Promise initiative can be tracked in the [promisification](promisification.md) tracking file. - -As we work to perform these updates, we seek to create the least disruptive amount of change at any given time, so as many changes as possible will be introduced in a backward compatible manner and deprecated after enough time has passed to give users a chance to upgrade their API calls. - -This document and its child documents will be updated to reflect the latest status of our API changes. - -* [Promisification](promisification.md) -* [Property Updates](property-updates.md) diff --git a/docs/api/modernization/promisification.md b/docs/api/modernization/promisification.md deleted file mode 100644 index 333b978c97c33..0000000000000 --- a/docs/api/modernization/promisification.md +++ /dev/null @@ -1,42 +0,0 @@ -## Promisification - -The Electron team recently underwent an initiative to convert callback-based APIs to Promise-based ones. See converted functions below: - -- [app.getFileIcon(path[, options], callback)](https://github.com/electron/electron/blob/master/docs/api/app.md#getFileIcon) -- [contents.capturePage([rect, ]callback)](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#capturePage) -- [contents.executeJavaScript(code[, userGesture, callback])](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#executeJavaScript) -- [contents.printToPDF(options, callback)](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#printToPDF) -- [contents.savePage(fullPath, saveType, callback)](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#savePage) -- [contentTracing.getCategories(callback)](https://github.com/electron/electron/blob/master/docs/api/content-tracing.md#getCategories) -- [contentTracing.startRecording(options, callback)](https://github.com/electron/electron/blob/master/docs/api/content-tracing.md#startRecording) -- [contentTracing.stopRecording(resultFilePath, callback)](https://github.com/electron/electron/blob/master/docs/api/content-tracing.md#stopRecording) -- [contentTracing.getTraceBufferUsage(callback)](https://github.com/electron/electron/blob/master/docs/api/content-tracing.md#getTraceBufferUsage) -- [cookies.flushStore(callback)](https://github.com/electron/electron/blob/master/docs/api/cookies.md#flushStore) -- [cookies.get(filter, callback)](https://github.com/electron/electron/blob/master/docs/api/cookies.md#get) -- [cookies.remove(url, name, callback)](https://github.com/electron/electron/blob/master/docs/api/cookies.md#remove) -- [cookies.set(details, callback)](https://github.com/electron/electron/blob/master/docs/api/cookies.md#set) -- [debugger.sendCommand(method[, commandParams, callback])](https://github.com/electron/electron/blob/master/docs/api/debugger.md#sendCommand) -- [desktopCapturer.getSources(options, callback)](https://github.com/electron/electron/blob/master/docs/api/desktop-capturer.md#getSources) -- [dialog.showOpenDialog([browserWindow, ]options[, callback])](https://github.com/electron/electron/blob/master/docs/api/dialog.md#showOpenDialog) -- [dialog.showSaveDialog([browserWindow, ]options[, callback])](https://github.com/electron/electron/blob/master/docs/api/dialog.md#showSaveDialog) -- [inAppPurchase.purchaseProduct(productID, quantity, callback)](https://github.com/electron/electron/blob/master/docs/api/in-app-purchase.md#purchaseProduct) -- [inAppPurchase.getProducts(productIDs, callback)](https://github.com/electron/electron/blob/master/docs/api/in-app-purchase.md#getProducts) -- [dialog.showMessageBox([browserWindow, ]options[, callback])](https://github.com/electron/electron/blob/master/docs/api/dialog.md#showMessageBox) -- [dialog.showCertificateTrustDialog([browserWindow, ]options, callback)](https://github.com/electron/electron/blob/master/docs/api/dialog.md#showCertificateTrustDialog) -- [netLog.stopLogging([callback])](https://github.com/electron/electron/blob/master/docs/api/net-log.md#stopLogging) -- [protocol.isProtocolHandled(scheme, callback)](https://github.com/electron/electron/blob/master/docs/api/protocol.md#isProtocolHandled) -- [ses.clearHostResolverCache([callback])](https://github.com/electron/electron/blob/master/docs/api/session.md#clearHostResolverCache) -- [ses.clearStorageData([options, callback])](https://github.com/electron/electron/blob/master/docs/api/session.md#clearStorageData) -- [ses.setProxy(config, callback)](https://github.com/electron/electron/blob/master/docs/api/session.md#setProxy) -- [ses.resolveProxy(url, callback)](https://github.com/electron/electron/blob/master/docs/api/session.md#resolveProxy) -- [ses.getCacheSize(callback)](https://github.com/electron/electron/blob/master/docs/api/session.md#getCacheSize) -- [ses.clearAuthCache(options[, callback])](https://github.com/electron/electron/blob/master/docs/api/session.md#clearAuthCache) -- [ses.clearCache(callback)](https://github.com/electron/electron/blob/master/docs/api/session.md#clearCache) -- [ses.getBlobData(identifier, callback)](https://github.com/electron/electron/blob/master/docs/api/session.md#getBlobData) -- [shell.openExternal(url[, options, callback])](https://github.com/electron/electron/blob/master/docs/api/shell.md#openExternal) -- [webFrame.executeJavaScript(code[, userGesture, callback])](https://github.com/electron/electron/blob/master/docs/api/web-frame.md#executeJavaScript) -- [webFrame.executeJavaScriptInIsolatedWorld(worldId, scripts[, userGesture, callback])](https://github.com/electron/electron/blob/master/docs/api/web-frame.md#executeJavaScriptInIsolatedWorld) -- [webviewTag.capturePage([rect, ]callback)](https://github.com/electron/electron/blob/master/docs/api/webview-tag.md#capturePage) -- [webviewTag.executeJavaScript(code[, userGesture, callback])](https://github.com/electron/electron/blob/master/docs/api/webview-tag.md#executeJavaScript) -- [webviewTag.printToPDF(options, callback)](https://github.com/electron/electron/blob/master/docs/api/webview-tag.md#printToPDF) -- [win.capturePage([rect, ]callback)](https://github.com/electron/electron/blob/master/docs/api/browser-window.md#capturePage) diff --git a/docs/api/modernization/property-updates.md b/docs/api/modernization/property-updates.md deleted file mode 100644 index cf3c7c1c35a9f..0000000000000 --- a/docs/api/modernization/property-updates.md +++ /dev/null @@ -1,41 +0,0 @@ -## Property Updates - -The Electron team is currently undergoing an initiative to convert separate getter and setter functions in Electron to bespoke properties with `get` and `set` functionality. During this transition period, both the new properties and old getters and setters of these functions will work correctly and be documented. - -## Candidates - -* `BrowserWindow` - * `menubarVisible` -* `crashReporter` module - * `uploadToServer` -* `webFrame` modules - * `zoomFactor` - * `zoomLevel` - * `audioMuted` -* `<webview>` - * `zoomFactor` - * `zoomLevel` - * `audioMuted` - -## Converted Properties - -* `app` module - * `accessibilitySupport` - * `applicationMenu` - * `badgeCount` - * `name` -* `DownloadItem` class - * `savePath` -* `BrowserWindow` module - * `autoHideMenuBar` - * `resizable` - * `maximizable` - * `minimizable` - * `fullscreenable` - * `movable` - * `closable` - * `backgroundThrottling` -* `NativeImage` - * `isMacTemplateImage` -* `SystemPreferences` module - * `appLevelAppearance` diff --git a/docs/api/native-image.md b/docs/api/native-image.md index 7856412aeae18..f851606ec9040 100644 --- a/docs/api/native-image.md +++ b/docs/api/native-image.md @@ -4,36 +4,47 @@ Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process) -In Electron, for the APIs that take images, you can pass either file paths or -`NativeImage` instances. An empty image will be used when `null` is passed. +> [!IMPORTANT] +> If you want to call this API from a renderer process with context isolation enabled, +> place the API call in your preload script and +> [expose](../tutorial/context-isolation.md#after-context-isolation-enabled) it using the +> [`contextBridge`](context-bridge.md) API. -For example, when creating a tray or setting a window's icon, you can pass an -image file path as a `String`: +The `nativeImage` module provides a unified interface for manipulating +system images. These can be handy if you want to provide multiple scaled +versions of the same icon or take advantage of macOS [template images][template-image]. -```javascript +Electron APIs that take image files accept either file paths or +`NativeImage` instances. An empty and transparent image will be used when `null` is passed. + +For example, when creating a [Tray](../api/tray.md) or setting a [BrowserWindow](../api/browser-window.md)'s +icon, you can either pass an image file path as a string: + +```js title='Main Process' const { BrowserWindow, Tray } = require('electron') -const appIcon = new Tray('/Users/somebody/images/icon.png') +const tray = new Tray('/Users/somebody/images/icon.png') const win = new BrowserWindow({ icon: '/Users/somebody/images/window.png' }) -console.log(appIcon, win) ``` -Or read the image from the clipboard, which returns a `NativeImage`: +or generate a `NativeImage` instance from the same file: + +```js title='Main Process' +const { BrowserWindow, nativeImage, Tray } = require('electron') -```javascript -const { clipboard, Tray } = require('electron') -const image = clipboard.readImage() -const appIcon = new Tray(image) -console.log(appIcon) +const trayIcon = nativeImage.createFromPath('/Users/somebody/images/icon.png') +const appIcon = nativeImage.createFromPath('/Users/somebody/images/window.png') +const tray = new Tray(trayIcon) +const win = new BrowserWindow({ icon: appIcon }) ``` ## Supported Formats -Currently `PNG` and `JPEG` image formats are supported. `PNG` is recommended -because of its support for transparency and lossless compression. +Currently, `PNG` and `JPEG` image formats are supported across all platforms. +`PNG` is recommended because of its support for transparency and lossless compression. On Windows, you can also load `ICO` icons from file paths. For best visual -quality, it is recommended to include at least the following sizes in the: +quality, we recommend including at least the following sizes: * Small icon * 16x16 (100% DPI scale) @@ -47,22 +58,30 @@ quality, it is recommended to include at least the following sizes in the: * 64x64 (200% DPI scale) * 256x256 -Check the *Size requirements* section in [this article][icons]. +Check the _Icon Scaling_ section in the Windows [App Icon Construction][icons] reference. + +[icons]: https://learn.microsoft.com/en-us/windows/apps/design/style/iconography/app-icon-construction#icon-scaling + +:::note + +EXIF metadata is currently not supported and will not be taken into account during +image encoding and decoding. -[icons]:https://msdn.microsoft.com/en-us/library/windows/desktop/dn742485(v=vs.85).aspx +::: ## High Resolution Image -On platforms that have high-DPI support such as Apple Retina displays, you can -append `@2x` after image's base filename to mark it as a high resolution image. +On platforms that support high pixel density displays (such as Apple Retina), +you can append `@2x` after image's base filename to mark it as a 2x scale +high resolution image. For example, if `icon.png` is a normal image that has standard resolution, then -`icon@2x.png` will be treated as a high resolution image that has double DPI -density. +`icon@2x.png` will be treated as a high resolution image that has double +Dots per Inch (DPI) density. If you want to support displays with different DPI densities at the same time, you can put images with different sizes in the same folder and use the filename -without DPI suffixes. For example: +without DPI suffixes within Electron. For example: ```plaintext images/ @@ -71,10 +90,10 @@ images/ └── icon@3x.png ``` -```javascript +```js title='Main Process' const { Tray } = require('electron') -const appIcon = new Tray('/Users/somebody/images/icon.png') -console.log(appIcon) + +const appTray = new Tray('/Users/somebody/images/icon.png') ``` The following suffixes for DPI are also supported: @@ -91,27 +110,23 @@ The following suffixes for DPI are also supported: * `@4x` * `@5x` -## Template Image +## Template Image _macOS_ -Template images consist of black and an alpha channel. +On macOS, [template images][template-image] consist of black and an alpha channel. Template images are not intended to be used as standalone images and are usually mixed with other content to create the desired final appearance. -The most common case is to use template images for a menu bar icon, so it can +The most common case is to use template images for a menu bar (Tray) icon, so it can adapt to both light and dark menu bars. -**Note:** Template image is only supported on macOS. - -To mark an image as a template image, its filename should end with the word -`Template`. For example: - -* `xxxTemplate.png` -* `xxxTemplate@2x.png` +To mark an image as a template image, its base filename should end with the word +`Template` (e.g. `xxxTemplate.png`). You can also specify template images at +different DPI densities (e.g. `xxxTemplate@2x.png`). ## Methods The `nativeImage` module has the following methods, all of which return -an instance of the `NativeImage` class: +an instance of the [`NativeImage`](#class-nativeimage) class: ### `nativeImage.createEmpty()` @@ -119,25 +134,28 @@ Returns `NativeImage` Creates an empty `NativeImage` instance. -### `nativeImage.createThumbnailFromPath(path, maxSize)` _macOS_ _Windows_ +### `nativeImage.createThumbnailFromPath(path, size)` _macOS_ _Windows_ -* `path` String - path to a file that we intend to construct a thumbnail out of. -* `maxSize` [Size](structures/size.md) - the maximum width and height (positive numbers) the thumbnail returned can be. The Windows implementation will ignore `maxSize.height` and scale the height according to `maxSize.width`. +* `path` string - path to a file that we intend to construct a thumbnail out of. +* `size` [Size](structures/size.md) - the desired width and height (positive numbers) of the thumbnail. Returns `Promise<NativeImage>` - fulfilled with the file's thumbnail preview image, which is a [NativeImage](native-image.md). +> [!NOTE] +> Windows implementation will ignore `size.height` and scale the height according to `size.width`. + ### `nativeImage.createFromPath(path)` -* `path` String +* `path` string - path to a file that we intend to construct an image out of. Returns `NativeImage` -Creates a new `NativeImage` instance from a file located at `path`. This method -returns an empty image if the `path` does not exist, cannot be read, or is not +Creates a new `NativeImage` instance from an image file (e.g., PNG or JPEG) located at `path`. +This method returns an empty image if the `path` does not exist, cannot be read, or is not a valid image. -```javascript -const nativeImage = require('electron').nativeImage +```js +const { nativeImage } = require('electron') const image = nativeImage.createFromPath('/Users/somebody/images/icon.png') console.log(image) @@ -149,7 +167,7 @@ console.log(image) * `options` Object * `width` Integer * `height` Integer - * `scaleFactor` Double (optional) - Defaults to 1.0. + * `scaleFactor` Number (optional) - Defaults to 1.0. Returns `NativeImage` @@ -162,7 +180,7 @@ pixel data returned by `toBitmap()`. The specific format is platform-dependent. * `options` Object (optional) * `width` Integer (optional) - Required for bitmap buffers. * `height` Integer (optional) - Required for bitmap buffers. - * `scaleFactor` Double (optional) - Defaults to 1.0. + * `scaleFactor` Number (optional) - Defaults to 1.0. Returns `NativeImage` @@ -170,27 +188,26 @@ Creates a new `NativeImage` instance from `buffer`. Tries to decode as PNG or JP ### `nativeImage.createFromDataURL(dataURL)` -* `dataURL` String +* `dataURL` string Returns `NativeImage` -Creates a new `NativeImage` instance from `dataURL`. +Creates a new `NativeImage` instance from `dataUrl`, a base 64 encoded [Data URL][data-url] string. ### `nativeImage.createFromNamedImage(imageName[, hslShift])` _macOS_ -* `imageName` String -* `hslShift` Number[] (optional) +* `imageName` string +* `hslShift` number[] (optional) Returns `NativeImage` -Creates a new `NativeImage` instance from the NSImage that maps to the -given image name. See [`System Icons`](https://developer.apple.com/design/human-interface-guidelines/macos/icons-and-images/system-icons/) -for a list of possible values. +Creates a new `NativeImage` instance from the `NSImage` that maps to the +given image name. See Apple's [`NSImageName`](https://developer.apple.com/documentation/appkit/nsimagename#2901388) documentation and [SF Symbols](https://developer.apple.com/sf-symbols/) for a list of possible values. The `hslShift` is applied to the image with the following rules: * `hsl_shift[0]` (hue): The absolute hue value for the image - 0 and 1 map - to 0 and 360 on the hue color wheel (red). + to 0 and 360 on the hue color wheel (red). * `hsl_shift[1]` (saturation): A saturation shift for the image, with the following key values: 0 = remove all color. @@ -207,15 +224,27 @@ This means that `[-1, 0, 1]` will make the image completely white and In some cases, the `NSImageName` doesn't match its string representation; one example of this is `NSFolderImageName`, whose string representation would actually be `NSFolder`. Therefore, you'll need to determine the correct string representation for your image before passing it in. This can be done with the following: -`echo -e '#import <Cocoa/Cocoa.h>\nint main() { NSLog(@"%@", SYSTEM_IMAGE_NAME); }' | clang -otest -x objective-c -framework Cocoa - && ./test` +```sh +echo -e '#import <Cocoa/Cocoa.h>\nint main() { NSLog(@"%@", SYSTEM_IMAGE_NAME); }' | clang -otest -x objective-c -framework Cocoa - && ./test +``` where `SYSTEM_IMAGE_NAME` should be replaced with any value from [this list](https://developer.apple.com/documentation/appkit/nsimagename?language=objc). +For SF Symbols, usage looks as follows: + +```js +const image = nativeImage.createFromNamedImage('square.and.pencil') +``` + +where `'square.and.pencil'` is the symbol name from the +[SF Symbols app](https://developer.apple.com/sf-symbols/). + ## Class: NativeImage > Natively wrap images such as tray, dock, and application icons. -Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process) +Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process)<br /> +_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ ### Instance Methods @@ -224,7 +253,7 @@ The following methods are available on instances of the `NativeImage` class: #### `image.toPNG([options])` * `options` Object (optional) - * `scaleFactor` Double (optional) - Defaults to 1.0. + * `scaleFactor` Number (optional) - Defaults to 1.0. Returns `Buffer` - A [Buffer][buffer] that contains the image's `PNG` encoded data. @@ -237,33 +266,38 @@ Returns `Buffer` - A [Buffer][buffer] that contains the image's `JPEG` encoded d #### `image.toBitmap([options])` * `options` Object (optional) - * `scaleFactor` Double (optional) - Defaults to 1.0. + * `scaleFactor` Number (optional) - Defaults to 1.0. Returns `Buffer` - A [Buffer][buffer] that contains a copy of the image's raw bitmap pixel data. #### `image.toDataURL([options])` +<!-- +```YAML history +changes: + - pr-url: https://github.com/electron/electron/pull/41752 + description: "`nativeImage.toDataURL` will preserve PNG colorspace" + breaking-changes-header: behavior-changed-nativeimagetodataurl-will-preserve-png-colorspace +``` +--> + * `options` Object (optional) - * `scaleFactor` Double (optional) - Defaults to 1.0. + * `scaleFactor` Number (optional) - Defaults to 1.0. -Returns `String` - The data URL of the image. +Returns `string` - The [Data URL][data-url] of the image. -#### `image.getBitmap([options])` +#### `image.getBitmap([options])` _Deprecated_ * `options` Object (optional) - * `scaleFactor` Double (optional) - Defaults to 1.0. + * `scaleFactor` Number (optional) - Defaults to 1.0. -Returns `Buffer` - A [Buffer][buffer] that contains the image's raw bitmap pixel data. - -The difference between `getBitmap()` and `toBitmap()` is that `getBitmap()` does not -copy the bitmap data, so you have to use the returned Buffer immediately in -current event loop tick; otherwise the data might be changed or destroyed. +Legacy alias for `image.toBitmap()`. #### `image.getNativeHandle()` _macOS_ Returns `Buffer` - A [Buffer][buffer] that stores C pointer to underlying native handle of -the image. On macOS, a pointer to `NSImage` instance would be returned. +the image. On macOS, a pointer to `NSImage` instance is returned. Notice that the returned pointer is a weak pointer to the underlying native image instead of a copy, so you _must_ ensure that the associated @@ -271,11 +305,11 @@ image instead of a copy, so you _must_ ensure that the associated #### `image.isEmpty()` -Returns `Boolean` - Whether the image is empty. +Returns `boolean` - Whether the image is empty. #### `image.getSize([scaleFactor])` -* `scaleFactor` Double (optional) - Defaults to 1.0. +* `scaleFactor` Number (optional) - Defaults to 1.0. Returns [`Size`](structures/size.md). @@ -283,13 +317,13 @@ If `scaleFactor` is passed, this will return the size corresponding to the image #### `image.setTemplateImage(option)` -* `option` Boolean +* `option` boolean -Marks the image as a template image. +Marks the image as a macOS [template image][template-image]. #### `image.isTemplateImage()` -Returns `Boolean` - Whether the image is a template image. +Returns `boolean` - Whether the image is a macOS [template image][template-image]. #### `image.crop(rect)` @@ -302,8 +336,8 @@ Returns `NativeImage` - The cropped image. * `options` Object * `width` Integer (optional) - Defaults to the image's width. * `height` Integer (optional) - Defaults to the image's height. - * `quality` String (optional) - The desired quality of the resize image. - Possible values are `good`, `better`, or `best`. The default is `best`. + * `quality` string (optional) - The desired quality of the resize image. + Possible values include `good`, `better`, or `best`. The default is `best`. These values express a desired quality/speed tradeoff. They are translated into an algorithm-specific method that depends on the capabilities (CPU, GPU) of the underlying platform. It is possible for all three methods @@ -316,38 +350,40 @@ will be preserved in the resized image. #### `image.getAspectRatio([scaleFactor])` -* `scaleFactor` Double (optional) - Defaults to 1.0. +* `scaleFactor` Number (optional) - Defaults to 1.0. -Returns `Float` - The image's aspect ratio. +Returns `Number` - The image's aspect ratio (width divided by height). If `scaleFactor` is passed, this will return the aspect ratio corresponding to the image representation most closely matching the passed value. #### `image.getScaleFactors()` -Returns `Float[]` - An array of all scale factors corresponding to representations for a given nativeImage. +Returns `Number[]` - An array of all scale factors corresponding to representations for a given `NativeImage`. #### `image.addRepresentation(options)` * `options` Object - * `scaleFactor` Double - The scale factor to add the image representation for. + * `scaleFactor` Number (optional) - The scale factor to add the image representation for. * `width` Integer (optional) - Defaults to 0. Required if a bitmap buffer is specified as `buffer`. * `height` Integer (optional) - Defaults to 0. Required if a bitmap buffer is specified as `buffer`. * `buffer` Buffer (optional) - The buffer containing the raw image data. - * `dataURL` String (optional) - The data URL containing either a base 64 + * `dataURL` string (optional) - The data URL containing either a base 64 encoded PNG or JPEG image. Add an image representation for a specific scale factor. This can be used -to explicitly add different scale factor representations to an image. This +to programmatically add different scale factor representations to an image. This can be called on empty images. -[buffer]: https://nodejs.org/api/buffer.html#buffer_class_buffer - ### Instance Properties #### `nativeImage.isMacTemplateImage` _macOS_ -A `Boolean` property that determines whether the image is considered a [template image](https://developer.apple.com/documentation/appkit/nsimage/1520017-template). +A `boolean` property that determines whether the image is considered a [template image][template-image]. Please note that this property only has an effect on macOS. + +[buffer]: https://nodejs.org/api/buffer.html#buffer_class_buffer +[data-url]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs +[template-image]: https://developer.apple.com/documentation/appkit/nsimage/1520017-template diff --git a/docs/api/native-theme.md b/docs/api/native-theme.md index f7df167cbc1f0..c587cb8ca2631 100644 --- a/docs/api/native-theme.md +++ b/docs/api/native-theme.md @@ -21,13 +21,13 @@ The `nativeTheme` module has the following properties: ### `nativeTheme.shouldUseDarkColors` _Readonly_ -A `Boolean` for if the OS / Chromium currently has a dark mode enabled or is +A `boolean` for if the OS / Chromium currently has a dark mode enabled or is being instructed to show a dark-style UI. If you want to modify this value you should use `themeSource` below. ### `nativeTheme.themeSource` -A `String` property that can be `system`, `light` or `dark`. It is used to override and supersede +A `string` property that can be `system`, `light` or `dark`. It is used to override and supersede the value that Chromium has chosen to use internally. Setting this property to `system` will remove the override and @@ -36,7 +36,7 @@ everything will be reset to the OS default. By default `themeSource` is `system Settings this property to `dark` will have the following effects: * `nativeTheme.shouldUseDarkColors` will be `true` when accessed -* Any UI Electron renders on Linux and Windows including context menus, devtools, etc. will use the dark UI. +* Any UI Electron renders on Linux and Windows including context menus, DevTools, etc. will use the dark UI. * Any UI the OS renders on macOS including menus, window frames, etc. will use the dark UI. * The [`prefers-color-scheme`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) CSS query will match `dark` mode. * The `updated` event will be emitted @@ -44,7 +44,7 @@ Settings this property to `dark` will have the following effects: Settings this property to `light` will have the following effects: * `nativeTheme.shouldUseDarkColors` will be `false` when accessed -* Any UI Electron renders on Linux and Windows including context menus, devtools, etc. will use the light UI. +* Any UI Electron renders on Linux and Windows including context menus, DevTools, etc. will use the light UI. * Any UI the OS renders on macOS including menus, window frames, etc. will use the light UI. * The [`prefers-color-scheme`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) CSS query will match `light` mode. * The `updated` event will be emitted @@ -60,10 +60,31 @@ Your application should then always use `shouldUseDarkColors` to determine what ### `nativeTheme.shouldUseHighContrastColors` _macOS_ _Windows_ _Readonly_ -A `Boolean` for if the OS / Chromium currently has high-contrast mode enabled +A `boolean` for if the OS / Chromium currently has high-contrast mode enabled or is being instructed to show a high-contrast UI. +### `nativeTheme.shouldUseDarkColorsForSystemIntegratedUI` _macOS_ _Windows_ _Readonly_ + +A `boolean` property indicating whether or not the system theme has been set to dark or light. + +On Windows this property distinguishes between system and app light/dark theme, returning +`true` if the system theme is set to dark theme and `false` otherwise. On macOS the return +value will be the same as `nativeTheme.shouldUseDarkColors`. + ### `nativeTheme.shouldUseInvertedColorScheme` _macOS_ _Windows_ _Readonly_ -A `Boolean` for if the OS / Chromium currently has an inverted color scheme +A `boolean` for if the OS / Chromium currently has an inverted color scheme or is being instructed to use an inverted color scheme. + +### `nativeTheme.inForcedColorsMode` _Windows_ _Readonly_ + +A `boolean` indicating whether Chromium is in forced colors mode, controlled by system accessibility settings. +Currently, Windows high contrast is the only system setting that triggers forced colors mode. + +### `nativeTheme.prefersReducedTransparency` _Readonly_ + +A `boolean` that indicates whether the user has chosen via system accessibility settings to reduce transparency at the OS level. + +### `nativeTheme.shouldDifferentiateWithoutColor` _macOS_ _Readonly_ + +A `boolean` that indicates whether the user prefers UI that differentiates items using something other than color alone (e.g. shapes or labels). This maps to [NSWorkspace.accessibilityDisplayShouldDifferentiateWithoutColor](https://developer.apple.com/documentation/appkit/nsworkspace/accessibilitydisplayshoulddifferentiatewithoutcolor). diff --git a/docs/api/navigation-history.md b/docs/api/navigation-history.md new file mode 100644 index 0000000000000..098279bdb4c26 --- /dev/null +++ b/docs/api/navigation-history.md @@ -0,0 +1,104 @@ +## Class: NavigationHistory + +> Manage a list of navigation entries, representing the user's browsing history within the application. + +Process: [Main](../glossary.md#main-process)<br /> +_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ + +Each [NavigationEntry](./structures/navigation-entry.md) corresponds to a specific visited page. +The indexing system follows a sequential order, where the entry for the earliest visited +page is at index 0 and the entry for the most recent visited page is at index N. + +Some APIs in this class also accept an _offset_, which is an integer representing the relative +position of an index from the current entry according to the above indexing system (i.e. an offset +value of `1` would represent going forward in history by one page). + +Maintaining this ordered list of navigation entries enables seamless navigation both backward and +forward through the user's browsing history. + +### Instance Methods + +#### `navigationHistory.canGoBack()` + +Returns `boolean` - Whether the browser can go back to previous web page. + +#### `navigationHistory.canGoForward()` + +Returns `boolean` - Whether the browser can go forward to next web page. + +#### `navigationHistory.canGoToOffset(offset)` + +* `offset` Integer + +Returns `boolean` - Whether the web page can go to the specified relative `offset` from the current entry. + +#### `navigationHistory.clear()` + +Clears the navigation history. + +#### `navigationHistory.getActiveIndex()` + +Returns `Integer` - The index of the current page, from which we would go back/forward or reload. + +#### `navigationHistory.getEntryAtIndex(index)` + +* `index` Integer + +Returns [`NavigationEntry`](structures/navigation-entry.md) - Navigation entry at the given index. + +If index is out of bounds (greater than history length or less than 0), null will be returned. + +#### `navigationHistory.goBack()` + +Makes the browser go back a web page. + +#### `navigationHistory.goForward()` + +Makes the browser go forward a web page. + +#### `navigationHistory.goToIndex(index)` + +* `index` Integer + +Navigates browser to the specified absolute web page index. + +#### `navigationHistory.goToOffset(offset)` + +* `offset` Integer + +Navigates to the specified relative offset from the current entry. + +#### `navigationHistory.length()` + +Returns `Integer` - History length. + +#### `navigationHistory.removeEntryAtIndex(index)` + +* `index` Integer + +Removes the navigation entry at the given index. Can't remove entry at the "current active index". + +Returns `boolean` - Whether the navigation entry was removed from the webContents history. + +#### `navigationHistory.getAllEntries()` + +Returns [`NavigationEntry[]`](structures/navigation-entry.md) - WebContents complete history. + +#### `navigationHistory.restore(options)` + +Restores navigation history and loads the given entry in the in stack. Will make a best effort +to restore not just the navigation stack but also the state of the individual pages - for instance +including HTML form values or the scroll position. It's recommended to call this API before any +navigation entries are created, so ideally before you call `loadURL()` or `loadFile()` on the +`webContents` object. + +This API allows you to create common flows that aim to restore, recreate, or clone other webContents. + +* `options` Object + * `entries` [NavigationEntry[]](structures/navigation-entry.md) - Result of a prior `getAllEntries()` call + * `index` Integer (optional) - Index of the stack that should be loaded. If you set it to `0`, the webContents will load the first (oldest) entry. If you leave it undefined, Electron will automatically load the last (newest) entry. + +Returns `Promise<void>` - the promise will resolve when the page has finished loading the selected navigation entry +(see [`did-finish-load`](web-contents.md#event-did-finish-load)), and rejects +if the page fails to load (see +[`did-fail-load`](web-contents.md#event-did-fail-load)). A noop rejection handler is already attached, which avoids unhandled rejection errors. diff --git a/docs/api/net-log.md b/docs/api/net-log.md index b5875898a8d5e..2ae5beabfc9ee 100644 --- a/docs/api/net-log.md +++ b/docs/api/net-log.md @@ -4,8 +4,8 @@ Process: [Main](../glossary.md#main-process) -```javascript -const { netLog } = require('electron') +```js +const { app, netLog } = require('electron') app.whenReady().then(async () => { await netLog.startLogging('/path/to/net-log') @@ -17,21 +17,22 @@ app.whenReady().then(async () => { See [`--log-net-log`](command-line-switches.md#--log-net-logpath) to log network events throughout the app's lifecycle. -**Note:** All methods unless specified can only be used after the `ready` event -of the `app` module gets emitted. +> [!NOTE] +> All methods unless specified can only be used after the `ready` event +> of the `app` module gets emitted. ## Methods ### `netLog.startLogging(path[, options])` -* `path` String - File path to record network logs. +* `path` string - File path to record network logs. * `options` Object (optional) - * `captureMode` String (optional) - What kinds of data should be captured. By + * `captureMode` string (optional) - What kinds of data should be captured. By default, only metadata about requests will be captured. Setting this to `includeSensitive` will include cookies and authentication data. Setting it to `everything` will include all bytes transferred on sockets. Can be `default`, `includeSensitive` or `everything`. - * `maxFileSize` Number (optional) - When the log grows beyond this size, + * `maxFileSize` number (optional) - When the log grows beyond this size, logging will automatically stop. Defaults to unlimited. Returns `Promise<void>` - resolves when the net log has begun recording. @@ -48,4 +49,4 @@ Stops recording network events. If not called, net logging will automatically en ### `netLog.currentlyLogging` _Readonly_ -A `Boolean` property that indicates whether network logs are currently being recorded. +A `boolean` property that indicates whether network logs are currently being recorded. diff --git a/docs/api/net.md b/docs/api/net.md index 84ec362743633..7f166b752152b 100644 --- a/docs/api/net.md +++ b/docs/api/net.md @@ -2,7 +2,7 @@ > Issue HTTP/HTTPS requests using Chromium's native networking library -Process: [Main](../glossary.md#main-process) +Process: [Main](../glossary.md#main-process), [Utility](../glossary.md#utility-process) The `net` module is a client-side API for issuing HTTP(S) requests. It is similar to the [HTTP](https://nodejs.org/api/http.html) and @@ -26,8 +26,9 @@ Node.js. Example usage: -```javascript +```js const { app } = require('electron') + app.whenReady().then(() => { const { net } = require('electron') const request = net.request('https://github.com') @@ -54,7 +55,7 @@ The `net` module has the following methods: ### `net.request(options)` -* `options` (ClientRequestConstructorOptions | String) - The `ClientRequest` constructor options. +* `options` ([ClientRequestConstructorOptions](client-request.md#new-clientrequestoptions) | string) - The `ClientRequest` constructor options. Returns [`ClientRequest`](./client-request.md) @@ -63,9 +64,67 @@ Creates a [`ClientRequest`](./client-request.md) instance using the provided The `net.request` method would be used to issue both secure and insecure HTTP requests according to the specified protocol scheme in the `options` object. +### `net.fetch(input[, init])` + +* `input` string | [GlobalRequest](https://nodejs.org/api/globals.html#request) +* `init` [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/fetch#options) & \{ bypassCustomProtocolHandlers?: boolean \} (optional) + +Returns `Promise<GlobalResponse>` - see [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response). + +Sends a request, similarly to how `fetch()` works in the renderer, using +Chrome's network stack. This differs from Node's `fetch()`, which uses +Node.js's HTTP stack. + +Example: + +```js +async function example () { + const response = await net.fetch('https://my.app') + if (response.ok) { + const body = await response.json() + // ... use the result. + } +} +``` + +This method will issue requests from the [default session](session.md#sessiondefaultsession). +To send a `fetch` request from another session, use [ses.fetch()](session.md#sesfetchinput-init). + +See the MDN documentation for +[`fetch()`](https://developer.mozilla.org/en-US/docs/Web/API/fetch) for more +details. + +Limitations: + +* `net.fetch()` does not support the `data:` or `blob:` schemes. +* The value of the `integrity` option is ignored. +* The `.type` and `.url` values of the returned `Response` object are + incorrect. + +By default, requests made with `net.fetch` can be made to [custom protocols](protocol.md) +as well as `file:`, and will trigger [webRequest](web-request.md) handlers if present. +When the non-standard `bypassCustomProtocolHandlers` option is set in RequestInit, +custom protocol handlers will not be called for this request. This allows forwarding an +intercepted request to the built-in handler. [webRequest](web-request.md) +handlers will still be triggered when bypassing custom protocols. + +```js +protocol.handle('https', (req) => { + if (req.url === 'https://my-app.com') { + return new Response('<body>my app</body>') + } else { + return net.fetch(req, { bypassCustomProtocolHandlers: true }) + } +}) +``` + +> [!NOTE] +> In the [utility process](../glossary.md#utility-process), custom protocols +> are not supported. + ### `net.isOnline()` -Returns `Boolean` - Whether there is currently internet connection. +Returns `boolean` - Whether there is currently internet connection. A return value of `false` is a pretty strong indicator that the user won't be able to connect to remote sites. However, a return value of @@ -73,11 +132,49 @@ won't be able to connect to remote sites. However, a return value of whether a particular connection attempt to a particular remote site will be successful. +### `net.resolveHost(host, [options])` + +* `host` string - Hostname to resolve. +* `options` Object (optional) + * `queryType` string (optional) - Requested DNS query type. If unspecified, + resolver will pick A or AAAA (or both) based on IPv4/IPv6 settings: + * `A` - Fetch only A records + * `AAAA` - Fetch only AAAA records. + * `source` string (optional) - The source to use for resolved addresses. + Default allows the resolver to pick an appropriate source. Only affects use + of big external sources (e.g. calling the system for resolution or using + DNS). Even if a source is specified, results can still come from cache, + resolving "localhost" or IP literals, etc. One of the following values: + * `any` (default) - Resolver will pick an appropriate source. Results could + come from DNS, MulticastDNS, HOSTS file, etc + * `system` - Results will only be retrieved from the system or OS, e.g. via + the `getaddrinfo()` system call + * `dns` - Results will only come from DNS queries + * `mdns` - Results will only come from Multicast DNS queries + * `localOnly` - No external sources will be used. Results will only come + from fast local sources that are available no matter the source setting, + e.g. cache, hosts file, IP literal resolution, etc. + * `cacheUsage` string (optional) - Indicates what DNS cache entries, if any, + can be used to provide a response. One of the following values: + * `allowed` (default) - Results may come from the host cache if non-stale + * `staleAllowed` - Results may come from the host cache even if stale (by + expiration or network changes) + * `disallowed` - Results will not come from the host cache. + * `secureDnsPolicy` string (optional) - Controls the resolver's Secure DNS + behavior for this request. One of the following values: + * `allow` (default) + * `disable` + +Returns [`Promise<ResolvedHost>`](structures/resolved-host.md) - Resolves with the resolved IP addresses for the `host`. + +This method will resolve hosts from the [default session](session.md#sessiondefaultsession). +To resolve a host from another session, use [ses.resolveHost()](session.md#sesresolvehosthost-options). + ## Properties ### `net.online` _Readonly_ -A `Boolean` property. Whether there is currently internet connection. +A `boolean` property. Whether there is currently internet connection. A return value of `false` is a pretty strong indicator that the user won't be able to connect to remote sites. However, a return value of diff --git a/docs/api/notification.md b/docs/api/notification.md index dbf855171e350..cd4d66745c6f6 100644 --- a/docs/api/notification.md +++ b/docs/api/notification.md @@ -4,9 +4,15 @@ Process: [Main](../glossary.md#main-process) -## Using in the renderer process +> [!NOTE] +> If you want to show notifications from a renderer process you should use the +> [web Notifications API](../tutorial/notifications.md) -If you want to show Notifications from a renderer process you should use the [HTML5 Notification API](../tutorial/notifications.md) +> [!NOTE] +> On MacOS, notifications use the UNNotification API as their underlying framework. +> This API requires an application to be code-signed in order for notifications +> to appear. Unsigned binaries will emit a `failed` event when notifications +> are called. ## Class: Notification @@ -18,37 +24,130 @@ Process: [Main](../glossary.md#main-process) It creates a new `Notification` with native properties as set by the `options`. +> [!WARNING] +> Electron's built-in classes cannot be subclassed in user code. +> For more information, see [the FAQ](../faq.md#class-inheritance-does-not-work-with-electron-built-in-modules). + ### Static Methods The `Notification` class has the following static methods: #### `Notification.isSupported()` -Returns `Boolean` - Whether or not desktop notifications are supported on the current system +Returns `boolean` - Whether or not desktop notifications are supported on the current system + +#### `Notification.handleActivation(callback)` _Windows_ + +* `callback` Function + * `details` [ActivationArguments](structures/activation-arguments.md) - Details about the notification activation. + +Registers a callback to handle all notification activations. The callback is invoked whenever a +notification is clicked, replied to, or has an action button pressed - regardless of whether +the original `Notification` object is still in memory. + +This method handles timing automatically: + +* If an activation already occurred before calling this method, the callback is invoked immediately + with those details. +* For all subsequent activations, the callback is invoked when they occur. + +The callback remains registered until replaced by another call to `handleActivation`. + +This provides a centralized way to handle notification interactions that works in all scenarios: + +* Cold start (app launched from notification click) +* Notifications persisted in AC that have no in-memory representation after app re-start +* Notification object was garbage collected +* Notification object is still in memory (callback is invoked in addition to instance events) + +```js +const { Notification, app } = require('electron') + +app.whenReady().then(() => { + // Register handler for all notification activations + Notification.handleActivation((details) => { + console.log('Notification activated:', details.type) + if (details.type === 'reply') { + console.log('User reply:', details.reply) + } else if (details.type === 'action') { + console.log('Action index:', details.actionIndex) + } + }) +}) +``` + +#### `Notification.getHistory()` _macOS_ + +Returns `Promise<Notification[]>` - Resolves with an array of `Notification` objects representing all delivered notifications still present in Notification Center. + +Each returned `Notification` is a live object connected to the corresponding delivered notification. Interaction events (`click`, `reply`, `action`, `close`) will fire on these objects when the user interacts with the notification in Notification Center. This is useful after an app restart to re-attach event handlers to notifications from a previous session. + +The returned notifications have their `id`, `groupId`, `title`, `subtitle`, and `body` properties populated from information available in the Notification Center. Other properties (e.g., `actions`, `silent`, `icon`) are not available from delivered notifications and will have default values. + +> [!NOTE] +> Like all macOS notification APIs, this method requires the application to be +> code-signed. In unsigned development builds, notifications are not delivered +> to Notification Center and this method will resolve with an empty array. + +> [!NOTE] +> Unlike notifications created with `new Notification()`, notifications returned +> by `getHistory()` will remain visible in Notification Center when the object +> is garbage collected. Calling `show()` on a restored notification will remove +> the original from Notification Center and post a new one with the same +> properties. + +```js +const { Notification, app } = require('electron') + +app.whenReady().then(async () => { + // Restore notifications from a previous session + const notifications = await Notification.getHistory() + for (const n of notifications) { + console.log(`Found delivered notification: ${n.id} - ${n.title}`) + n.on('click', () => { + console.log(`User clicked: ${n.id}`) + }) + n.on('reply', (event) => { + console.log(`User replied to ${n.id}: ${event.reply}`) + }) + } + // Keep references so events continue to fire +}) +``` ### `new Notification([options])` * `options` Object (optional) - * `title` String (optional) - A title for the notification, which will be shown at the top of the notification window when it is shown. - * `subtitle` String (optional) _macOS_ - A subtitle for the notification, which will be displayed below the title. - * `body` String (optional) - The body text of the notification, which will be displayed below the title or subtitle. - * `silent` Boolean (optional) - Whether or not to emit an OS notification noise when showing the notification. - * `icon` (String | [NativeImage](native-image.md)) (optional) - An icon to use in the notification. - * `hasReply` Boolean (optional) _macOS_ - Whether or not to add an inline reply option to the notification. - * `timeoutType` String (optional) _Linux_ _Windows_ - The timeout duration of the notification. Can be 'default' or 'never'. - * `replyPlaceholder` String (optional) _macOS_ - The placeholder to write in the inline reply input field. - * `sound` String (optional) _macOS_ - The name of the sound file to play when the notification is shown. - * `urgency` String (optional) _Linux_ - The urgency level of the notification. Can be 'normal', 'critical', or 'low'. - * `actions` [NotificationAction[]](structures/notification-action.md) (optional) _macOS_ - Actions to add to the notification. Please read the available actions and limitations in the `NotificationAction` documentation. - * `closeButtonText` String (optional) _macOS_ - A custom title for the close button of an alert. An empty string will cause the default localized text to be used. - * `toastXml` String (optional) _Windows_ - A custom description of the Notification on Windows superseding all properties above. Provides full customization of design and behavior of the notification. + * `id` string (optional) _macOS_ _Windows_ - A unique identifier for the notification. On macOS, maps to `UNNotificationRequest`'s [`identifier`](https://developer.apple.com/documentation/usernotifications/unnotificationrequest/identifier) property. On Windows, maps to the toast notification's [`Tag`](https://learn.microsoft.com/en-us/uwp/api/windows.ui.notifications.toastnotification.tag) property. Defaults to a random UUID if not provided or if an empty string is passed. This can be used to remove or update previously delivered notifications. + * `groupId` string (optional) _macOS_ _Windows_ - A string identifier used to visually group notifications together in Notification Center / Action Center. On macOS, maps to `UNNotificationContent`'s [`threadIdentifier`](https://developer.apple.com/documentation/usernotifications/unnotificationcontent/threadidentifier) property. On Windows, maps to the toast notification's [`Group`](https://learn.microsoft.com/en-us/uwp/api/windows.ui.notifications.toastnotification.group) property. + * `groupTitle` string (optional) _Windows_ - A title for the notification group header. When both `groupId` and `groupTitle` are specified, Windows will display a header above the notification that groups related notifications together. Maps to the toast notification's [`header`](https://learn.microsoft.com/en-us/windows/apps/design/shell/tiles-and-notifications/toast-headers) element. + * `title` string (optional) - A title for the notification, which will be displayed at the top of the notification window when it is shown. + * `subtitle` string (optional) _macOS_ - A subtitle for the notification, which will be displayed below the title. + * `body` string (optional) - The body text of the notification, which will be displayed below the title or subtitle. + * `silent` boolean (optional) - Whether or not to suppress the OS notification noise when showing the notification. + * `icon` (string | [NativeImage](native-image.md)) (optional) - An icon to use in the notification. If a string is passed, it must be a valid path to a local icon file. + * `hasReply` boolean (optional) _macOS_ _Windows_ - Whether or not to add an inline reply option to the notification. + * `timeoutType` string (optional) _Linux_ _Windows_ - The timeout duration of the notification. Can be 'default' or 'never'. + * `replyPlaceholder` string (optional) _macOS_ _Windows_ - The placeholder to write in the inline reply input field. + * `sound` string (optional) _macOS_ - The name of the sound file to play when the notification is shown. + * `urgency` string (optional) _Linux_ _Windows_ - The urgency level of the notification. Can be 'normal', 'critical', or 'low'. + * `actions` [NotificationAction[]](structures/notification-action.md) (optional) _macOS_ _Windows_ - Actions to add to the notification. Please read the available actions and limitations in the `NotificationAction` documentation. + * `closeButtonText` string (optional) _macOS_ - A custom title for the close button of an alert. An empty string will cause the default localized text to be used. + * `toastXml` string (optional) _Windows_ - A custom description of the Notification on Windows superseding all properties above. Provides full customization of design and behavior of the notification. + +> [!NOTE] +> On Windows, `urgency` type 'critical' sorts the notification higher in Action Center (above default priority notifications), but does not prevent auto-dismissal. To prevent auto-dismissal, you should also set +> `timeoutType` to 'never'. ### Instance Events Objects created with `new Notification` emit the following events: -**Note:** Some events are only available on specific operating systems and are -labeled as such. +:::info + +Some events are only available on specific operating systems and are labeled as such. + +::: #### Event: 'show' @@ -56,10 +155,26 @@ Returns: * `event` Event -Emitted when the notification is shown to the user, note this could be fired +Emitted when the notification is shown to the user. Note that this event can be fired multiple times as a notification can be shown multiple times through the `show()` method. +```js +const { Notification, app } = require('electron') + +app.whenReady().then(() => { + const n = new Notification({ + title: 'Title!', + subtitle: 'Subtitle!', + body: 'Body!' + }) + + n.on('show', () => console.log('Notification shown!')) + + n.show() +}) +``` + #### Event: 'click' Returns: @@ -68,103 +183,249 @@ Returns: Emitted when the notification is clicked by the user. +```js +const { Notification, app } = require('electron') + +app.whenReady().then(() => { + const n = new Notification({ + title: 'Title!', + subtitle: 'Subtitle!', + body: 'Body!' + }) + + n.on('click', () => console.log('Notification clicked!')) + + n.show() +}) +``` + #### Event: 'close' Returns: -* `event` Event +* `details` Event\<\> + * `reason` _Windows_ string (optional) - The reason the notification was closed. This can be 'userCanceled', 'applicationHidden', or 'timedOut'. Emitted when the notification is closed by manual intervention from the user. This event is not guaranteed to be emitted in all cases where the notification is closed. -#### Event: 'reply' _macOS_ +On Windows, the `close` event can be emitted in one of three ways: programmatic dismissal with `notification.close()`, by the user closing the notification, or via system timeout. If a notification is in the Action Center after the initial `close` event is emitted, a call to `notification.close()` will remove the notification from the action center but the `close` event will not be emitted again. + +```js +const { Notification, app } = require('electron') + +app.whenReady().then(() => { + const n = new Notification({ + title: 'Title!', + subtitle: 'Subtitle!', + body: 'Body!' + }) + + n.on('close', () => console.log('Notification closed!')) + + n.show() +}) +``` + +#### Event: 'reply' _macOS_ _Windows_ Returns: -* `event` Event -* `reply` String - The string the user entered into the inline reply field. +* `details` Event\<\> + * `reply` string - The string the user entered into the inline reply field. +* `reply` string _Deprecated_ Emitted when the user clicks the "Reply" button on a notification with `hasReply: true`. -#### Event: 'action' _macOS_ +```js +const { Notification, app } = require('electron') + +app.whenReady().then(() => { + const n = new Notification({ + title: 'Send a Message', + body: 'Body Text', + hasReply: true, + replyPlaceholder: 'Message text...' + }) + + n.on('reply', (e, reply) => console.log(`User replied: ${reply}`)) + n.on('click', () => console.log('Notification clicked')) + + n.show() +}) +``` + +#### Event: 'action' _macOS_ _Windows_ Returns: -* `event` Event -* `index` Number - The index of the action that was activated. +* `details` Event\<\> + * `actionIndex` number - The index of the action that was activated. + * `selectionIndex` number _Windows_ - The index of the selected item, if one was chosen. -1 if none was chosen. +* `actionIndex` number _Deprecated_ +* `selectionIndex` number _Windows_ _Deprecated_ + +```js +const { Notification, app } = require('electron') + +app.whenReady().then(() => { + const items = ['One', 'Two', 'Three'] + const n = new Notification({ + title: 'Choose an Action!', + actions: [ + { type: 'button', text: 'Action 1' }, + { type: 'button', text: 'Action 2' }, + { type: 'selection', text: 'Apply', items } + ] + }) + + n.on('click', () => console.log('Notification clicked')) + n.on('action', (e) => { + console.log(`User triggered action at index: ${e.actionIndex}`) + if (e.selectionIndex > -1) { + console.log(`User chose selection item '${items[e.selectionIndex]}'`) + } + }) + + n.show() +}) +``` #### Event: 'failed' _Windows_ Returns: * `event` Event -* `error` String - The error encountered during execution of the `show()` method. +* `error` string - The error encountered during execution of the `show()` method. Emitted when an error is encountered while creating and showing the native notification. +```js +const { Notification, app } = require('electron') + +app.whenReady().then(() => { + const n = new Notification({ + title: 'Bad Action' + }) + + n.on('failed', (e, err) => { + console.log('Notification failed: ', err) + }) + + n.show() +}) +``` + ### Instance Methods -Objects created with `new Notification` have the following instance methods: +Objects created with the `new Notification()` constructor have the following instance methods: #### `notification.show()` -Immediately shows the notification to the user, please note this means unlike the -HTML5 Notification implementation, instantiating a `new Notification` does -not immediately show it to the user, you need to call this method before the OS -will display it. +Immediately shows the notification to the user. Unlike the web notification API, +instantiating a `new Notification()` does not immediately show it to the user. Instead, you need to +call this method before the OS will display it. If the notification has been shown before, this method will dismiss the previously shown notification and create a new one with identical properties. +On macOS, calling `show()` on a notification returned by `Notification.getHistory()` will +remove the original notification from Notification Center and post a new one with the same +properties. + +```js +const { Notification, app } = require('electron') + +app.whenReady().then(() => { + const n = new Notification({ + title: 'Title!', + subtitle: 'Subtitle!', + body: 'Body!' + }) + + n.show() +}) +``` + #### `notification.close()` Dismisses the notification. +On Windows, calling `notification.close()` while the notification is visible on screen will dismiss the notification and remove it from the Action Center. If `notification.close()` is called after the notification is no longer visible on screen, calling `notification.close()` will try remove it from the Action Center. + +```js +const { Notification, app } = require('electron') + +app.whenReady().then(() => { + const n = new Notification({ + title: 'Title!', + subtitle: 'Subtitle!', + body: 'Body!' + }) + + n.show() + + setTimeout(() => n.close(), 5000) +}) +``` + ### Instance Properties +#### `notification.id` _macOS_ _Windows_ _Readonly_ + +A `string` property representing the unique identifier of the notification. This is set at construction time — either from the `id` option or as a generated UUID if none was provided. + +#### `notification.groupId` _macOS_ _Windows_ _Readonly_ + +A `string` property representing the group identifier of the notification. Notifications with the same `groupId` will be visually grouped together in Notification Center (macOS) or Action Center (Windows). + +#### `notification.groupTitle` _Windows_ _Readonly_ + +A `string` property representing the title of the notification group header. + #### `notification.title` -A `String` property representing the title of the notification. +A `string` property representing the title of the notification. #### `notification.subtitle` -A `String` property representing the subtitle of the notification. +A `string` property representing the subtitle of the notification. #### `notification.body` -A `String` property representing the body of the notification. +A `string` property representing the body of the notification. #### `notification.replyPlaceholder` -A `String` property representing the reply placeholder of the notification. +A `string` property representing the reply placeholder of the notification. #### `notification.sound` -A `String` property representing the sound of the notification. +A `string` property representing the sound of the notification. #### `notification.closeButtonText` -A `String` property representing the close button text of the notification. +A `string` property representing the close button text of the notification. #### `notification.silent` -A `Boolean` property representing whether the notification is silent. +A `boolean` property representing whether the notification is silent. #### `notification.hasReply` -A `Boolean` property representing whether the notification has a reply action. +A `boolean` property representing whether the notification has a reply action. #### `notification.urgency` _Linux_ -A `String` property representing the urgency level of the notification. Can be 'normal', 'critical', or 'low'. +A `string` property representing the urgency level of the notification. Can be 'normal', 'critical', or 'low'. -Default is 'low' - see [NotifyUrgency](https://developer.gnome.org/notification-spec/#urgency-levels) for more information. +Default is 'low' - see [NotifyUrgency](https://developer-old.gnome.org/notification-spec/#urgency-levels) for more information. #### `notification.timeoutType` _Linux_ _Windows_ -A `String` property representing the type of timeout duration for the notification. Can be 'default' or 'never'. +A `string` property representing the type of timeout duration for the notification. Can be 'default' or 'never'. If `timeoutType` is set to 'never', the notification never expires. It stays open until closed by the calling API or the user. @@ -174,7 +435,7 @@ A [`NotificationAction[]`](structures/notification-action.md) property represent #### `notification.toastXml` _Windows_ -A `String` property representing the custom Toast XML of the notification. +A `string` property representing the custom Toast XML of the notification. ### Playing Sounds diff --git a/docs/api/parent-port.md b/docs/api/parent-port.md new file mode 100644 index 0000000000000..4b181b474b933 --- /dev/null +++ b/docs/api/parent-port.md @@ -0,0 +1,48 @@ +# parentPort + +> Interface for communication with parent process. + +Process: [Utility](../glossary.md#utility-process) + +`parentPort` is an [EventEmitter][event-emitter]. +_This object is not exported from the `'electron'` module. It is only available as a property of the process object in the Electron API._ + +```js +// Main process +const child = utilityProcess.fork(path.join(__dirname, 'test.js')) +child.postMessage({ message: 'hello' }) +child.on('message', (data) => { + console.log(data) // hello world! +}) + +// Child process +process.parentPort.on('message', (e) => { + process.parentPort.postMessage(`${e.data} world!`) +}) +``` + +## Events + +The `parentPort` object emits the following events: + +### Event: 'message' + +Returns: + +* `messageEvent` Object + * `data` any + * `ports` MessagePortMain[] + +Emitted when the process receives a message. Messages received on +this port will be queued up until a handler is registered for this +event. + +## Methods + +### `parentPort.postMessage(message)` + +* `message` any + +Sends a message from the process to its parent. + +[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter diff --git a/docs/api/power-monitor.md b/docs/api/power-monitor.md index 0f5e5b53ac783..83289e0739123 100644 --- a/docs/api/power-monitor.md +++ b/docs/api/power-monitor.md @@ -8,11 +8,11 @@ Process: [Main](../glossary.md#main-process) The `powerMonitor` module emits the following events: -### Event: 'suspend' _macOS_ _Windows_ +### Event: 'suspend' Emitted when the system is suspending. -### Event: 'resume' _macOS_ _Windows_ +### Event: 'resume' Emitted when system is resuming. @@ -24,6 +24,36 @@ Emitted when the system changes to AC power. Emitted when system changes to battery power. +### Event: 'thermal-state-change' _macOS_ + +Returns: + +* `details` Event\<\> + * `state` string - The system's new thermal state. Can be `unknown`, `nominal`, `fair`, `serious`, `critical`. + +Emitted when the thermal state of the system changes. Notification of a change +in the thermal status of the system, such as entering a critical temperature +range. Depending on the severity, the system might take steps to reduce said +temperature, for example, throttling the CPU or switching on the fans if +available. + +Apps may react to the new state by reducing expensive computing tasks (e.g. +video encoding), or notifying the user. The same state might be received +repeatedly. + +See https://developer.apple.com/library/archive/documentation/Performance/Conceptual/power_efficiency_guidelines_osx/RespondToThermalStateChanges.html + +### Event: 'speed-limit-change' _macOS_ _Windows_ + +Returns: + +* `details` Event\<\> + * `limit` number - The operating system's advertised speed limit for CPUs, in percent. + +Notification of a change in the operating system's advertised speed limit for +CPUs, in percent. Values below 100 indicate that the system is impairing +processing power due to thermal management. + ### Event: 'shutdown' _Linux_ _macOS_ Emitted when the system is about to reboot or shut down. If the event handler @@ -55,7 +85,7 @@ The `powerMonitor` module has the following methods: * `idleThreshold` Integer -Returns `String` - The system's current state. Can be `active`, `idle`, `locked` or `unknown`. +Returns `string` - The system's current idle state. Can be `active`, `idle`, `locked` or `unknown`. Calculate the system idle state. `idleThreshold` is the amount of time (in seconds) before considered idle. `locked` is available on supported systems only. @@ -66,9 +96,13 @@ Returns `Integer` - Idle time in seconds Calculate system idle time in seconds. +### `powerMonitor.getCurrentThermalState()` _macOS_ + +Returns `string` - The system's current thermal state. Can be `unknown`, `nominal`, `fair`, `serious`, or `critical`. + ### `powerMonitor.isOnBatteryPower()` -Returns `Boolean` - Whether the system is on battery power. +Returns `boolean` - Whether the system is on battery power. To monitor for changes in this property, use the `on-battery` and `on-ac` events. @@ -77,6 +111,6 @@ events. ### `powerMonitor.onBatteryPower` -A `Boolean` property. True if the system is on battery power. +A `boolean` property. True if the system is on battery power. See [`powerMonitor.isOnBatteryPower()`](#powermonitorisonbatterypower). diff --git a/docs/api/power-save-blocker.md b/docs/api/power-save-blocker.md index 548b02756c678..348a6b78907a6 100644 --- a/docs/api/power-save-blocker.md +++ b/docs/api/power-save-blocker.md @@ -6,7 +6,7 @@ Process: [Main](../glossary.md#main-process) For example: -```javascript +```js const { powerSaveBlocker } = require('electron') const id = powerSaveBlocker.start('prevent-display-sleep') @@ -21,7 +21,7 @@ The `powerSaveBlocker` module has the following methods: ### `powerSaveBlocker.start(type)` -* `type` String - Power save blocker type. +* `type` string - Power save blocker type. * `prevent-app-suspension` - Prevent the application from being suspended. Keeps system active but allows screen to be turned off. Example use cases: downloading a file or playing audio. @@ -33,10 +33,11 @@ Returns `Integer` - The blocker ID that is assigned to this power blocker. Starts preventing the system from entering lower-power mode. Returns an integer identifying the power save blocker. -**Note:** `prevent-display-sleep` has higher precedence over -`prevent-app-suspension`. Only the highest precedence type takes effect. In -other words, `prevent-display-sleep` always takes precedence over -`prevent-app-suspension`. +> [!NOTE] +> `prevent-display-sleep` has higher precedence over +> `prevent-app-suspension`. Only the highest precedence type takes effect. In +> other words, `prevent-display-sleep` always takes precedence over +> `prevent-app-suspension`. For example, an API calling A requests for `prevent-app-suspension`, and another calling B requests for `prevent-display-sleep`. `prevent-display-sleep` @@ -49,8 +50,10 @@ is used. Stops the specified power save blocker. +Returns `boolean` - Whether the specified `powerSaveBlocker` has been stopped. + ### `powerSaveBlocker.isStarted(id)` * `id` Integer - The power save blocker id returned by `powerSaveBlocker.start`. -Returns `Boolean` - Whether the corresponding `powerSaveBlocker` has started. +Returns `boolean` - Whether the corresponding `powerSaveBlocker` has started. diff --git a/docs/api/process.md b/docs/api/process.md index d3de0264c48bd..3833bf40d58f9 100644 --- a/docs/api/process.md +++ b/docs/api/process.md @@ -12,28 +12,30 @@ It adds the following events, properties, and methods: In sandboxed renderers the `process` object contains only a subset of the APIs: -- `crash()` -- `hang()` -- `getCreationTime()` -- `getHeapStatistics()` -- `getBlinkMemoryInfo()` -- `getProcessMemoryInfo()` -- `getSystemMemoryInfo()` -- `getSystemVersion()` -- `getCPUUsage()` -- `getIOCounters()` -- `argv` -- `execPath` -- `env` -- `pid` -- `arch` -- `platform` -- `sandboxed` -- `type` -- `version` -- `versions` -- `mas` -- `windowsStore` +* `crash()` +* `hang()` +* `getCreationTime()` +* `getHeapStatistics()` +* `getBlinkMemoryInfo()` +* `getProcessMemoryInfo()` +* `getSystemMemoryInfo()` +* `getSystemVersion()` +* `getCPUUsage()` +* `uptime()` +* `argv` +* `execPath` +* `env` +* `pid` +* `arch` +* `platform` +* `sandboxed` +* `contextIsolated` +* `type` +* `version` +* `versions` +* `mas` +* `windowsStore` +* `contextId` ## Events @@ -42,95 +44,104 @@ In sandboxed renderers the `process` object contains only a subset of the APIs: Emitted when Electron has loaded its internal initialization script and is beginning to load the web page or the main script. -It can be used by the preload script to add removed Node global symbols back to -the global scope when node integration is turned off: - -```javascript -// preload.js -const _setImmediate = setImmediate -const _clearImmediate = clearImmediate -process.once('loaded', () => { - global.setImmediate = _setImmediate - global.clearImmediate = _clearImmediate -}) -``` - ## Properties ### `process.defaultApp` _Readonly_ -A `Boolean`. When app is started by being passed as parameter to the default app, this +A `boolean`. When the app is started by being passed as parameter to the default Electron executable, this property is `true` in the main process, otherwise it is `undefined`. +For example when running the app with `electron .`, it is `true`, +even if the app is packaged ([`isPackaged`](app.md#appispackaged-readonly)) is `true`. +This can be useful to determine how many arguments will need to be sliced off from `process.argv`. ### `process.isMainFrame` _Readonly_ -A `Boolean`, `true` when the current renderer context is the "main" renderer +A `boolean`, `true` when the current renderer context is the "main" renderer frame. If you want the ID of the current frame you should use `webFrame.routingId`. ### `process.mas` _Readonly_ -A `Boolean`. For Mac App Store build, this property is `true`, for other builds it is +A `boolean`. For Mac App Store build, this property is `true`, for other builds it is `undefined`. ### `process.noAsar` -A `Boolean` that controls ASAR support inside your application. Setting this to `true` +A `boolean` that controls ASAR support inside your application. Setting this to `true` will disable the support for `asar` archives in Node's built-in modules. ### `process.noDeprecation` -A `Boolean` that controls whether or not deprecation warnings are printed to `stderr`. +A `boolean` (optional) that controls whether or not deprecation warnings are printed to `stderr`. Setting this to `true` will silence deprecation warnings. This property is used instead of the `--no-deprecation` command line flag. ### `process.resourcesPath` _Readonly_ -A `String` representing the path to the resources directory. +A `string` representing the path to the resources directory. ### `process.sandboxed` _Readonly_ -A `Boolean`. When the renderer process is sandboxed, this property is `true`, +A `boolean`. When the renderer process is sandboxed, this property is `true`, otherwise it is `undefined`. +### `process.contextIsolated` _Readonly_ + +A `boolean` that indicates whether the current renderer context has `contextIsolation` enabled. +It is `undefined` in the main process. + ### `process.throwDeprecation` -A `Boolean` that controls whether or not deprecation warnings will be thrown as +A `boolean` that controls whether or not deprecation warnings will be thrown as exceptions. Setting this to `true` will throw errors for deprecations. This property is used instead of the `--throw-deprecation` command line flag. ### `process.traceDeprecation` -A `Boolean` that controls whether or not deprecations printed to `stderr` include +A `boolean` that controls whether or not deprecations printed to `stderr` include their stack trace. Setting this to `true` will print stack traces for deprecations. - This property is instead of the `--trace-deprecation` command line flag. + This property is used instead of the `--trace-deprecation` command line flag. ### `process.traceProcessWarnings` -A `Boolean` that controls whether or not process warnings printed to `stderr` include +A `boolean` that controls whether or not process warnings printed to `stderr` include their stack trace. Setting this to `true` will print stack traces for process warnings - (including deprecations). This property is instead of the `--trace-warnings` command + (including deprecations). This property is used instead of the `--trace-warnings` command line flag. ### `process.type` _Readonly_ -A `String` representing the current process's type, can be: +A `string` representing the current process's type, can be: * `browser` - The main process * `renderer` - A renderer process +* `service-worker` - In a service worker * `worker` - In a web worker +* `utility` - In a node process launched as a service ### `process.versions.chrome` _Readonly_ -A `String` representing Chrome's version string. +A `string` representing Chrome's version string. ### `process.versions.electron` _Readonly_ -A `String` representing Electron's version string. +A `string` representing Electron's version string. ### `process.windowsStore` _Readonly_ -A `Boolean`. If the app is running as a Windows Store app (appx), this property is `true`, -for otherwise it is `undefined`. +A `boolean`. If the app is running as an MSIX package (including AppX for Windows Store), +this property is `true`, otherwise it is `undefined`. + +### `process.contextId` _Readonly_ + +A `string` (optional) representing a globally unique ID of the current JavaScript context. +Each frame has its own JavaScript context. When contextIsolation is enabled, the isolated +world also has a separate JavaScript context. +This property is only available in the renderer process. + +### `process.parentPort` + +A [`Electron.ParentPort`](parent-port.md) property if this is a [`UtilityProcess`](utility-process.md) +(or `null` otherwise) allowing communication with the parent process. ## Methods @@ -142,7 +153,7 @@ Causes the main thread of the current process crash. ### `process.getCreationTime()` -Returns `Number | null` - The number of milliseconds since epoch, or `null` if the information is unavailable +Returns `number | null` - The number of milliseconds since epoch, or `null` if the information is unavailable Indicates the creation time of the application. The time is represented as number of milliseconds since epoch. It returns null if it is unable to get the process creation time. @@ -151,10 +162,6 @@ The time is represented as number of milliseconds since epoch. It returns null i Returns [`CPUUsage`](structures/cpu-usage.md) -### `process.getIOCounters()` _Windows_ _Linux_ - -Returns [`IOCounters`](structures/io-counters.md) - ### `process.getHeapStatistics()` Returns `Object`: @@ -167,7 +174,7 @@ Returns `Object`: * `heapSizeLimit` Integer * `mallocedMemory` Integer * `peakMallocedMemory` Integer -* `doesZapGarbage` Boolean +* `doesZapGarbage` boolean Returns an object with V8 heap statistics. Note that all statistics are reported in Kilobytes. @@ -176,7 +183,6 @@ Returns an object with V8 heap statistics. Note that all statistics are reported Returns `Object`: * `allocated` Integer - Size of all allocated objects in Kilobytes. -* `marked` Integer - Size of all marked objects in Kilobytes. * `total` Integer - Total allocated space in Kilobytes. Returns an object with Blink memory information. @@ -205,6 +211,10 @@ Returns `Object`: system. * `free` Integer - The total amount of memory not being used by applications or disk cache. +* `fileBacked` Integer _macOS_ - The amount of memory that currently has been paged out to storage. + Includes memory for file caches, network buffers, and other system services. +* `purgeable` Integer _macOS_ - The amount of memory that is marked as "purgeable". The system can reclaim it + if memory pressure increases. * `swapTotal` Integer _Windows_ _Linux_ - The total amount of swap memory in Kilobytes available to the system. * `swapFree` Integer _Windows_ _Linux_ - The free amount of swap memory in Kilobytes available to the @@ -215,7 +225,7 @@ that all statistics are reported in Kilobytes. ### `process.getSystemVersion()` -Returns `String` - The version of the host operating system. +Returns `string` - The version of the host operating system. Example: @@ -227,13 +237,14 @@ console.log(version) // On Linux -> '4.15.0-45-generic' ``` -**Note:** It returns the actual operating system version instead of kernel version on macOS unlike `os.release()`. +> [!NOTE] +> It returns the actual operating system version instead of kernel version on macOS unlike `os.release()`. ### `process.takeHeapSnapshot(filePath)` -* `filePath` String - Path to the output file. +* `filePath` string - Path to the output file. -Returns `Boolean` - Indicates whether the snapshot has been created successfully. +Returns `boolean` - Indicates whether the snapshot has been created successfully. Takes a V8 heap snapshot and saves it to `filePath`. diff --git a/docs/api/protocol.md b/docs/api/protocol.md index 7b5115dc90fe3..c1ee54e511c07 100644 --- a/docs/api/protocol.md +++ b/docs/api/protocol.md @@ -7,20 +7,23 @@ Process: [Main](../glossary.md#main-process) An example of implementing a protocol that has the same effect as the `file://` protocol: -```javascript -const { app, protocol } = require('electron') -const path = require('path') +```js +const { app, protocol, net } = require('electron') + +const path = require('node:path') +const url = require('node:url') app.whenReady().then(() => { - protocol.registerFileProtocol('atom', (request, callback) => { - const url = request.url.substr(7) - callback({ path: path.normalize(`${__dirname}/${url}`) }) + protocol.handle('atom', (request) => { + const filePath = request.url.slice('atom://'.length) + return net.fetch(url.pathToFileURL(path.join(__dirname, filePath)).toString()) }) }) ``` -**Note:** All methods unless specified can only be used after the `ready` event -of the `app` module gets emitted. +> [!NOTE] +> All methods unless specified can only be used after the `ready` event +> of the `app` module gets emitted. ## Using `protocol` with a custom `partition` or `session` @@ -34,23 +37,34 @@ a different session and your custom protocol will not work if you just use To have your custom protocol work in combination with a custom session, you need to register it to that session explicitly. -```javascript -const { session, app, protocol } = require('electron') -const path = require('path') +```js +const { app, BrowserWindow, net, protocol, session } = require('electron') + +const path = require('node:path') +const url = require('node:url') app.whenReady().then(() => { const partition = 'persist:example' const ses = session.fromPartition(partition) - ses.protocol.registerFileProtocol('atom', (request, callback) => { - const url = request.url.substr(7) - callback({ path: path.normalize(`${__dirname}/${url}`) }) + ses.protocol.handle('atom', (request) => { + const filePath = request.url.slice('atom://'.length) + return net.fetch(url.pathToFileURL(path.resolve(__dirname, filePath)).toString()) }) - mainWindow = new BrowserWindow({ webPreferences: { partition } }) + const mainWindow = new BrowserWindow({ webPreferences: { partition } }) }) ``` +## Protocol names + +[RFC 3986](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) defines what a valid +protocol name is: + +> Scheme names consist of a sequence of characters beginning with a letter and followed +> by any combination of letters, digits, plus ("+"), period ("."), or hyphen ("-"). +> Although schemes are case-insensitive, the canonical form is lowercase […]. + ## Methods The `protocol` module has the following methods: @@ -59,26 +73,28 @@ The `protocol` module has the following methods: * `customSchemes` [CustomScheme[]](structures/custom-scheme.md) -**Note:** This method can only be used before the `ready` event of the `app` -module gets emitted and can be called only once. +> [!NOTE] +> This method can only be used before the `ready` event of the `app` +> module gets emitted and can be called only once. Registers the `scheme` as standard, secure, bypasses content security policy for -resources, allows registering ServiceWorker, supports fetch API, and streaming -video/audio. Specify a privilege with the value of `true` to enable the capability. +resources, allows registering ServiceWorker, supports fetch API, streaming +video/audio, and V8 code cache. Specify a privilege with the value of `true` to +enable the capability. An example of registering a privileged scheme, that bypasses Content Security Policy: -```javascript +```js const { protocol } = require('electron') + protocol.registerSchemesAsPrivileged([ { scheme: 'foo', privileges: { bypassCSP: true } } ]) ``` -A standard scheme adheres to what RFC 3986 calls [generic URI -syntax](https://tools.ietf.org/html/rfc3986#section-3). For example `http` and -`https` are standard schemes, while `file` is not. +A standard scheme adheres to what RFC 3986 calls [generic URI syntax](https://tools.ietf.org/html/rfc3986#section-3). +For example `http` and `https` are standard schemes, while `file` is not. Registering a scheme as standard allows relative and absolute resources to be resolved correctly when served. Otherwise the scheme will behave like the @@ -108,15 +124,102 @@ The `<video>` and `<audio>` HTML elements expect protocols to buffer their responses by default. The `stream` flag configures those elements to correctly expect streaming responses. -### `protocol.registerFileProtocol(scheme, handler)` +### `protocol.handle(scheme, handler)` + +* `scheme` string - scheme to handle, for example `https` or `my-app`. This is + the bit before the `:` in a URL. +* `handler` Function\<[GlobalResponse](https://nodejs.org/api/globals.html#response) | Promise\<GlobalResponse\>\> + * `request` [GlobalRequest](https://nodejs.org/api/globals.html#request) + +Register a protocol handler for `scheme`. Requests made to URLs with this +scheme will delegate to this handler to determine what response should be sent. + +Either a `Response` or a `Promise<Response>` can be returned. + +Example: + +```js +const { app, net, protocol } = require('electron') + +const path = require('node:path') +const { pathToFileURL } = require('node:url') + +protocol.registerSchemesAsPrivileged([ + { + scheme: 'app', + privileges: { + standard: true, + secure: true, + supportFetchAPI: true + } + } +]) + +app.whenReady().then(() => { + protocol.handle('app', (req) => { + const { host, pathname } = new URL(req.url) + if (host === 'bundle') { + if (pathname === '/') { + return new Response('<h1>hello, world</h1>', { + headers: { 'content-type': 'text/html' } + }) + } + // NB, this checks for paths that escape the bundle, e.g. + // app://bundle/../../secret_file.txt + const pathToServe = path.resolve(__dirname, pathname) + const relativePath = path.relative(__dirname, pathToServe) + const isSafe = relativePath && !relativePath.startsWith('..') && !path.isAbsolute(relativePath) + if (!isSafe) { + return new Response('bad', { + status: 400, + headers: { 'content-type': 'text/html' } + }) + } + + return net.fetch(pathToFileURL(pathToServe).toString()) + } else if (host === 'api') { + return net.fetch('https://api.my-server.com/' + pathname, { + method: req.method, + headers: req.headers, + body: req.body + }) + } + }) +}) +``` + +See the MDN docs for [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) and [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) for more details. + +### `protocol.unhandle(scheme)` -* `scheme` String +* `scheme` string - scheme for which to remove the handler. + +Removes a protocol handler registered with `protocol.handle`. + +### `protocol.isProtocolHandled(scheme)` + +* `scheme` string + +Returns `boolean` - Whether `scheme` is already handled. + +### `protocol.registerFileProtocol(scheme, handler)` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/36674 + description: "`protocol.register*Protocol` and `protocol.intercept*Protocol` methods have been replaced with `protocol.handle`" + breaking-changes-header: deprecated-protocolunregisterinterceptbufferstringstreamfilehttpprotocol-and-protocolisprotocolregisteredintercepted +``` +--> + +* `scheme` string * `handler` Function * `request` [ProtocolRequest](structures/protocol-request.md) * `callback` Function - * `response` (String | [ProtocolResponse](structures/protocol-response.md)) + * `response` (string | [ProtocolResponse](structures/protocol-response.md)) -Returns `Boolean` - Whether the protocol was successfully registered +Returns `boolean` - Whether the protocol was successfully registered Registers a protocol of `scheme` that will send a file as the response. The `handler` will be called with `request` and `callback` where `request` is @@ -129,15 +232,24 @@ path or an object that has a `path` property, e.g. `callback(filePath)` or By default the `scheme` is treated like `http:`, which is parsed differently from protocols that follow the "generic URI syntax" like `file:`. -### `protocol.registerBufferProtocol(scheme, handler)` +### `protocol.registerBufferProtocol(scheme, handler)` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/36674 + description: "`protocol.register*Protocol` and `protocol.intercept*Protocol` methods have been replaced with `protocol.handle`" + breaking-changes-header: deprecated-protocolunregisterinterceptbufferstringstreamfilehttpprotocol-and-protocolisprotocolregisteredintercepted +``` +--> -* `scheme` String +* `scheme` string * `handler` Function * `request` [ProtocolRequest](structures/protocol-request.md) * `callback` Function * `response` (Buffer | [ProtocolResponse](structures/protocol-response.md)) -Returns `Boolean` - Whether the protocol was successfully registered +Returns `boolean` - Whether the protocol was successfully registered Registers a protocol of `scheme` that will send a `Buffer` as a response. @@ -147,52 +259,79 @@ property. Example: -```javascript +```js protocol.registerBufferProtocol('atom', (request, callback) => { callback({ mimeType: 'text/html', data: Buffer.from('<h5>Response</h5>') }) }) ``` -### `protocol.registerStringProtocol(scheme, handler)` +### `protocol.registerStringProtocol(scheme, handler)` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/36674 + description: "`protocol.register*Protocol` and `protocol.intercept*Protocol` methods have been replaced with `protocol.handle`" + breaking-changes-header: deprecated-protocolunregisterinterceptbufferstringstreamfilehttpprotocol-and-protocolisprotocolregisteredintercepted +``` +--> -* `scheme` String +* `scheme` string * `handler` Function * `request` [ProtocolRequest](structures/protocol-request.md) * `callback` Function - * `response` (String | [ProtocolResponse](structures/protocol-response.md)) + * `response` (string | [ProtocolResponse](structures/protocol-response.md)) -Returns `Boolean` - Whether the protocol was successfully registered +Returns `boolean` - Whether the protocol was successfully registered -Registers a protocol of `scheme` that will send a `String` as a response. +Registers a protocol of `scheme` that will send a `string` as a response. The usage is the same with `registerFileProtocol`, except that the `callback` -should be called with either a `String` or an object that has the `data` +should be called with either a `string` or an object that has the `data` property. -### `protocol.registerHttpProtocol(scheme, handler)` +### `protocol.registerHttpProtocol(scheme, handler)` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/36674 + description: "`protocol.register*Protocol` and `protocol.intercept*Protocol` methods have been replaced with `protocol.handle`" + breaking-changes-header: deprecated-protocolunregisterinterceptbufferstringstreamfilehttpprotocol-and-protocolisprotocolregisteredintercepted +``` +--> -* `scheme` String +* `scheme` string * `handler` Function * `request` [ProtocolRequest](structures/protocol-request.md) * `callback` Function - * `response` ProtocolResponse + * `response` [ProtocolResponse](structures/protocol-response.md) -Returns `Boolean` - Whether the protocol was successfully registered +Returns `boolean` - Whether the protocol was successfully registered Registers a protocol of `scheme` that will send an HTTP request as a response. The usage is the same with `registerFileProtocol`, except that the `callback` should be called with an object that has the `url` property. -### `protocol.registerStreamProtocol(scheme, handler)` +### `protocol.registerStreamProtocol(scheme, handler)` _Deprecated_ -* `scheme` String +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/36674 + description: "`protocol.register*Protocol` and `protocol.intercept*Protocol` methods have been replaced with `protocol.handle`" + breaking-changes-header: deprecated-protocolunregisterinterceptbufferstringstreamfilehttpprotocol-and-protocolisprotocolregisteredintercepted +``` +--> + +* `scheme` string * `handler` Function * `request` [ProtocolRequest](structures/protocol-request.md) * `callback` Function * `response` (ReadableStream | [ProtocolResponse](structures/protocol-response.md)) -Returns `Boolean` - Whether the protocol was successfully registered +Returns `boolean` - Whether the protocol was successfully registered Registers a protocol of `scheme` that will send a stream as a response. @@ -202,9 +341,10 @@ has the `data` property. Example: -```javascript +```js const { protocol } = require('electron') -const { PassThrough } = require('stream') + +const { PassThrough } = require('node:stream') function createStream (text) { const rv = new PassThrough() // PassThrough is also a Readable stream @@ -227,103 +367,184 @@ protocol.registerStreamProtocol('atom', (request, callback) => { It is possible to pass any object that implements the readable stream API (emits `data`/`end`/`error` events). For example, here's how a file could be returned: -```javascript +```js protocol.registerStreamProtocol('atom', (request, callback) => { callback(fs.createReadStream('index.html')) }) ``` -### `protocol.unregisterProtocol(scheme)` +### `protocol.unregisterProtocol(scheme)` _Deprecated_ -* `scheme` String +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/36674 + description: "`protocol.register*Protocol` and `protocol.intercept*Protocol` methods have been replaced with `protocol.handle`" + breaking-changes-header: deprecated-protocolunregisterinterceptbufferstringstreamfilehttpprotocol-and-protocolisprotocolregisteredintercepted +``` +--> -Returns `Boolean` - Whether the protocol was successfully unregistered +* `scheme` string + +Returns `boolean` - Whether the protocol was successfully unregistered Unregisters the custom protocol of `scheme`. -### `protocol.isProtocolRegistered(scheme)` +### `protocol.isProtocolRegistered(scheme)` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/36674 + description: "`protocol.register*Protocol` and `protocol.intercept*Protocol` methods have been replaced with `protocol.handle`" + breaking-changes-header: deprecated-protocolunregisterinterceptbufferstringstreamfilehttpprotocol-and-protocolisprotocolregisteredintercepted +``` +--> -* `scheme` String +* `scheme` string -Returns `Boolean` - Whether `scheme` is already registered. +Returns `boolean` - Whether `scheme` is already registered. -### `protocol.interceptFileProtocol(scheme, handler)` +### `protocol.interceptFileProtocol(scheme, handler)` _Deprecated_ -* `scheme` String +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/36674 + description: "`protocol.register*Protocol` and `protocol.intercept*Protocol` methods have been replaced with `protocol.handle`" + breaking-changes-header: deprecated-protocolunregisterinterceptbufferstringstreamfilehttpprotocol-and-protocolisprotocolregisteredintercepted +``` +--> + +* `scheme` string * `handler` Function * `request` [ProtocolRequest](structures/protocol-request.md) * `callback` Function - * `response` (String | [ProtocolResponse](structures/protocol-response.md)) + * `response` (string | [ProtocolResponse](structures/protocol-response.md)) -Returns `Boolean` - Whether the protocol was successfully intercepted +Returns `boolean` - Whether the protocol was successfully intercepted Intercepts `scheme` protocol and uses `handler` as the protocol's new handler which sends a file as a response. -### `protocol.interceptStringProtocol(scheme, handler)` +### `protocol.interceptStringProtocol(scheme, handler)` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/36674 + description: "`protocol.register*Protocol` and `protocol.intercept*Protocol` methods have been replaced with `protocol.handle`" + breaking-changes-header: deprecated-protocolunregisterinterceptbufferstringstreamfilehttpprotocol-and-protocolisprotocolregisteredintercepted +``` +--> -* `scheme` String +* `scheme` string * `handler` Function * `request` [ProtocolRequest](structures/protocol-request.md) * `callback` Function - * `response` (String | [ProtocolResponse](structures/protocol-response.md)) + * `response` (string | [ProtocolResponse](structures/protocol-response.md)) -Returns `Boolean` - Whether the protocol was successfully intercepted +Returns `boolean` - Whether the protocol was successfully intercepted Intercepts `scheme` protocol and uses `handler` as the protocol's new handler -which sends a `String` as a response. +which sends a `string` as a response. -### `protocol.interceptBufferProtocol(scheme, handler)` +### `protocol.interceptBufferProtocol(scheme, handler)` _Deprecated_ -* `scheme` String +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/36674 + description: "`protocol.register*Protocol` and `protocol.intercept*Protocol` methods have been replaced with `protocol.handle`" + breaking-changes-header: deprecated-protocolunregisterinterceptbufferstringstreamfilehttpprotocol-and-protocolisprotocolregisteredintercepted +``` +--> + +* `scheme` string * `handler` Function * `request` [ProtocolRequest](structures/protocol-request.md) * `callback` Function * `response` (Buffer | [ProtocolResponse](structures/protocol-response.md)) -Returns `Boolean` - Whether the protocol was successfully intercepted +Returns `boolean` - Whether the protocol was successfully intercepted Intercepts `scheme` protocol and uses `handler` as the protocol's new handler which sends a `Buffer` as a response. -### `protocol.interceptHttpProtocol(scheme, handler)` +### `protocol.interceptHttpProtocol(scheme, handler)` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/36674 + description: "`protocol.register*Protocol` and `protocol.intercept*Protocol` methods have been replaced with `protocol.handle`" + breaking-changes-header: deprecated-protocolunregisterinterceptbufferstringstreamfilehttpprotocol-and-protocolisprotocolregisteredintercepted +``` +--> -* `scheme` String +* `scheme` string * `handler` Function * `request` [ProtocolRequest](structures/protocol-request.md) * `callback` Function * `response` [ProtocolResponse](structures/protocol-response.md) -Returns `Boolean` - Whether the protocol was successfully intercepted +Returns `boolean` - Whether the protocol was successfully intercepted Intercepts `scheme` protocol and uses `handler` as the protocol's new handler which sends a new HTTP request as a response. -### `protocol.interceptStreamProtocol(scheme, handler)` +### `protocol.interceptStreamProtocol(scheme, handler)` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/36674 + description: "`protocol.register*Protocol` and `protocol.intercept*Protocol` methods have been replaced with `protocol.handle`" + breaking-changes-header: deprecated-protocolunregisterinterceptbufferstringstreamfilehttpprotocol-and-protocolisprotocolregisteredintercepted +``` +--> -* `scheme` String +* `scheme` string * `handler` Function * `request` [ProtocolRequest](structures/protocol-request.md) * `callback` Function * `response` (ReadableStream | [ProtocolResponse](structures/protocol-response.md)) -Returns `Boolean` - Whether the protocol was successfully intercepted +Returns `boolean` - Whether the protocol was successfully intercepted Same as `protocol.registerStreamProtocol`, except that it replaces an existing protocol handler. -### `protocol.uninterceptProtocol(scheme)` +### `protocol.uninterceptProtocol(scheme)` _Deprecated_ -* `scheme` String +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/36674 + description: "`protocol.register*Protocol` and `protocol.intercept*Protocol` methods have been replaced with `protocol.handle`" + breaking-changes-header: deprecated-protocolunregisterinterceptbufferstringstreamfilehttpprotocol-and-protocolisprotocolregisteredintercepted +``` +--> -Returns `Boolean` - Whether the protocol was successfully unintercepted +* `scheme` string + +Returns `boolean` - Whether the protocol was successfully unintercepted Remove the interceptor installed for `scheme` and restore its original handler. -### `protocol.isProtocolIntercepted(scheme)` +### `protocol.isProtocolIntercepted(scheme)` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/36674 + description: "`protocol.register*Protocol` and `protocol.intercept*Protocol` methods have been replaced with `protocol.handle`" + breaking-changes-header: deprecated-protocolunregisterinterceptbufferstringstreamfilehttpprotocol-and-protocolisprotocolregisteredintercepted +``` +--> -* `scheme` String +* `scheme` string -Returns `Boolean` - Whether `scheme` is already intercepted. +Returns `boolean` - Whether `scheme` is already intercepted. [file-system-api]: https://developer.mozilla.org/en-US/docs/Web/API/LocalFileSystem diff --git a/docs/api/push-notifications.md b/docs/api/push-notifications.md new file mode 100644 index 0000000000000..099689d927300 --- /dev/null +++ b/docs/api/push-notifications.md @@ -0,0 +1,52 @@ +# pushNotifications + +Process: [Main](../glossary.md#main-process) + +> Register for and receive notifications from remote push notification services + +For example, when registering for push notifications via Apple push notification services (APNS): + +```js +const { pushNotifications, Notification } = require('electron') + +pushNotifications.registerForAPNSNotifications().then((token) => { + // forward token to your remote notification server +}) + +pushNotifications.on('received-apns-notification', (event, userInfo) => { + // generate a new Notification object with the relevant userInfo fields +}) +``` + +## Events + +The `pushNotification` module emits the following events: + +#### Event: 'received-apns-notification' _macOS_ + +Returns: + +* `event` Event +* `userInfo` Record\<String, any\> + +Emitted when the app receives a remote notification while running. +See: https://developer.apple.com/documentation/appkit/nsapplicationdelegate/1428430-application?language=objc + +## Methods + +The `pushNotification` module has the following methods: + +### `pushNotifications.registerForAPNSNotifications()` _macOS_ + +Returns `Promise<string>` + +Registers the app with Apple Push Notification service (APNS) to receive [Badge, Sound, and Alert](https://developer.apple.com/documentation/appkit/nsremotenotificationtype?language=objc) notifications. If registration is successful, the promise will be resolved with the APNS device token. Otherwise, the promise will be rejected with an error message. +See: https://developer.apple.com/documentation/appkit/nsapplication/1428476-registerforremotenotificationtyp?language=objc + +### `pushNotifications.unregisterForAPNSNotifications()` _macOS_ + +Unregisters the app from notifications received from APNS. + +Apps unregistered through this method can always reregister. + +See: https://developer.apple.com/documentation/appkit/nsapplication/1428747-unregisterforremotenotifications?language=objc diff --git a/docs/api/remote.md b/docs/api/remote.md deleted file mode 100644 index 01f963673505a..0000000000000 --- a/docs/api/remote.md +++ /dev/null @@ -1,217 +0,0 @@ -# remote - -> Use main process modules from the renderer process. - -Process: [Renderer](../glossary.md#renderer-process) - -> ⚠️ WARNING ⚠️ -> The `remote` module is [deprecated](https://github.com/electron/electron/issues/21408). -> Instead of `remote`, use [`ipcRenderer`](ipc-renderer.md) and -> [`ipcMain`](ipc-main.md). -> -> Read more about why the `remote` module is deprecated [here](https://medium.com/@nornagon/electrons-remote-module-considered-harmful-70d69500f31). -> -> If you still want to use `remote` despite the performance and security -> concerns, see [@electron/remote](https://github.com/electron/remote). - -The `remote` module provides a simple way to do inter-process communication -(IPC) between the renderer process (web page) and the main process. - -In Electron, GUI-related modules (such as `dialog`, `menu` etc.) are only -available in the main process, not in the renderer process. In order to use them -from the renderer process, the `ipc` module is necessary to send inter-process -messages to the main process. With the `remote` module, you can invoke methods -of the main process object without explicitly sending inter-process messages, -similar to Java's [RMI][rmi]. An example of creating a browser window from a -renderer process: - -```javascript -const { BrowserWindow } = require('electron').remote -const win = new BrowserWindow({ width: 800, height: 600 }) -win.loadURL('https://github.com') -``` - -**Note:** For the reverse (access the renderer process from the main process), -you can use [webContents.executeJavaScript](web-contents.md#contentsexecutejavascriptcode-usergesture). - -**Note:** The remote module can be disabled for security reasons in the following contexts: - -- [`BrowserWindow`](browser-window.md) - by setting the `enableRemoteModule` option to `false`. -- [`<webview>`](webview-tag.md) - by setting the `enableremotemodule` attribute to `false`. - -## Remote Objects - -Each object (including functions) returned by the `remote` module represents an -object in the main process (we call it a remote object or remote function). -When you invoke methods of a remote object, call a remote function, or create -a new object with the remote constructor (function), you are actually sending -synchronous inter-process messages. - -In the example above, both [`BrowserWindow`](browser-window.md) and `win` were remote objects and -`new BrowserWindow` didn't create a `BrowserWindow` object in the renderer -process. Instead, it created a `BrowserWindow` object in the main process and -returned the corresponding remote object in the renderer process, namely the -`win` object. - -**Note:** Only [enumerable properties][enumerable-properties] which are present -when the remote object is first referenced are accessible via remote. - -**Note:** Arrays and Buffers are copied over IPC when accessed via the `remote` -module. Modifying them in the renderer process does not modify them in the main -process and vice versa. - -## Lifetime of Remote Objects - -Electron makes sure that as long as the remote object in the renderer process -lives (in other words, has not been garbage collected), the corresponding object -in the main process will not be released. When the remote object has been -garbage collected, the corresponding object in the main process will be -dereferenced. - -If the remote object is leaked in the renderer process (e.g. stored in a map but -never freed), the corresponding object in the main process will also be leaked, -so you should be very careful not to leak remote objects. - -Primary value types like strings and numbers, however, are sent by copy. - -## Passing callbacks to the main process - -Code in the main process can accept callbacks from the renderer - for instance -the `remote` module - but you should be extremely careful when using this -feature. - -First, in order to avoid deadlocks, the callbacks passed to the main process -are called asynchronously. You should not expect the main process to -get the return value of the passed callbacks. - -For instance you can't use a function from the renderer process in an -`Array.map` called in the main process: - -```javascript -// main process mapNumbers.js -exports.withRendererCallback = (mapper) => { - return [1, 2, 3].map(mapper) -} - -exports.withLocalCallback = () => { - return [1, 2, 3].map(x => x + 1) -} -``` - -```javascript -// renderer process -const mapNumbers = require('electron').remote.require('./mapNumbers') -const withRendererCb = mapNumbers.withRendererCallback(x => x + 1) -const withLocalCb = mapNumbers.withLocalCallback() - -console.log(withRendererCb, withLocalCb) -// [undefined, undefined, undefined], [2, 3, 4] -``` - -As you can see, the renderer callback's synchronous return value was not as -expected, and didn't match the return value of an identical callback that lives -in the main process. - -Second, the callbacks passed to the main process will persist until the -main process garbage-collects them. - -For example, the following code seems innocent at first glance. It installs a -callback for the `close` event on a remote object: - -```javascript -require('electron').remote.getCurrentWindow().on('close', () => { - // window was closed... -}) -``` - -But remember the callback is referenced by the main process until you -explicitly uninstall it. If you do not, each time you reload your window the -callback will be installed again, leaking one callback for each restart. - -To make things worse, since the context of previously installed callbacks has -been released, exceptions will be raised in the main process when the `close` -event is emitted. - -To avoid this problem, ensure you clean up any references to renderer callbacks -passed to the main process. This involves cleaning up event handlers, or -ensuring the main process is explicitly told to dereference callbacks that came -from a renderer process that is exiting. - -## Accessing built-in modules in the main process - -The built-in modules in the main process are added as getters in the `remote` -module, so you can use them directly like the `electron` module. - -```javascript -const app = require('electron').remote.app -console.log(app) -``` - -## Methods - -The `remote` module has the following methods: - -### `remote.getCurrentWindow()` - -Returns [`BrowserWindow`](browser-window.md) - The window to which this web page -belongs. - -**Note:** Do not use `removeAllListeners` on [`BrowserWindow`](browser-window.md). -Use of this can remove all [`blur`](https://developer.mozilla.org/en-US/docs/Web/Events/blur) -listeners, disable click events on touch bar buttons, and other unintended -consequences. - -### `remote.getCurrentWebContents()` - -Returns [`WebContents`](web-contents.md) - The web contents of this web page. - -### `remote.getGlobal(name)` - -* `name` String - -Returns `any` - The global variable of `name` (e.g. `global[name]`) in the main -process. - -## Properties - -### `remote.require` - -A `NodeJS.Require` function equivalent to `require(module)` in the main process. -Modules specified by their relative path will resolve relative to the entrypoint -of the main process. - -e.g. - -```sh -project/ -├── main -│   ├── foo.js -│   └── index.js -├── package.json -└── renderer - └── index.js -``` - -```js -// main process: main/index.js -const { app } = require('electron') -app.whenReady().then(() => { /* ... */ }) -``` - -```js -// some relative module: main/foo.js -module.exports = 'bar' -``` - -```js -// renderer process: renderer/index.js -const foo = require('electron').remote.require('./foo') // bar -``` - -### `remote.process` _Readonly_ - -A `NodeJS.Process` object. The `process` object in the main process. This is the same as -`remote.getGlobal('process')` but is cached. - -[rmi]: https://en.wikipedia.org/wiki/Java_remote_method_invocation -[enumerable-properties]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties diff --git a/docs/api/safe-storage.md b/docs/api/safe-storage.md new file mode 100644 index 0000000000000..d2aa4cee93ff1 --- /dev/null +++ b/docs/api/safe-storage.md @@ -0,0 +1,124 @@ +# safeStorage + +> Allows access to simple encryption and decryption of strings for storage on the local machine. + +Process: [Main](../glossary.md#main-process) + +This module adds extra protection to data being stored on disk by using OS-provided cryptography systems. Current +security semantics for each platform are outlined below. + +> [!NOTE] +> We recommend using the asynchronous API (`encryptStringAsync`/`decryptStringAsync`) over the synchronous API. +> The async API is non-blocking, supports key rotation, and handles temporary unavailability gracefully. +> The synchronous API may be deprecated in a future version of Electron. + +## Platform-Specific Key Providers + +### Synchronous API + +* **macOS**: Encryption keys are stored for your app in [Keychain Access](https://support.apple.com/en-ca/guide/keychain-access/kyca1083/mac) in a way that prevents +other applications from loading them without user override. Therefore, content is protected from other users and other apps running in the same userspace. +* **Windows**: Encryption keys are generated via [DPAPI](https://learn.microsoft.com/en-us/windows/win32/api/dpapi/nf-dpapi-cryptprotectdata). As per the Windows documentation: "Typically, only a user with the same logon credential as the user who encrypted the data can typically decrypt the data". Therefore, content is protected from other users on the same machine, but not from other apps running in the +same userspace. +* **Linux**: Encryption keys are generated and stored in a secret store that varies depending on your window manager and system setup. Options currently supported are `kwallet`, `kwallet5`, `kwallet6` and `gnome-libsecret`, but more may be available in future versions of Electron. As such, the +security semantics of content protected via the `safeStorage` API vary between window managers and secret stores. + * Note that not all Linux setups have an available secret store. If no secret store is available, items stored in using the `safeStorage` API will be unprotected as they are encrypted via hardcoded plaintext password. You can detect when this happens when `safeStorage.getSelectedStorageBackend()` returns `basic_text`. + +Note that on macOS, access to the system Keychain is required and +these calls can block the current thread to collect user input. +The same is true for Linux, if a password management tool is available. + +### Asynchronous API + +The asynchronous API uses pluggable key providers that vary by platform: + +* **macOS**: Encryption keys are stored and retrieved from [Keychain Access](https://developer.apple.com/documentation/security/keychain-items). This provides the same security model as the synchronous API, protecting content from other users and other apps running in the same userspace. +* **Windows**: Encryption keys are protected via [DPAPI](https://learn.microsoft.com/en-us/windows/win32/api/dpapi). This provides the same security model as the synchronous API, protecting content from other users on the same machine but not from other apps running in the same userspace. +* **Linux**: Multiple key providers may be available depending on the desktop environment: + * [`org.freedesktop.portal.Secret`](https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Secret.html): Uses the Portal Secret D-Bus interface to retrieve application-specific secrets. This is the preferred provider for sandboxed environments like Flatpak. + * [Secret Service API](https://specifications.freedesktop.org/secret-service/latest/): Uses the freedesktop.org Secret Service API (e.g., GNOME Keyring) for key storage. + * A fallback provider is used for environments without a secret service available. + +Unlike the synchronous API, these operations are non-blocking and support additional features like key rotation (indicated by `shouldReEncrypt`) and temporary unavailability handling (indicated by `isTemporarilyUnavailable`). + +## Events + +The `safeStorage` module emits the following events: + +## Methods + +The `safeStorage` module has the following methods: + +### `safeStorage.isEncryptionAvailable()` + +Returns `boolean` - Whether encryption is available. + +On Linux, returns true if the app has emitted the `ready` event and the secret key is available. +On MacOS, returns true if Keychain is available. +On Windows, returns true once the app has emitted the `ready` event. + +### `safeStorage.isAsyncEncryptionAvailable()` + +Returns `Promise<boolean>` - Resolves with whether encryption is available for +asynchronous safeStorage operations. + +The asynchronous encryptor is initialized lazily the first time this method, +`encryptStringAsync`, or `decryptStringAsync` is called after the app is ready. +The returned promise resolves once initialization completes. + +### `safeStorage.encryptString(plainText)` + +* `plainText` string + +Returns `Buffer` - An array of bytes representing the encrypted string. + +This function will throw an error if encryption fails. + +### `safeStorage.decryptString(encrypted)` + +* `encrypted` Buffer + +Returns `string` - the decrypted string. Decrypts the encrypted buffer +obtained with `safeStorage.encryptString` back into a string. + +### `safeStorage.encryptStringAsync(plainText)` + +* `plainText` string + +Returns `Promise<Buffer>` - An array of bytes representing the encrypted string. + +### `safeStorage.decryptStringAsync(encrypted)` + +* `encrypted` Buffer + +Returns `Promise<Object>` - Resolve with an object containing the following: + +* `shouldReEncrypt` boolean - whether data that has just been returned from the decrypt operation should be + re-encrypted, as the key has been rotated or a new key is available that provides a different security level. If `true`, you should call `decryptStringAsync` again to receive the new decrypted string. +* `result` string - the decrypted string. + +### `safeStorage.setUsePlainTextEncryption(usePlainText)` + +* `usePlainText` boolean + +This function on Linux will force the module to use an in memory password for creating +symmetric key that is used for encrypt/decrypt functions when a valid OS password +manager cannot be determined for the current active desktop environment. This function +is a no-op on Windows and MacOS. + +### `safeStorage.getSelectedStorageBackend()` _Linux_ + +Returns `string` - User friendly name of the password manager selected on Linux. + +This function will return one of the following values: + +* `basic_text` - When the desktop environment is not recognised or if the following +command line flag is provided `--password-store="basic"`. +* `gnome_libsecret` - When the desktop environment is `X-Cinnamon`, `Deepin`, `GNOME`, `Pantheon`, `XFCE`, `UKUI`, `unity` or if the following command line flag is provided `--password-store="gnome-libsecret"`. +* `kwallet` - When the desktop session is `kde4` or if the following command line flag +is provided `--password-store="kwallet"`. +* `kwallet5` - When the desktop session is `kde5` or if the following command line flag +is provided `--password-store="kwallet5"`. +* `kwallet6` - When the desktop session is `kde6` or if the following command line flag +is provided `--password-store="kwallet6"`. +* `unknown` - When the function is called before app has emitted the `ready` event. diff --git a/docs/api/sandbox-option.md b/docs/api/sandbox-option.md deleted file mode 100644 index da8b530911fdd..0000000000000 --- a/docs/api/sandbox-option.md +++ /dev/null @@ -1,182 +0,0 @@ -# `sandbox` Option - -> Create a browser window with a sandboxed renderer. With this -option enabled, the renderer must communicate via IPC to the main process in order to access node APIs. - -One of the key security features of Chromium is that all blink rendering/JavaScript -code is executed within a sandbox. This sandbox uses OS-specific features to ensure -that exploits in the renderer process cannot harm the system. - -In other words, when the sandbox is enabled, the renderers can only make changes -to the system by delegating tasks to the main process via IPC. -[Here's](https://www.chromium.org/developers/design-documents/sandbox) more -information about the sandbox. - -Since a major feature in Electron is the ability to run Node.js in the -renderer process (making it easier to develop desktop applications using web -technologies), the sandbox is disabled by electron. This is because -most Node.js APIs require system access. `require()` for example, is not -possible without file system permissions, which are not available in a sandboxed -environment. - -Usually this is not a problem for desktop applications since the code is always -trusted, but it makes Electron less secure than Chromium for displaying -untrusted web content. For applications that require more security, the -`sandbox` flag will force Electron to spawn a classic Chromium renderer that is -compatible with the sandbox. - -A sandboxed renderer doesn't have a Node.js environment running and doesn't -expose Node.js JavaScript APIs to client code. The only exception is the preload script, -which has access to a subset of the Electron renderer API. - -Another difference is that sandboxed renderers don't modify any of the default -JavaScript APIs. Consequently, some APIs such as `window.open` will work as they -do in Chromium (i.e. they do not return a [`BrowserWindowProxy`](browser-window-proxy.md)). - -## Example - -To create a sandboxed window, pass `sandbox: true` to `webPreferences`: - -```js -let win -app.whenReady().then(() => { - win = new BrowserWindow({ - webPreferences: { - sandbox: true - } - }) - win.loadURL('http://google.com') -}) -``` - -In the above code the [`BrowserWindow`](browser-window.md) that was created has Node.js disabled and can communicate -only via IPC. The use of this option stops Electron from creating a Node.js runtime in the renderer. Also, -within this new window `window.open` follows the native behavior (by default Electron creates a [`BrowserWindow`](browser-window.md) -and returns a proxy to this via `window.open`). - -[`app.enableSandbox`](app.md#appenablesandbox) can be used to force `sandbox: true` for all `BrowserWindow` instances. - -```js -let win -app.enableSandbox() -app.whenReady().then(() => { - // no need to pass `sandbox: true` since `app.enableSandbox()` was called. - win = new BrowserWindow() - win.loadURL('http://google.com') -}) -``` - -## Preload - -An app can make customizations to sandboxed renderers using a preload script. -Here's an example: - -```js -let win -app.whenReady().then(() => { - win = new BrowserWindow({ - webPreferences: { - sandbox: true, - preload: path.join(app.getAppPath(), 'preload.js') - } - }) - win.loadURL('http://google.com') -}) -``` - -and preload.js: - -```js -// This file is loaded whenever a javascript context is created. It runs in a -// private scope that can access a subset of Electron renderer APIs. Without -// contextIsolation enabled, it's possible to accidentally leak privileged -// globals like ipcRenderer to web content. -const { ipcRenderer } = require('electron') - -const defaultWindowOpen = window.open - -window.open = function customWindowOpen (url, ...args) { - ipcRenderer.send('report-window-open', location.origin, url, args) - return defaultWindowOpen(url + '?from_electron=1', ...args) -} -``` - -Important things to notice in the preload script: - -- Even though the sandboxed renderer doesn't have Node.js running, it still has - access to a limited node-like environment: `Buffer`, `process`, `setImmediate`, - `clearImmediate` and `require` are available. -- The preload script must be contained in a single script, but it is possible to have - complex preload code composed with multiple modules by using a tool like - webpack or browserify. An example of using browserify is below. - -To create a browserify bundle and use it as a preload script, something like -the following should be used: - -```sh - browserify preload/index.js \ - -x electron \ - --insert-global-vars=__filename,__dirname -o preload.js -``` - -The `-x` flag should be used with any required module that is already exposed in -the preload scope, and tells browserify to use the enclosing `require` function -for it. `--insert-global-vars` will ensure that `process`, `Buffer` and -`setImmediate` are also taken from the enclosing scope(normally browserify -injects code for those). - -Currently the `require` function provided in the preload scope exposes the -following modules: - -- `electron` - - `crashReporter` - - `desktopCapturer` - - `ipcRenderer` - - `nativeImage` - - `webFrame` -- `events` -- `timers` -- `url` - -More may be added as needed to expose more Electron APIs in the sandbox. - -## Rendering untrusted content - -Rendering untrusted content in Electron is still somewhat uncharted territory, -though some apps are finding success (e.g. Beaker Browser). Our goal is to get -as close to Chrome as we can in terms of the security of sandboxed content, but -ultimately we will always be behind due to a few fundamental issues: - -1. We do not have the dedicated resources or expertise that Chromium has to - apply to the security of its product. We do our best to make use of what we - have, to inherit everything we can from Chromium, and to respond quickly to - security issues, but Electron cannot be as secure as Chromium without the - resources that Chromium is able to dedicate. -2. Some security features in Chrome (such as Safe Browsing and Certificate - Transparency) require a centralized authority and dedicated servers, both of - which run counter to the goals of the Electron project. As such, we disable - those features in Electron, at the cost of the associated security they - would otherwise bring. -3. There is only one Chromium, whereas there are many thousands of apps built - on Electron, all of which behave slightly differently. Accounting for those - differences can yield a huge possibility space, and make it challenging to - ensure the security of the platform in unusual use cases. -4. We can't push security updates to users directly, so we rely on app vendors - to upgrade the version of Electron underlying their app in order for - security updates to reach users. - -Here are some things to consider before rendering untrusted content: - -- A preload script can accidentally leak privileged APIs to untrusted code, - unless [`contextIsolation`](../tutorial/security.md#3-enable-context-isolation-for-remote-content) - is also enabled. -- Some bug in the V8 engine may allow malicious code to access the renderer - preload APIs, effectively granting full access to the system through the - `remote` module. Therefore, it is highly recommended to [disable the `remote` - module](../tutorial/security.md#15-disable-the-remote-module). - If disabling is not feasible, you should selectively [filter the `remote` - module](../tutorial/security.md#16-filter-the-remote-module). -- While we make our best effort to backport Chromium security fixes to older - versions of Electron, we do not make a guarantee that every fix will be - backported. Your best chance at staying secure is to be on the latest stable - version of Electron. diff --git a/docs/api/screen.md b/docs/api/screen.md index b0c2dfb74c1f2..d3411069af2fd 100644 --- a/docs/api/screen.md +++ b/docs/api/screen.md @@ -9,25 +9,35 @@ module is emitted. `screen` is an [EventEmitter][event-emitter]. -**Note:** In the renderer / DevTools, `window.screen` is a reserved DOM -property, so writing `let { screen } = require('electron')` will not work. +> [!NOTE] +> In the renderer / DevTools, `window.screen` is a reserved DOM +> property, so writing `let { screen } = require('electron')` will not work. An example of creating a window that fills the whole screen: -```javascript fiddle='docs/fiddles/screen/fit-screen' -const { app, BrowserWindow, screen } = require('electron') +```fiddle docs/fiddles/screen/fit-screen +// Retrieve information about screen size, displays, cursor position, etc. +// +// For more info, see: +// https://www.electronjs.org/docs/latest/api/screen + +const { app, BrowserWindow, screen } = require('electron/main') + +let mainWindow = null -let win app.whenReady().then(() => { - const { width, height } = screen.getPrimaryDisplay().workAreaSize - win = new BrowserWindow({ width, height }) - win.loadURL('https://github.com') + // Create a window that fills the screen's available work area. + const primaryDisplay = screen.getPrimaryDisplay() + const { width, height } = primaryDisplay.workAreaSize + + mainWindow = new BrowserWindow({ width, height }) + mainWindow.loadURL('https://electronjs.org') }) ``` Another example of creating a window in the external display: -```javascript +```js const { app, BrowserWindow, screen } = require('electron') let win @@ -48,6 +58,14 @@ app.whenReady().then(() => { }) ``` +> [!NOTE] +> Screen coordinates used by this module are [`Point`](structures/point.md) structures. +> There are two kinds of coordinates available to the process: +> +> * **Physical screen points** are raw hardware pixels on a display. +> * **Device-independent pixel (DIP) points** are virtualized screen points scaled based on the DPI +> (dots per inch) of the display. + ## Events The `screen` module emits the following events: @@ -76,7 +94,7 @@ Returns: * `event` Event * `display` [Display](structures/display.md) -* `changedMetrics` String[] +* `changedMetrics` string[] Emitted when one or more metrics change in a `display`. The `changedMetrics` is an array of strings that describe the changes. Possible changes are `bounds`, @@ -92,6 +110,11 @@ Returns [`Point`](structures/point.md) The current absolute position of the mouse pointer. +Not supported on Wayland (Linux). + +> [!NOTE] +> The return value is a DIP point, not a screen physical point. + ### `screen.getPrimaryDisplay()` Returns [`Display`](structures/display.md) - The primary display. @@ -113,7 +136,7 @@ Returns [`Display`](structures/display.md) - The display nearest the specified p Returns [`Display`](structures/display.md) - The display that most closely intersects the provided bounds. -### `screen.screenToDipPoint(point)` _Windows_ +### `screen.screenToDipPoint(point)` _Windows_ _Linux_ * `point` [Point](structures/point.md) @@ -122,7 +145,10 @@ Returns [`Point`](structures/point.md) Converts a screen physical point to a screen DIP point. The DPI scale is performed relative to the display containing the physical point. -### `screen.dipToScreenPoint(point)` _Windows_ +Not currently supported on Wayland - if used there it will return the point passed +in with no changes. + +### `screen.dipToScreenPoint(point)` _Windows_ _Linux_ * `point` [Point](structures/point.md) @@ -131,6 +157,8 @@ Returns [`Point`](structures/point.md) Converts a screen DIP point to a screen physical point. The DPI scale is performed relative to the display containing the DIP point. +Not currently supported on Wayland. + ### `screen.screenToDipRect(window, rect)` _Windows_ * `window` [BrowserWindow](browser-window.md) | null diff --git a/docs/api/service-worker-main.md b/docs/api/service-worker-main.md new file mode 100644 index 0000000000000..d51d65c9e351c --- /dev/null +++ b/docs/api/service-worker-main.md @@ -0,0 +1,54 @@ +## Class: ServiceWorkerMain + +> An instance of a Service Worker representing a version of a script for a given scope. + +Process: [Main](../glossary.md#main-process)<br /> +_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ + +### Instance Methods + +#### `serviceWorker.isDestroyed()` _Experimental_ + +Returns `boolean` - Whether the service worker has been destroyed. + +#### `serviceWorker.send(channel, ...args)` _Experimental_ + +- `channel` string +- `...args` any[] + +Send an asynchronous message to the service worker process via `channel`, along with +arguments. Arguments will be serialized with the [Structured Clone Algorithm][SCA], +just like [`postMessage`][], so prototype chains will not be included. +Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an exception. + +The service worker process can handle the message by listening to `channel` with the +[`ipcRenderer`](ipc-renderer.md) module. + +#### `serviceWorker.startTask()` _Experimental_ + +Returns `Object`: + +- `end` Function - Method to call when the task has ended. If never called, the service won't terminate while otherwise idle. + +Initiate a task to keep the service worker alive until ended. + +### Instance Properties + +#### `serviceWorker.ipc` _Readonly_ _Experimental_ + +An [`IpcMainServiceWorker`](ipc-main-service-worker.md) instance scoped to the service worker. + +#### `serviceWorker.scope` _Readonly_ _Experimental_ + +A `string` representing the scope URL of the service worker. + +#### `serviceWorker.scriptURL` _Readonly_ _Experimental_ + +A `string` representing the script URL of the service worker. + +#### `serviceWorker.versionId` _Readonly_ _Experimental_ + +A `number` representing the ID of the specific version of the service worker script in its scope. + +[SCA]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm +[`postMessage`]: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage diff --git a/docs/api/service-workers.md b/docs/api/service-workers.md index b3d9351200a0b..2132368b80779 100644 --- a/docs/api/service-workers.md +++ b/docs/api/service-workers.md @@ -2,14 +2,15 @@ > Query and receive events from a sessions active service workers. -Process: [Main](../glossary.md#main-process) +Process: [Main](../glossary.md#main-process)<br /> +_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ Instances of the `ServiceWorkers` class are accessed by using `serviceWorkers` property of a `Session`. For example: -```javascript +```js const { session } = require('electron') // Get all service workers. @@ -36,27 +37,94 @@ Returns: * `event` Event * `messageDetails` Object - Information about the console message - * `message` String - The actual console message - * `versionId` Number - The version ID of the service worker that sent the log message - * `source` String - The type of source for this message. Can be `javascript`, `xml`, `network`, `console-api`, `storage`, `app-cache`, `rendering`, `security`, `deprecation`, `worker`, `violation`, `intervention`, `recommendation` or `other`. - * `level` Number - The log level, from 0 to 3. In order it matches `verbose`, `info`, `warning` and `error`. - * `sourceUrl` String - The URL the message came from - * `lineNumber` Number - The line number of the source that triggered this console message + * `message` string - The actual console message + * `versionId` number - The version ID of the service worker that sent the log message + * `source` string - The type of source for this message. Can be `javascript`, `xml`, `network`, `console-api`, `storage`, `rendering`, `security`, `deprecation`, `worker`, `violation`, `intervention`, `recommendation` or `other`. + * `level` number - The log level, from 0 to 3. In order it matches `verbose`, `info`, `warning` and `error`. + * `sourceUrl` string - The URL the message came from + * `lineNumber` number - The line number of the source that triggered this console message Emitted when a service worker logs something to the console. +#### Event: 'registration-completed' + +Returns: + +* `event` Event +* `details` Object - Information about the registered service worker + * `scope` string - The base URL that a service worker is registered for + +Emitted when a service worker has been registered. Can occur after a call to [`navigator.serviceWorker.register('/sw.js')`](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/register) successfully resolves or when a Chrome extension is loaded. + +#### Event: 'running-status-changed' _Experimental_ + +Returns: + +* `details` Event\<\> + * `versionId` number - ID of the updated service worker version + * `runningStatus` string - Running status. + Possible values include `starting`, `running`, `stopping`, or `stopped`. + +Emitted when a service worker's running status has changed. + ### Instance Methods The following methods are available on instances of `ServiceWorkers`: #### `serviceWorkers.getAllRunning()` -Returns `Record<Number, ServiceWorkerInfo>` - A [ServiceWorkerInfo](structures/service-worker-info.md) object where the keys are the service worker version ID and the values are the information about that service worker. +Returns `Record<number, ServiceWorkerInfo>` - A [ServiceWorkerInfo](structures/service-worker-info.md) object where the keys are the service worker version ID and the values are the information about that service worker. -#### `serviceWorkers.getFromVersionID(versionId)` +#### `serviceWorkers.getInfoFromVersionID(versionId)` -* `versionId` Number +* `versionId` number - ID of the service worker version Returns [`ServiceWorkerInfo`](structures/service-worker-info.md) - Information about this service worker If the service worker does not exist or is not running this method will throw an exception. + +#### `serviceWorkers.getFromVersionID(versionId)` _Deprecated_ + +* `versionId` number - ID of the service worker version + +Returns [`ServiceWorkerInfo`](structures/service-worker-info.md) - Information about this service worker + +If the service worker does not exist or is not running this method will throw an exception. + +**Deprecated:** Use the new `serviceWorkers.getInfoFromVersionID` API. + +#### `serviceWorkers.getWorkerFromVersionID(versionId)` _Experimental_ + +* `versionId` number - ID of the service worker version + +Returns [`ServiceWorkerMain | undefined`](service-worker-main.md) - Instance of the service worker associated with the given version ID. If there's no associated version, or its running status has changed to 'stopped', this will return `undefined`. + +#### `serviceWorkers.startWorkerForScope(scope)` _Experimental_ + +* `scope` string - The scope of the service worker to start. + +Returns `Promise<ServiceWorkerMain>` - Resolves with the service worker when it's started. + +Starts the service worker or does nothing if already running. + +```js +const { app, session } = require('electron') + +const { serviceWorkers } = session.defaultSession + +// Collect service workers scopes +const workerScopes = Object.values(serviceWorkers.getAllRunning()).map((info) => info.scope) + +app.on('browser-window-created', async (event, window) => { + for (const scope of workerScopes) { + try { + // Ensure worker is started + const serviceWorker = await serviceWorkers.startWorkerForScope(scope) + serviceWorker.send('window-created', { windowId: window.id }) + } catch (error) { + console.error(`Failed to start service worker for ${scope}`) + console.error(error) + } + } +}) +``` diff --git a/docs/api/session.md b/docs/api/session.md index 5db617e9ba049..e7279604f3b66 100644 --- a/docs/api/session.md +++ b/docs/api/session.md @@ -9,11 +9,11 @@ The `session` module can be used to create new `Session` objects. You can also access the `session` of existing pages by using the `session` property of [`WebContents`](web-contents.md), or from the `session` module. -```javascript +```js const { BrowserWindow } = require('electron') const win = new BrowserWindow({ width: 800, height: 600 }) -win.loadURL('http://github.com') +win.loadURL('https://github.com') const ses = win.webContents.session console.log(ses.getUserAgent()) @@ -25,9 +25,10 @@ The `session` module has the following methods: ### `session.fromPartition(partition[, options])` -* `partition` String +* `partition` string * `options` Object (optional) - * `cache` Boolean - Whether to enable cache. + * `cache` boolean - Whether to enable cache. Default is `true` unless the + [`--disable-http-cache` switch](command-line-switches.md#--disable-http-cache) is used. Returns `Session` - A session instance from `partition` string. When there is an existing `Session` with the same `partition`, it will be returned; otherwise a new @@ -42,24 +43,43 @@ To create a `Session` with `options`, you have to ensure the `Session` with the `partition` has never been used before. There is no way to change the `options` of an existing `Session` object. +### `session.fromPath(path[, options])` + +* `path` string +* `options` Object (optional) + * `cache` boolean - Whether to enable cache. Default is `true` unless the + [`--disable-http-cache` switch](command-line-switches.md#--disable-http-cache) is used. + +Returns `Session` - A session instance from the absolute path as specified by the `path` +string. When there is an existing `Session` with the same absolute path, it +will be returned; otherwise a new `Session` instance will be created with `options`. The +call will throw an error if the path is not an absolute path. Additionally, an error will +be thrown if an empty string is provided. + +To create a `Session` with `options`, you have to ensure the `Session` with the +`path` has never been used before. There is no way to change the `options` +of an existing `Session` object. + ## Properties The `session` module has the following properties: ### `session.defaultSession` -A `Session` object, the default session object of the app. +A `Session` object, the default session object of the app, available after `app.whenReady` is called. ## Class: Session > Get and set properties of a session. -Process: [Main](../glossary.md#main-process) +Process: [Main](../glossary.md#main-process)<br /> +_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ You can create a `Session` object in the `session` module: -```javascript +```js const { session } = require('electron') + const ses = session.fromPartition('persist:name') console.log(ses.getUserAgent()) ``` @@ -81,12 +101,13 @@ Emitted when Electron is about to download `item` in `webContents`. Calling `event.preventDefault()` will cancel the download and `item` will not be available from next tick of the process. -```javascript +```js @ts-expect-error=[5] const { session } = require('electron') + session.defaultSession.on('will-download', (event, item, webContents) => { event.preventDefault() - require('request')(item.getURL(), (data) => { - require('fs').writeFileSync('/somewhere', data) + require('got')(item.getURL()).then((response) => { + require('node:fs').writeFileSync('/somewhere', response.body) }) }) ``` @@ -101,8 +122,8 @@ Returns: Emitted after an extension is loaded. This occurs whenever an extension is added to the "enabled" set of extensions. This includes: -- Extensions being loaded from `Session.loadExtension`. -- Extensions being reloaded: +* Extensions being loaded from `Session.loadExtension`. +* Extensions being reloaded: * from a crash. * if the extension requested it ([`chrome.runtime.reload()`](https://developer.chrome.com/extensions/runtime#method-reload)). @@ -126,14 +147,79 @@ Returns: Emitted after an extension is loaded and all necessary browser state is initialized to support the start of the extension's background page. +#### Event: 'file-system-access-restricted' + +Returns: + +* `event` Event +* `details` Object + * `origin` string - The origin that initiated access to the blocked path. + * `isDirectory` boolean - Whether or not the path is a directory. + * `path` string - The blocked path attempting to be accessed. +* `callback` Function + * `action` string - The action to take as a result of the restricted path access attempt. + * `allow` - This will allow `path` to be accessed despite restricted status. + * `deny` - This will block the access request and trigger an [`AbortError`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController/abort). + * `tryAgain` - This will open a new file picker and allow the user to choose another path. + +```js +const { app, dialog, BrowserWindow, session } = require('electron') + +async function createWindow () { + const mainWindow = new BrowserWindow() + + await mainWindow.loadURL('https://buzzfeed.com') + + session.defaultSession.on('file-system-access-restricted', async (e, details, callback) => { + const { origin, path } = details + const { response } = await dialog.showMessageBox({ + message: `Are you sure you want ${origin} to open restricted path ${path}?`, + title: 'File System Access Restricted', + buttons: ['Choose a different folder', 'Allow', 'Cancel'], + cancelId: 2 + }) + + if (response === 0) { + callback('tryAgain') + } else if (response === 1) { + callback('allow') + } else { + callback('deny') + } + }) + + mainWindow.webContents.executeJavaScript(` + window.showDirectoryPicker({ + id: 'electron-demo', + mode: 'readwrite', + startIn: 'downloads', + }).catch(e => { + console.log(e) + })`, true + ) +} + +app.whenReady().then(() => { + createWindow() + + app.on('activate', () => { + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) +}) + +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit() +}) +``` + #### Event: 'preconnect' Returns: * `event` Event -* `preconnectUrl` String - The URL being requested for preconnection by the +* `preconnectUrl` string - The URL being requested for preconnection by the renderer. -* `allowCredentials` Boolean - True if the renderer is requesting that the +* `allowCredentials` boolean - True if the renderer is requesting that the connection include credentials (see the [spec](https://w3c.github.io/resource-hints/#preconnect) for more details.) @@ -145,7 +231,7 @@ a [resource hint](https://w3c.github.io/resource-hints/). Returns: * `event` Event -* `languageCode` String - The language code of the dictionary file +* `languageCode` string - The language code of the dictionary file Emitted when a hunspell dictionary file has been successfully initialized. This occurs after the file has been downloaded. @@ -155,7 +241,7 @@ occurs after the file has been downloaded. Returns: * `event` Event -* `languageCode` String - The language code of the dictionary file +* `languageCode` string - The language code of the dictionary file Emitted when a hunspell dictionary file starts downloading @@ -164,7 +250,7 @@ Emitted when a hunspell dictionary file starts downloading Returns: * `event` Event -* `languageCode` String - The language code of the dictionary file +* `languageCode` string - The language code of the dictionary file Emitted when a hunspell dictionary file has been successfully downloaded @@ -173,13 +259,123 @@ Emitted when a hunspell dictionary file has been successfully downloaded Returns: * `event` Event -* `languageCode` String - The language code of the dictionary file +* `languageCode` string - The language code of the dictionary file Emitted when a hunspell dictionary file download fails. For details on the failure you should collect a netlog and inspect the download request. -#### Event: 'select-serial-port' _Experimental_ +#### Event: 'select-hid-device' + +Returns: + +* `event` Event +* `details` Object + * `deviceList` [HIDDevice[]](structures/hid-device.md) + * `frame` [WebFrameMain](web-frame-main.md) | null - The frame initiating this event. + May be `null` if accessed after the frame has either navigated or been destroyed. +* `callback` Function + * `deviceId` string | null (optional) + +Emitted when a HID device needs to be selected when a call to +`navigator.hid.requestDevice` is made. `callback` should be called with +`deviceId` to be selected; passing no arguments to `callback` will +cancel the request. Additionally, permissioning on `navigator.hid` can +be further managed by using [`ses.setPermissionCheckHandler(handler)`](#sessetpermissioncheckhandlerhandler) +and [`ses.setDevicePermissionHandler(handler)`](#sessetdevicepermissionhandlerhandler). + +```js @ts-type={fetchGrantedDevices:()=>(Array<Electron.DevicePermissionHandlerHandlerDetails['device']>)} +const { app, BrowserWindow } = require('electron') + +let win = null + +app.whenReady().then(() => { + win = new BrowserWindow() + + win.webContents.session.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => { + if (permission === 'hid') { + // Add logic here to determine if permission should be given to allow HID selection + return true + } + return false + }) + + // Optionally, retrieve previously persisted devices from a persistent store + const grantedDevices = fetchGrantedDevices() + + win.webContents.session.setDevicePermissionHandler((details) => { + if (new URL(details.origin).hostname === 'some-host' && details.deviceType === 'hid') { + if (details.device.vendorId === 123 && details.device.productId === 345) { + // Always allow this type of device (this allows skipping the call to `navigator.hid.requestDevice` first) + return true + } + + // Search through the list of devices that have previously been granted permission + return grantedDevices.some((grantedDevice) => { + return grantedDevice.vendorId === details.device.vendorId && + grantedDevice.productId === details.device.productId && + grantedDevice.serialNumber && grantedDevice.serialNumber === details.device.serialNumber + }) + } + return false + }) + + win.webContents.session.on('select-hid-device', (event, details, callback) => { + event.preventDefault() + const selectedDevice = details.deviceList.find((device) => { + return device.vendorId === 9025 && device.productId === 67 + }) + callback(selectedDevice?.deviceId) + }) +}) +``` + +#### Event: 'hid-device-added' + +Returns: + +* `event` Event +* `details` Object + * `device` [HIDDevice](structures/hid-device.md) + * `frame` [WebFrameMain](web-frame-main.md) | null - The frame initiating this event. + May be `null` if accessed after the frame has either navigated or been destroyed. + +Emitted after `navigator.hid.requestDevice` has been called and +`select-hid-device` has fired if a new device becomes available before +the callback from `select-hid-device` is called. This event is intended for +use when using a UI to ask users to pick a device so that the UI can be updated +with the newly added device. + +#### Event: 'hid-device-removed' + +Returns: + +* `event` Event +* `details` Object + * `device` [HIDDevice](structures/hid-device.md) + * `frame` [WebFrameMain](web-frame-main.md) | null - The frame initiating this event. + May be `null` if accessed after the frame has either navigated or been destroyed. + +Emitted after `navigator.hid.requestDevice` has been called and +`select-hid-device` has fired if a device has been removed before the callback +from `select-hid-device` is called. This event is intended for use when using +a UI to ask users to pick a device so that the UI can be updated to remove the +specified device. + +#### Event: 'hid-device-revoked' + +Returns: + +* `event` Event +* `details` Object + * `device` [HIDDevice](structures/hid-device.md) + * `origin` string (optional) - The origin that the device has been revoked from. + +Emitted after `HIDDevice.forget()` has been called. This event can be used +to help maintain persistent storage of permissions when +`setDevicePermissionHandler` is used. + +#### Event: 'select-serial-port' Returns: @@ -187,7 +383,7 @@ Returns: * `portList` [SerialPort[]](structures/serial-port.md) * `webContents` [WebContents](web-contents.md) * `callback` Function - * `portId` String + * `portId` string Emitted when a serial port needs to be selected when a call to `navigator.serial.requestPort` is made. `callback` should be called with @@ -196,40 +392,60 @@ cancel the request. Additionally, permissioning on `navigator.serial` can be managed by using [ses.setPermissionCheckHandler(handler)](#sessetpermissioncheckhandlerhandler) with the `serial` permission. -Because this is an experimental feature it is disabled by default. To enable this feature, you -will need to use the `--enable-features=ElectronSerialChooser` command line switch. Additionally -because this is an experimental Chromium feature you will need to set `enableBlinkFeatures: 'Serial'` -on the `webPreferences` property when opening a BrowserWindow. - -```javascript +```js @ts-type={fetchGrantedDevices:()=>(Array<Electron.DevicePermissionHandlerHandlerDetails['device']>)} const { app, BrowserWindow } = require('electron') let win = null -app.commandLine.appendSwitch('enable-features', 'ElectronSerialChooser') app.whenReady().then(() => { win = new BrowserWindow({ width: 800, - height: 600, - webPreferences: { - enableBlinkFeatures: 'Serial' + height: 600 + }) + + win.webContents.session.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => { + if (permission === 'serial') { + // Add logic here to determine if permission should be given to allow serial selection + return true } + return false }) - win.webContents.session.on('select-serial-port', (event, portList, callback) => { + + // Optionally, retrieve previously persisted devices from a persistent store + const grantedDevices = fetchGrantedDevices() + + win.webContents.session.setDevicePermissionHandler((details) => { + if (new URL(details.origin).hostname === 'some-host' && details.deviceType === 'serial') { + if (details.device.vendorId === 123 && details.device.productId === 345) { + // Always allow this type of device (this allows skipping the call to `navigator.serial.requestPort` first) + return true + } + + // Search through the list of devices that have previously been granted permission + return grantedDevices.some((grantedDevice) => { + return grantedDevice.vendorId === details.device.vendorId && + grantedDevice.productId === details.device.productId && + grantedDevice.serialNumber && grantedDevice.serialNumber === details.device.serialNumber + }) + } + return false + }) + + win.webContents.session.on('select-serial-port', (event, portList, webContents, callback) => { event.preventDefault() const selectedPort = portList.find((device) => { - return device.vendorId === 0x2341 && device.productId === 0x0043 + return device.vendorId === '9025' && device.productId === '67' }) if (!selectedPort) { callback('') } else { - callback(result1.portId) + callback(selectedPort.portId) } }) }) ``` -#### Event: 'serial-port-added' _Experimental_ +#### Event: 'serial-port-added' Returns: @@ -237,9 +453,13 @@ Returns: * `port` [SerialPort](structures/serial-port.md) * `webContents` [WebContents](web-contents.md) -Emitted after `navigator.serial.requestPort` has been called and `select-serial-port` has fired if a new serial port becomes available. For example, this event will fire when a new USB device is plugged in. +Emitted after `navigator.serial.requestPort` has been called and +`select-serial-port` has fired if a new serial port becomes available before +the callback from `select-serial-port` is called. This event is intended for +use when using a UI to ask users to pick a port so that the UI can be updated +with the newly added port. -#### Event: 'serial-port-removed' _Experimental_ +#### Event: 'serial-port-removed' Returns: @@ -247,146 +467,249 @@ Returns: * `port` [SerialPort](structures/serial-port.md) * `webContents` [WebContents](web-contents.md) -Emitted after `navigator.serial.requestPort` has been called and `select-serial-port` has fired if a serial port has been removed. For example, this event will fire when a USB device is unplugged. +Emitted after `navigator.serial.requestPort` has been called and +`select-serial-port` has fired if a serial port has been removed before the +callback from `select-serial-port` is called. This event is intended for use +when using a UI to ask users to pick a port so that the UI can be updated +to remove the specified port. -### Instance Methods +#### Event: 'serial-port-revoked' -The following methods are available on instances of `Session`: +Returns: -#### `ses.getCacheSize()` +* `event` Event +* `details` Object + * `port` [SerialPort](structures/serial-port.md) + * `frame` [WebFrameMain](web-frame-main.md) | null - The frame initiating this event. + May be `null` if accessed after the frame has either navigated or been destroyed. + * `origin` string - The origin that the device has been revoked from. -Returns `Promise<Integer>` - the session's current cache size, in bytes. +Emitted after `SerialPort.forget()` has been called. This event can be used +to help maintain persistent storage of permissions when `setDevicePermissionHandler` is used. -#### `ses.clearCache()` +```js +// Browser Process +const { app, BrowserWindow } = require('electron') -Returns `Promise<void>` - resolves when the cache clear operation is complete. +app.whenReady().then(() => { + const win = new BrowserWindow({ + width: 800, + height: 600 + }) -Clears the session’s HTTP cache. + win.webContents.session.on('serial-port-revoked', (event, details) => { + console.log(`Access revoked for serial device from origin ${details.origin}`) + }) +}) +``` -#### `ses.clearStorageData([options])` +```js @ts-nocheck +// Renderer Process -* `options` Object (optional) - * `origin` String (optional) - Should follow `window.location.origin`’s representation - `scheme://host:port`. - * `storages` String[] (optional) - The types of storages to clear, can contain: - `appcache`, `cookies`, `filesystem`, `indexdb`, `localstorage`, - `shadercache`, `websql`, `serviceworkers`, `cachestorage`. If not - specified, clear all storage types. - * `quotas` String[] (optional) - The types of quotas to clear, can contain: - `temporary`, `persistent`, `syncable`. If not specified, clear all quotas. +const portConnect = async () => { + // Request a port. + const port = await navigator.serial.requestPort() -Returns `Promise<void>` - resolves when the storage data has been cleared. + // Wait for the serial port to open. + await port.open({ baudRate: 9600 }) -#### `ses.flushStorageData()` + // ...later, revoke access to the serial port. + await port.forget() +} +``` -Writes any unwritten DOMStorage data to disk. +#### Event: 'select-usb-device' -#### `ses.setProxy(config)` +Returns: -* `config` Object - * `mode` String (optional) - The proxy mode. Should be one of `direct`, - `auto_detect`, `pac_script`, `fixed_servers` or `system`. If it's - unspecified, it will be automatically determined based on other specified - options. - * `direct` - In direct mode all connections are created directly, without any proxy involved. - * `auto_detect` - In auto_detect mode the proxy configuration is determined by a PAC script that can - be downloaded at http://wpad/wpad.dat. - * `pac_script` - In pac_script mode the proxy configuration is determined by a PAC script that is - retrieved from the URL specified in the `pacScript`. This is the default mode - if `pacScript` is specified. - * `fixed_servers` - In fixed_servers mode the proxy configuration is specified in `proxyRules`. - This is the default mode if `proxyRules` is specified. - * `system` - In system mode the proxy configuration is taken from the operating system. - Note that the system mode is different from setting no proxy configuration. - In the latter case, Electron falls back to the system settings - only if no command-line options influence the proxy configuration. - * `pacScript` String (optional) - The URL associated with the PAC file. - * `proxyRules` String (optional) - Rules indicating which proxies to use. - * `proxyBypassRules` String (optional) - Rules indicating which URLs should - bypass the proxy settings. +* `event` Event +* `details` Object + * `deviceList` [USBDevice[]](structures/usb-device.md) + * `frame` [WebFrameMain](web-frame-main.md) | null - The frame initiating this event. + May be `null` if accessed after the frame has either navigated or been destroyed. +* `callback` Function + * `deviceId` string (optional) -Returns `Promise<void>` - Resolves when the proxy setting process is complete. +Emitted when a USB device needs to be selected when a call to +`navigator.usb.requestDevice` is made. `callback` should be called with +`deviceId` to be selected; passing no arguments to `callback` will +cancel the request. Additionally, permissioning on `navigator.usb` can +be further managed by using [`ses.setPermissionCheckHandler(handler)`](#sessetpermissioncheckhandlerhandler) +and [`ses.setDevicePermissionHandler(handler)`](#sessetdevicepermissionhandlerhandler). -Sets the proxy settings. +```js @ts-type={fetchGrantedDevices:()=>(Array<Electron.DevicePermissionHandlerHandlerDetails['device']>)} @ts-type={updateGrantedDevices:(devices:Array<Electron.DevicePermissionHandlerHandlerDetails['device']>)=>void} +const { app, BrowserWindow } = require('electron') + +let win = null -When `mode` is unspecified, `pacScript` and `proxyRules` are provided together, the `proxyRules` -option is ignored and `pacScript` configuration is applied. +app.whenReady().then(() => { + win = new BrowserWindow() -You may need `ses.closeAllConnections` to close currently in flight connections to prevent -pooled sockets using previous proxy from being reused by future requests. + win.webContents.session.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => { + if (permission === 'usb') { + // Add logic here to determine if permission should be given to allow USB selection + return true + } + return false + }) -The `proxyRules` has to follow the rules below: + // Optionally, retrieve previously persisted devices from a persistent store (fetchGrantedDevices needs to be implemented by developer to fetch persisted permissions) + const grantedDevices = fetchGrantedDevices() + + win.webContents.session.setDevicePermissionHandler((details) => { + if (new URL(details.origin).hostname === 'some-host' && details.deviceType === 'usb') { + if (details.device.vendorId === 123 && details.device.productId === 345) { + // Always allow this type of device (this allows skipping the call to `navigator.usb.requestDevice` first) + return true + } + + // Search through the list of devices that have previously been granted permission + return grantedDevices.some((grantedDevice) => { + return grantedDevice.vendorId === details.device.vendorId && + grantedDevice.productId === details.device.productId && + grantedDevice.serialNumber && grantedDevice.serialNumber === details.device.serialNumber + }) + } + return false + }) -```sh -proxyRules = schemeProxies[";"<schemeProxies>] -schemeProxies = [<urlScheme>"="]<proxyURIList> -urlScheme = "http" | "https" | "ftp" | "socks" -proxyURIList = <proxyURL>[","<proxyURIList>] -proxyURL = [<proxyScheme>"://"]<proxyHost>[":"<proxyPort>] + win.webContents.session.on('select-usb-device', (event, details, callback) => { + event.preventDefault() + const selectedDevice = details.deviceList.find((device) => { + return device.vendorId === 9025 && device.productId === 67 + }) + if (selectedDevice) { + // Optionally, add this to the persisted devices (updateGrantedDevices needs to be implemented by developer to persist permissions) + grantedDevices.push(selectedDevice) + updateGrantedDevices(grantedDevices) + } + callback(selectedDevice?.deviceId) + }) +}) ``` -For example: +#### Event: 'usb-device-added' + +Returns: + +* `event` Event +* `device` [USBDevice](structures/usb-device.md) +* `webContents` [WebContents](web-contents.md) + +Emitted after `navigator.usb.requestDevice` has been called and +`select-usb-device` has fired if a new device becomes available before +the callback from `select-usb-device` is called. This event is intended for +use when using a UI to ask users to pick a device so that the UI can be updated +with the newly added device. + +#### Event: 'usb-device-removed' + +Returns: + +* `event` Event +* `device` [USBDevice](structures/usb-device.md) +* `webContents` [WebContents](web-contents.md) + +Emitted after `navigator.usb.requestDevice` has been called and +`select-usb-device` has fired if a device has been removed before the callback +from `select-usb-device` is called. This event is intended for use when using +a UI to ask users to pick a device so that the UI can be updated to remove the +specified device. -* `http=foopy:80;ftp=foopy2` - Use HTTP proxy `foopy:80` for `http://` URLs, and - HTTP proxy `foopy2:80` for `ftp://` URLs. -* `foopy:80` - Use HTTP proxy `foopy:80` for all URLs. -* `foopy:80,bar,direct://` - Use HTTP proxy `foopy:80` for all URLs, failing - over to `bar` if `foopy:80` is unavailable, and after that using no proxy. -* `socks4://foopy` - Use SOCKS v4 proxy `foopy:1080` for all URLs. -* `http=foopy,socks5://bar.com` - Use HTTP proxy `foopy` for http URLs, and fail - over to the SOCKS5 proxy `bar.com` if `foopy` is unavailable. -* `http=foopy,direct://` - Use HTTP proxy `foopy` for http URLs, and use no - proxy if `foopy` is unavailable. -* `http=foopy;socks=foopy2` - Use HTTP proxy `foopy` for http URLs, and use - `socks4://foopy2` for all other URLs. +#### Event: 'usb-device-revoked' -The `proxyBypassRules` is a comma separated list of rules described below: +Returns: + +* `event` Event +* `details` Object + * `device` [USBDevice](structures/usb-device.md) + * `origin` string (optional) - The origin that the device has been revoked from. -* `[ URL_SCHEME "://" ] HOSTNAME_PATTERN [ ":" <port> ]` +Emitted after `USBDevice.forget()` has been called. This event can be used +to help maintain persistent storage of permissions when +`setDevicePermissionHandler` is used. - Match all hostnames that match the pattern HOSTNAME_PATTERN. +### Instance Methods - Examples: - "foobar.com", "*foobar.com", "*.foobar.com", "*foobar.com:99", - "https://x.*.y.com:99" +The following methods are available on instances of `Session`: -* `"." HOSTNAME_SUFFIX_PATTERN [ ":" PORT ]` +#### `ses.getCacheSize()` - Match a particular domain suffix. +Returns `Promise<Integer>` - the session's current cache size, in bytes. + +#### `ses.clearCache()` + +Returns `Promise<void>` - resolves when the cache clear operation is complete. + +Clears the session’s HTTP cache. + +#### `ses.clearStorageData([options])` + +* `options` Object (optional) + * `origin` string (optional) - Should follow `window.location.origin`’s representation + `scheme://host:port`. + * `storages` string[] (optional) - The types of storages to clear, can be + `cookies`, `filesystem`, `indexdb`, `localstorage`, + `shadercache`, `serviceworkers`, `cachestorage`. If not + specified, clear all storage types. + +Returns `Promise<void>` - resolves when the storage data has been cleared. - Examples: - ".google.com", ".com", "http://.google.com" +#### `ses.flushStorageData()` -* `[ SCHEME "://" ] IP_LITERAL [ ":" PORT ]` +Writes any unwritten DOMStorage data to disk. - Match URLs which are IP address literals. +#### `ses.setProxy(config)` - Examples: - "127.0.1", "[0:0::1]", "[::1]", "http://[::1]:99" +* `config` [ProxyConfig](structures/proxy-config.md) -* `IP_LITERAL "/" PREFIX_LENGTH_IN_BITS` +Returns `Promise<void>` - Resolves when the proxy setting process is complete. - Match any URL that is to an IP literal that falls between the - given range. IP range is specified using CIDR notation. +Sets the proxy settings. - Examples: - "192.168.1.1/16", "fefe:13::abc/33". +You may need `ses.closeAllConnections` to close currently in flight connections to prevent +pooled sockets using previous proxy from being reused by future requests. -* `<local>` +#### `ses.resolveHost(host, [options])` - Match local addresses. The meaning of `<local>` is whether the - host matches one of: "127.0.0.1", "::1", "localhost". +* `host` string - Hostname to resolve. +* `options` Object (optional) + * `queryType` string (optional) - Requested DNS query type. If unspecified, + resolver will pick A or AAAA (or both) based on IPv4/IPv6 settings: + * `A` - Fetch only A records + * `AAAA` - Fetch only AAAA records. + * `source` string (optional) - The source to use for resolved addresses. + Default allows the resolver to pick an appropriate source. Only affects use + of big external sources (e.g. calling the system for resolution or using + DNS). Even if a source is specified, results can still come from cache, + resolving "localhost" or IP literals, etc. One of the following values: + * `any` (default) - Resolver will pick an appropriate source. Results could + come from DNS, MulticastDNS, HOSTS file, etc + * `system` - Results will only be retrieved from the system or OS, e.g. via + the `getaddrinfo()` system call + * `dns` - Results will only come from DNS queries + * `mdns` - Results will only come from Multicast DNS queries + * `localOnly` - No external sources will be used. Results will only come + from fast local sources that are available no matter the source setting, + e.g. cache, hosts file, IP literal resolution, etc. + * `cacheUsage` string (optional) - Indicates what DNS cache entries, if any, + can be used to provide a response. One of the following values: + * `allowed` (default) - Results may come from the host cache if non-stale + * `staleAllowed` - Results may come from the host cache even if stale (by + expiration or network changes) + * `disallowed` - Results will not come from the host cache. + * `secureDnsPolicy` string (optional) - Controls the resolver's Secure DNS + behavior for this request. One of the following values: + * `allow` (default) + * `disable` + +Returns [`Promise<ResolvedHost>`](structures/resolved-host.md) - Resolves with the resolved IP addresses for the `host`. #### `ses.resolveProxy(url)` * `url` URL -Returns `Promise<String>` - Resolves with the proxy information for `url`. +Returns `Promise<string>` - Resolves with the proxy information for `url`. #### `ses.forceReloadProxyConfig()` @@ -394,7 +717,7 @@ Returns `Promise<void>` - Resolves when the all internal states of proxy service #### `ses.setDownloadPath(path)` -* `path` String - The download location. +* `path` string - The download location. Sets download saving directory. By default, the download directory will be the `Downloads` under the respective app folder. @@ -402,7 +725,7 @@ Sets download saving directory. By default, the download directory will be the #### `ses.enableNetworkEmulation(options)` * `options` Object - * `offline` Boolean (optional) - Whether to emulate network outage. Defaults + * `offline` boolean (optional) - Whether to emulate network outage. Defaults to false. * `latency` Double (optional) - RTT in ms. Defaults to 0 which will disable latency throttling. @@ -413,23 +736,25 @@ Sets download saving directory. By default, the download directory will be the Emulates network with the given configuration for the `session`. -```javascript +```js +const win = new BrowserWindow() + // To emulate a GPRS connection with 50kbps throughput and 500 ms latency. -window.webContents.session.enableNetworkEmulation({ +win.webContents.session.enableNetworkEmulation({ latency: 500, downloadThroughput: 6400, uploadThroughput: 6400 }) // To emulate a network outage. -window.webContents.session.enableNetworkEmulation({ offline: true }) +win.webContents.session.enableNetworkEmulation({ offline: true }) ``` #### `ses.preconnect(options)` * `options` Object - * `url` String - URL for preconnect. Only the origin is relevant for opening the socket. - * `numSockets` Number (optional) - number of sockets to preconnect. Must be between 1 and 6. Defaults to 1. + * `url` string - URL for preconnect. Only the origin is relevant for opening the socket. + * `numSockets` number (optional) - number of sockets to preconnect. Must be between 1 and 6. Defaults to 1. Preconnects the given number of sockets to an origin. @@ -437,7 +762,62 @@ Preconnects the given number of sockets to an origin. Returns `Promise<void>` - Resolves when all connections are closed. -**Note:** It will terminate / fail all requests currently in flight. +> [!NOTE] +> It will terminate / fail all requests currently in flight. + +#### `ses.fetch(input[, init])` + +* `input` string | [GlobalRequest](https://nodejs.org/api/globals.html#request) +* `init` [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/fetch#options) & \{ bypassCustomProtocolHandlers?: boolean \} (optional) + +Returns `Promise<GlobalResponse>` - see [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response). + +Sends a request, similarly to how `fetch()` works in the renderer, using +Chrome's network stack. This differs from Node's `fetch()`, which uses +Node.js's HTTP stack. + +Example: + +```js +async function example () { + const response = await net.fetch('https://my.app') + if (response.ok) { + const body = await response.json() + // ... use the result. + } +} +``` + +See also [`net.fetch()`](net.md#netfetchinput-init), a convenience method which +issues requests from the [default session](#sessiondefaultsession). + +See the MDN documentation for +[`fetch()`](https://developer.mozilla.org/en-US/docs/Web/API/fetch) for more +details. + +Limitations: + +* `net.fetch()` does not support the `data:` or `blob:` schemes. +* The value of the `integrity` option is ignored. +* The `.type` and `.url` values of the returned `Response` object are + incorrect. + +By default, requests made with `net.fetch` can be made to [custom protocols](protocol.md) +as well as `file:`, and will trigger [webRequest](web-request.md) handlers if present. +When the non-standard `bypassCustomProtocolHandlers` option is set in RequestInit, +custom protocol handlers will not be called for this request. This allows forwarding an +intercepted request to the built-in handler. [webRequest](web-request.md) +handlers will still be triggered when bypassing custom protocols. + +```js +protocol.handle('https', (req) => { + if (req.url === 'https://my-app.com') { + return new Response('<body>my app</body>') + } else { + return net.fetch(req, { bypassCustomProtocolHandlers: true }) + } +}) +``` #### `ses.disableNetworkEmulation()` @@ -448,14 +828,15 @@ the original network configuration. * `proc` Function | null * `request` Object - * `hostname` String + * `hostname` string * `certificate` [Certificate](structures/certificate.md) * `validatedCertificate` [Certificate](structures/certificate.md) - * `verificationResult` String - Verification result from chromium. + * `isIssuedByKnownRoot` boolean - `true` if Chromium recognises the root CA as a standard root. If it isn't then it's probably the case that this certificate was generated by a MITM proxy whose root has been installed locally (for example, by a corporate proxy). This should not be trusted if the `verificationResult` is not `OK`. + * `verificationResult` string - `OK` if the certificate is trusted, otherwise an error like `CERT_REVOKED`. * `errorCode` Integer - Error code. * `callback` Function * `verificationResult` Integer - Value can be one of certificate error codes - from [here](https://source.chromium.org/chromium/chromium/src/+/master:net/base/net_error_list.h). + from [here](https://source.chromium.org/chromium/chromium/src/+/main:net/base/net_error_list.h). Apart from the certificate error codes, the following special codes can be used. * `0` - Indicates success and disables Certificate Transparency verification. * `-2` - Indicates failure. @@ -469,8 +850,9 @@ calling `callback(-2)` rejects it. Calling `setCertificateVerifyProc(null)` will revert back to default certificate verify proc. -```javascript +```js const { BrowserWindow } = require('electron') + const win = new BrowserWindow() win.webContents.session.setCertificateVerifyProc((request, callback) => { @@ -489,32 +871,40 @@ win.webContents.session.setCertificateVerifyProc((request, callback) => { * `handler` Function | null * `webContents` [WebContents](web-contents.md) - WebContents requesting the permission. Please note that if the request comes from a subframe you should use `requestingUrl` to check the request origin. - * `permission` String - The type of requested permission. + * `permission` string - The type of requested permission. * `clipboard-read` - Request access to read from the clipboard. + * `clipboard-sanitized-write` - Request access to write to the clipboard. + * `display-capture` - Request access to capture the screen via the [Screen Capture API](https://developer.mozilla.org/en-US/docs/Web/API/Screen_Capture_API). + * `fullscreen` - Request control of the app's fullscreen state via the [Fullscreen API](https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API). + * `geolocation` - Request access to the user's location via the [Geolocation API](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API) + * `idle-detection` - Request access to the user's idle state via the [IdleDetector API](https://developer.mozilla.org/en-US/docs/Web/API/IdleDetector). * `media` - Request access to media devices such as camera, microphone and speakers. * `mediaKeySystem` - Request access to DRM protected content. - * `geolocation` - Request access to user's current location. - * `notifications` - Request notification creation and the ability to display them in the user's system tray. - * `midi` - Request MIDI access in the `webmidi` API. - * `midiSysex` - Request the use of system exclusive messages in the `webmidi` API. - * `pointerLock` - Request to directly interpret mouse movements as an input method. Click [here](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API) to know more. - * `fullscreen` - Request for the app to enter fullscreen mode. + * `midi` - Request MIDI access in the [Web MIDI API](https://developer.mozilla.org/en-US/docs/Web/API/Web_MIDI_API). + * `midiSysex` - Request the use of system exclusive messages in the [Web MIDI API](https://developer.mozilla.org/en-US/docs/Web/API/Web_MIDI_API). + * `notifications` - Request notification creation and the ability to display them in the user's system tray using the [Notifications API](https://developer.mozilla.org/en-US/docs/Web/API/notification) + * `pointerLock` - Request to directly interpret mouse movements as an input method via the [Pointer Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API). These requests always appear to originate from the main frame. + * `keyboardLock` - Request capture of keypresses for any or all of the keys on the physical keyboard via the [Keyboard Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Keyboard/lock). These requests always appear to originate from the main frame. * `openExternal` - Request to open links in external applications. + * `speaker-selection` - Request to enumerate and select audio output devices via the [speaker-selection permissions policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Permissions-Policy/speaker-selection). + * `storage-access` - Allows content loaded in a third-party context to request access to third-party cookies using the [Storage Access API](https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API). + * `top-level-storage-access` - Allow top-level sites to request third-party cookie access on behalf of embedded content originating from another site in the same related website set using the [Storage Access API](https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API). + * `window-management` - Request access to enumerate screens using the [`getScreenDetails`](https://developer.chrome.com/en/articles/multi-screen-window-placement/) API. + * `unknown` - An unrecognized permission request. + * `fileSystem` - Request access to read, write, and file management capabilities using the [File System API](https://developer.mozilla.org/en-US/docs/Web/API/File_System_API). * `callback` Function - * `permissionGranted` Boolean - Allow or deny the permission. - * `details` Object - Some properties are only available on certain permission types. - * `externalURL` String (optional) - The url of the `openExternal` request. - * `mediaTypes` String[] (optional) - The types of media access being requested, elements can be `video` - or `audio` - * `requestingUrl` String - The last URL the requesting frame loaded - * `isMainFrame` Boolean - Whether the frame making the request is the main frame + * `permissionGranted` boolean - Allow or deny the permission. + * `details` [PermissionRequest](structures/permission-request.md) | [FilesystemPermissionRequest](structures/filesystem-permission-request.md) | [MediaAccessPermissionRequest](structures/media-access-permission-request.md) | [OpenExternalPermissionRequest](structures/open-external-permission-request.md) - Additional information about the permission being requested. Sets the handler which can be used to respond to permission requests for the `session`. Calling `callback(true)` will allow the permission and `callback(false)` will reject it. -To clear the handler, call `setPermissionRequestHandler(null)`. +To clear the handler, call `setPermissionRequestHandler(null)`. Please note that +you must also implement `setPermissionCheckHandler` to get complete permission handling. +Most web APIs do a permission check and then make a permission request if the check is denied. -```javascript +```js const { session } = require('electron') + session.fromPartition('some-partition').setPermissionRequestHandler((webContents, permission, callback) => { if (webContents.getURL() === 'some-host' && permission === 'notifications') { return callback(false) // denied. @@ -526,29 +916,318 @@ session.fromPartition('some-partition').setPermissionRequestHandler((webContents #### `ses.setPermissionCheckHandler(handler)` -* `handler` Function\<Boolean> | null - * `webContents` [WebContents](web-contents.md) - WebContents checking the permission. Please note that if the request comes from a subframe you should use `requestingUrl` to check the request origin. - * `permission` String - Type of permission check. Valid values are `midiSysex`, `notifications`, `geolocation`, `media`,`mediaKeySystem`,`midi`, `pointerLock`, `fullscreen`, `openExternal`, or `serial`. - * `requestingOrigin` String - The origin URL of the permission check +* `handler` Function\<boolean> | null + * `webContents` ([WebContents](web-contents.md) | null) - WebContents checking the permission. Please note that if the request comes from a subframe you should use `requestingUrl` to check the request origin. All cross origin sub frames making permission checks will pass a `null` webContents to this handler, while certain other permission checks such as `notifications` checks will always pass `null`. You should use `embeddingOrigin` and `requestingOrigin` to determine what origin the owning frame and the requesting frame are on respectively. + * `permission` string - Type of permission check. + * `clipboard-read` - Request access to read from the clipboard. + * `clipboard-sanitized-write` - Request access to write to the clipboard. + * `geolocation` - Access the user's geolocation data via the [Geolocation API](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API) + * `fullscreen` - Control of the app's fullscreen state via the [Fullscreen API](https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API). + * `hid` - Access the HID protocol to manipulate HID devices via the [WebHID API](https://developer.mozilla.org/en-US/docs/Web/API/WebHID_API). + * `idle-detection` - Access the user's idle state via the [IdleDetector API](https://developer.mozilla.org/en-US/docs/Web/API/IdleDetector). + * `media` - Access to media devices such as camera, microphone and speakers. + * `mediaKeySystem` - Access to DRM protected content. + * `midi` - Enable MIDI access in the [Web MIDI API](https://developer.mozilla.org/en-US/docs/Web/API/Web_MIDI_API). + * `midiSysex` - Use system exclusive messages in the [Web MIDI API](https://developer.mozilla.org/en-US/docs/Web/API/Web_MIDI_API). + * `notifications` - Configure and display desktop notifications to the user with the [Notifications API](https://developer.mozilla.org/en-US/docs/Web/API/notification). + * `openExternal` - Open links in external applications. + * `pointerLock` - Directly interpret mouse movements as an input method via the [Pointer Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API). These requests always appear to originate from the main frame. + * `serial` - Read from and write to serial devices with the [Web Serial API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Serial_API). + * `storage-access` - Allows content loaded in a third-party context to request access to third-party cookies using the [Storage Access API](https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API). + * `top-level-storage-access` - Allow top-level sites to request third-party cookie access on behalf of embedded content originating from another site in the same related website set using the [Storage Access API](https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API). + * `usb` - Expose non-standard Universal Serial Bus (USB) compatible devices services to the web with the [WebUSB API](https://developer.mozilla.org/en-US/docs/Web/API/WebUSB_API). + * `deprecated-sync-clipboard-read` _Deprecated_ - Request access to run `document.execCommand("paste")` + * `fileSystem` - Access to read, write, and file management capabilities using the [File System API](https://developer.mozilla.org/en-US/docs/Web/API/File_System_API). + * `requestingOrigin` string - The origin URL of the permission check * `details` Object - Some properties are only available on certain permission types. - * `securityOrigin` String - The security origin of the `media` check. - * `mediaType` String - The type of media access being requested, can be `video`, - `audio` or `unknown` - * `requestingUrl` String - The last URL the requesting frame loaded - * `isMainFrame` Boolean - Whether the frame making the request is the main frame + * `embeddingOrigin` string (optional) - The origin of the frame embedding the frame that made the permission check. Only set for cross-origin sub frames making permission checks. + * `securityOrigin` string (optional) - The security origin of the `media` check. + * `mediaType` string (optional) - The type of media access being requested, can be `video`, + `audio` or `unknown`. + * `requestingUrl` string (optional) - The last URL the requesting frame loaded. This is not provided for cross-origin sub frames making permission checks. + * `isMainFrame` boolean - Whether the frame making the request is the main frame. + * `filePath` string (optional) - The path of a `fileSystem` request. + * `isDirectory` boolean (optional) - Whether a `fileSystem` request is a directory. + * `fileAccessType` string (optional) - The access type of a `fileSystem` request. Can be `writable` or `readable`. Sets the handler which can be used to respond to permission checks for the `session`. -Returning `true` will allow the permission and `false` will reject it. +Returning `true` will allow the permission and `false` will reject it. Please note that +you must also implement `setPermissionRequestHandler` to get complete permission handling. +Most web APIs do a permission check and then make a permission request if the check is denied. To clear the handler, call `setPermissionCheckHandler(null)`. -```javascript +```js const { session } = require('electron') -session.fromPartition('some-partition').setPermissionCheckHandler((webContents, permission) => { - if (webContents.getURL() === 'some-host' && permission === 'notifications') { - return false // denied + +const url = require('node:url') + +session.fromPartition('some-partition').setPermissionCheckHandler((webContents, permission, requestingOrigin) => { + if (new URL(requestingOrigin).hostname === 'some-host' && permission === 'notifications') { + return true // granted } - return true + return false // denied +}) +``` + +> [!NOTE] +> `isMainFrame` will always be `false` for a `fileSystem` request as a result of Chromium limitations. + +#### `ses.setDisplayMediaRequestHandler(handler[, opts])` + +* `handler` Function | null + * `request` Object + * `frame` [WebFrameMain](web-frame-main.md) | null - Frame that is requesting access to media. + May be `null` if accessed after the frame has either navigated or been destroyed. + * `securityOrigin` String - Origin of the page making the request. + * `videoRequested` Boolean - true if the web content requested a video stream. + * `audioRequested` Boolean - true if the web content requested an audio stream. + * `userGesture` Boolean - Whether a user gesture was active when this request was triggered. + * `callback` Function + * `streams` Object + * `video` Object | [WebFrameMain](web-frame-main.md) (optional) + * `id` String - The id of the stream being granted. This will usually + come from a [DesktopCapturerSource](structures/desktop-capturer-source.md) + object. + * `name` String - The name of the stream being granted. This will + usually come from a [DesktopCapturerSource](structures/desktop-capturer-source.md) + object. + * `audio` String | [WebFrameMain](web-frame-main.md) (optional) - If + a string is specified, can be `loopback` or `loopbackWithMute`. + Specifying a loopback device will capture system audio, and is + currently only supported on Windows. If a WebFrameMain is specified, + will capture audio from that frame. + * `enableLocalEcho` Boolean (optional) - If `audio` is a [WebFrameMain](web-frame-main.md) + and this is set to `true`, then local playback of audio will not be muted (e.g. using `MediaRecorder` + to record `WebFrameMain` with this flag set to `true` will allow audio to pass through to the speakers + while recording). Default is `false`. +* `opts` Object (optional) _macOS_ _Experimental_ + * `useSystemPicker` Boolean - true if the available native system picker should be used. Default is `false`. _macOS_ _Experimental_ + +This handler will be called when web content requests access to display media +via the `navigator.mediaDevices.getDisplayMedia` API. Use the +[desktopCapturer](desktop-capturer.md) API to choose which stream(s) to grant +access to. + +`useSystemPicker` allows an application to use the system picker instead of providing a specific video source from `getSources`. +This option is experimental, and currently available for MacOS 15+ only. If the system picker is available and `useSystemPicker` +is set to `true`, the handler will not be invoked. + +```js +const { session, desktopCapturer } = require('electron') + +session.defaultSession.setDisplayMediaRequestHandler((request, callback) => { + desktopCapturer.getSources({ types: ['screen'] }).then((sources) => { + // Grant access to the first screen found. + callback({ video: sources[0] }) + }) + // Use the system picker if available. + // Note: this is currently experimental. If the system picker + // is available, it will be used and the media request handler + // will not be invoked. +}, { useSystemPicker: true }) +``` + +Passing a [WebFrameMain](web-frame-main.md) object as a video or audio stream +will capture the video or audio stream from that frame. + +```js +const { session } = require('electron') + +session.defaultSession.setDisplayMediaRequestHandler((request, callback) => { + // Allow the tab to capture itself. + callback({ video: request.frame }) +}) +``` + +Passing `null` instead of a function resets the handler to its default state. + +#### `ses.setDevicePermissionHandler(handler)` + +* `handler` Function\<boolean> | null + * `details` Object + * `deviceType` string - The type of device that permission is being requested on, can be `hid`, `serial`, or `usb`. + * `origin` string - The origin URL of the device permission check. + * `device` [HIDDevice](structures/hid-device.md) | [SerialPort](structures/serial-port.md) | [USBDevice](structures/usb-device.md) - the device that permission is being requested for. + +Sets the handler which can be used to respond to device permission checks for the `session`. +Returning `true` will allow the device to be permitted and `false` will reject it. +To clear the handler, call `setDevicePermissionHandler(null)`. +This handler can be used to provide default permissioning to devices without first calling for permission +to devices (eg via `navigator.hid.requestDevice`). If this handler is not defined, the default device +permissions as granted through device selection (eg via `navigator.hid.requestDevice`) will be used. +Additionally, the default behavior of Electron is to store granted device permission in memory. +If longer term storage is needed, a developer can store granted device +permissions (eg when handling the `select-hid-device` event) and then read from that storage with `setDevicePermissionHandler`. + +```js @ts-type={fetchGrantedDevices:()=>(Array<Electron.DevicePermissionHandlerHandlerDetails['device']>)} +const { app, BrowserWindow } = require('electron') + +let win = null + +app.whenReady().then(() => { + win = new BrowserWindow() + + win.webContents.session.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => { + if (permission === 'hid') { + // Add logic here to determine if permission should be given to allow HID selection + return true + } else if (permission === 'serial') { + // Add logic here to determine if permission should be given to allow serial port selection + } else if (permission === 'usb') { + // Add logic here to determine if permission should be given to allow USB device selection + } + return false + }) + + // Optionally, retrieve previously persisted devices from a persistent store + const grantedDevices = fetchGrantedDevices() + + win.webContents.session.setDevicePermissionHandler((details) => { + if (new URL(details.origin).hostname === 'some-host' && details.deviceType === 'hid') { + if (details.device.vendorId === 123 && details.device.productId === 345) { + // Always allow this type of device (this allows skipping the call to `navigator.hid.requestDevice` first) + return true + } + + // Search through the list of devices that have previously been granted permission + return grantedDevices.some((grantedDevice) => { + return grantedDevice.vendorId === details.device.vendorId && + grantedDevice.productId === details.device.productId && + grantedDevice.serialNumber && grantedDevice.serialNumber === details.device.serialNumber + }) + } else if (details.deviceType === 'serial') { + if (details.device.vendorId === 123 && details.device.productId === 345) { + // Always allow this type of device (this allows skipping the call to `navigator.hid.requestDevice` first) + return true + } + } + return false + }) + + win.webContents.session.on('select-hid-device', (event, details, callback) => { + event.preventDefault() + const selectedDevice = details.deviceList.find((device) => { + return device.vendorId === 9025 && device.productId === 67 + }) + callback(selectedDevice?.deviceId) + }) +}) +``` + +#### `ses.setUSBProtectedClassesHandler(handler)` + +* `handler` Function\<string[]> | null + * `details` Object + * `protectedClasses` string[] - The current list of protected USB classes. Possible class values include: + * `audio` + * `audio-video` + * `hid` + * `mass-storage` + * `smart-card` + * `video` + * `wireless` + +Sets the handler which can be used to override which [USB classes are protected](https://wicg.github.io/webusb/#usbinterface-interface). +The return value for the handler is a string array of USB classes which should be considered protected (eg not available in the renderer). Valid values for the array are: + +* `audio` +* `audio-video` +* `hid` +* `mass-storage` +* `smart-card` +* `video` +* `wireless` + +Returning an empty string array from the handler will allow all USB classes; returning the passed in array will maintain the default list of protected USB classes (this is also the default behavior if a handler is not defined). +To clear the handler, call `setUSBProtectedClassesHandler(null)`. + +```js +const { app, BrowserWindow } = require('electron') + +let win = null + +app.whenReady().then(() => { + win = new BrowserWindow() + + win.webContents.session.setUSBProtectedClassesHandler((details) => { + // Allow all classes: + // return [] + // Keep the current set of protected classes: + // return details.protectedClasses + // Selectively remove classes: + return details.protectedClasses.filter((usbClass) => { + // Exclude classes except for audio classes + return usbClass.indexOf('audio') === -1 + }) + }) +}) +``` + +#### `ses.setBluetoothPairingHandler(handler)` _Windows_ _Linux_ + +* `handler` Function | null + * `details` Object + * `deviceId` string + * `pairingKind` string - The type of pairing prompt being requested. + One of the following values: + * `confirm` + This prompt is requesting confirmation that the Bluetooth device should + be paired. + * `confirmPin` + This prompt is requesting confirmation that the provided PIN matches the + pin displayed on the device. + * `providePin` + This prompt is requesting that a pin be provided for the device. + * `frame` [WebFrameMain](web-frame-main.md) | null - The frame initiating this handler. + May be `null` if accessed after the frame has either navigated or been destroyed. + * `pin` string (optional) - The pin value to verify if `pairingKind` is `confirmPin`. + * `callback` Function + * `response` Object + * `confirmed` boolean - `false` should be passed in if the dialog is canceled. + If the `pairingKind` is `confirm` or `confirmPin`, this value should indicate + if the pairing is confirmed. If the `pairingKind` is `providePin` the value + should be `true` when a value is provided. + * `pin` string | null (optional) - When the `pairingKind` is `providePin` + this value should be the required pin for the Bluetooth device. + +Sets a handler to respond to Bluetooth pairing requests. This handler +allows developers to handle devices that require additional validation +before pairing. When a handler is not defined, any pairing on Linux or Windows +that requires additional validation will be automatically cancelled. +macOS does not require a handler because macOS handles the pairing +automatically. To clear the handler, call `setBluetoothPairingHandler(null)`. + +```js +const { app, BrowserWindow, session } = require('electron') + +const path = require('node:path') + +function createWindow () { + let bluetoothPinCallback = null + + const mainWindow = new BrowserWindow({ + webPreferences: { + preload: path.join(__dirname, 'preload.js') + } + }) + + mainWindow.webContents.session.setBluetoothPairingHandler((details, callback) => { + bluetoothPinCallback = callback + // Send an IPC message to the renderer to prompt the user to confirm the pairing. + // Note that this will require logic in the renderer to handle this message and + // display a prompt to the user. + mainWindow.webContents.send('bluetooth-pairing-request', details) + }) + + // Listen for an IPC message from the renderer to get the response for the Bluetooth pairing. + mainWindow.webContents.ipc.on('bluetooth-pairing-response', (event, response) => { + bluetoothPinCallback(response) + }) +} + +app.whenReady().then(() => { + createWindow() }) ``` @@ -560,13 +1239,13 @@ Clears the host resolver cache. #### `ses.allowNTLMCredentialsForDomains(domains)` -* `domains` String - A comma-separated list of servers for which +* `domains` string - A comma-separated list of servers for which integrated authentication is enabled. Dynamically sets whether to always send credentials for HTTP NTLM or Negotiate authentication. -```javascript +```js const { session } = require('electron') // consider any url ending with `example.com`, `foobar.com`, `baz` // for integrated authentication. @@ -578,12 +1257,12 @@ session.defaultSession.allowNTLMCredentialsForDomains('*') #### `ses.setUserAgent(userAgent[, acceptLanguages])` -* `userAgent` String -* `acceptLanguages` String (optional) +* `userAgent` string +* `acceptLanguages` string (optional) Overrides the `userAgent` and `acceptLanguages` for this session. -The `acceptLanguages` must a comma separated ordered list of language codes, for +The `acceptLanguages` must be a comma separated ordered list of language codes, for example `"en-US,fr,de,ko,zh-CN,ja"`. This doesn't affect existing `WebContents`, and each `WebContents` can use @@ -591,22 +1270,22 @@ This doesn't affect existing `WebContents`, and each `WebContents` can use #### `ses.isPersistent()` -Returns `Boolean` - Whether or not this session is a persistent one. The default +Returns `boolean` - Whether or not this session is a persistent one. The default `webContents` session of a `BrowserWindow` is persistent. When creating a session from a partition, session prefixed with `persist:` will be persistent, while others will be temporary. #### `ses.getUserAgent()` -Returns `String` - The user agent for this session. +Returns `string` - The user agent for this session. #### `ses.setSSLConfig(config)` * `config` Object - * `minVersion` String (optional) - Can be `tls1`, `tls1.1`, `tls1.2` or `tls1.3`. The + * `minVersion` string (optional) - Can be `tls1`, `tls1.1`, `tls1.2` or `tls1.3`. The minimum SSL version to allow when connecting to remote servers. Defaults to `tls1`. - * `maxVersion` String (optional) - Can be `tls1.2` or `tls1.3`. The maximum SSL version + * `maxVersion` string (optional) - Can be `tls1.2` or `tls1.3`. The maximum SSL version to allow when connecting to remote servers. Defaults to `tls1.3`. * `disabledCipherSuites` Integer[] (optional) - List of cipher suites which should be explicitly prevented from being used in addition to those @@ -625,31 +1304,34 @@ reused for new connections. #### `ses.getBlobData(identifier)` -* `identifier` String - Valid UUID. +* `identifier` string - Valid UUID. Returns `Promise<Buffer>` - resolves with blob data. -#### `ses.downloadURL(url)` +#### `ses.downloadURL(url[, options])` -* `url` String +* `url` string +* `options` Object (optional) + * `headers` Record\<string, string\> (optional) - HTTP request headers. Initiates a download of the resource at `url`. The API will generate a [DownloadItem](download-item.md) that can be accessed with the [will-download](#event-will-download) event. -**Note:** This does not perform any security checks that relate to a page's origin, -unlike [`webContents.downloadURL`](web-contents.md#contentsdownloadurlurl). +> [!NOTE] +> This does not perform any security checks that relate to a page's origin, +> unlike [`webContents.downloadURL`](web-contents.md#contentsdownloadurlurl-options). #### `ses.createInterruptedDownload(options)` * `options` Object - * `path` String - Absolute path of the download. - * `urlChain` String[] - Complete URL chain for the download. - * `mimeType` String (optional) + * `path` string - Absolute path of the download. + * `urlChain` string[] - Complete URL chain for the download. + * `mimeType` string (optional) * `offset` Integer - Start range for the download. * `length` Integer - Total length of the download. - * `lastModified` String (optional) - Last-Modified header value. - * `eTag` String (optional) - ETag header value. + * `lastModified` string (optional) - Last-Modified header value. + * `eTag` string (optional) - ETag header value. * `startTime` Double (optional) - Time when download was started in number of seconds since UNIX epoch. @@ -663,88 +1345,172 @@ the initial state will be `interrupted`. The download will start only when the Returns `Promise<void>` - resolves when the session’s HTTP authentication cache has been cleared. -#### `ses.setPreloads(preloads)` +#### `ses.setPreloads(preloads)` _Deprecated_ -* `preloads` String[] - An array of absolute path to preload scripts +* `preloads` string[] - An array of absolute path to preload scripts Adds scripts that will be executed on ALL web contents that are associated with this session just before normal `preload` scripts run. -#### `ses.getPreloads()` +**Deprecated:** Use the new `ses.registerPreloadScript` API. + +#### `ses.getPreloads()` _Deprecated_ -Returns `String[]` an array of paths to preload scripts that have been +Returns `string[]` an array of paths to preload scripts that have been registered. +**Deprecated:** Use the new `ses.getPreloadScripts` API. This will only return preload script paths +for `frame` context types. + +#### `ses.registerPreloadScript(script)` + +* `script` [PreloadScriptRegistration](structures/preload-script-registration.md) - Preload script + +Registers preload script that will be executed in its associated context type in this session. For +`frame` contexts, this will run prior to any preload defined in the web preferences of a +WebContents. + +Returns `string` - The ID of the registered preload script. + +#### `ses.unregisterPreloadScript(id)` + +* `id` string - Preload script ID + +Unregisters script. + +#### `ses.getPreloadScripts()` + +Returns [`PreloadScript[]`](structures/preload-script.md): An array of paths to preload scripts that have been registered. + +#### `ses.setCodeCachePath(path)` + +* `path` String - Absolute path to store the v8 generated JS code cache from the renderer. + +Sets the directory to store the generated JS [code cache](https://v8.dev/blog/code-caching-for-devs) for this session. The directory is not required to be created by the user before this call, the runtime will create if it does not exist otherwise will use the existing directory. If directory cannot be created, then code cache will not be used and all operations related to code cache will fail silently inside the runtime. By default, the directory will be `Code Cache` under the +respective user data folder. + +Note that by default code cache is only enabled for http(s) URLs, to enable code +cache for custom protocols, `codeCache: true` and `standard: true` must be +specified when registering the protocol. + +#### `ses.clearCodeCaches(options)` + +* `options` Object + * `urls` String[] (optional) - An array of url corresponding to the resource whose generated code cache needs to be removed. If the list is empty then all entries in the cache directory will be removed. + +Returns `Promise<void>` - resolves when the code cache clear operation is complete. + +#### `ses.getSharedDictionaryUsageInfo()` + +Returns `Promise<SharedDictionaryUsageInfo[]>` - an array of shared dictionary information entries in Chromium's networking service's storage. + +Shared dictionaries are used to power advanced compression of data sent over the wire, specifically with Brotli and ZStandard. You don't need to call any of the shared dictionary APIs in Electron to make use of this advanced web feature, but if you do, they allow deeper control and inspection of the shared dictionaries used during decompression. + +To get detailed information about a specific shared dictionary entry, call `getSharedDictionaryInfo(options)`. + +#### `ses.getSharedDictionaryInfo(options)` + +* `options` Object + * `frameOrigin` string - The origin of the frame where the request originates. It’s specific to the individual frame making the request and is defined by its scheme, host, and port. In practice, will look like a URL. + * `topFrameSite` string - The site of the top-level browsing context (the main frame or tab that contains the request). It’s less granular than `frameOrigin` and focuses on the broader "site" scope. In practice, will look like a URL. + +Returns `Promise<SharedDictionaryInfo[]>` - an array of shared dictionary information entries in Chromium's networking service's storage. + +To get information about all present shared dictionaries, call `getSharedDictionaryUsageInfo()`. + +#### `ses.clearSharedDictionaryCache()` + +Returns `Promise<void>` - resolves when the dictionary cache has been cleared, both in memory and on disk. + +#### `ses.clearSharedDictionaryCacheForIsolationKey(options)` + +* `options` Object + * `frameOrigin` string - The origin of the frame where the request originates. It’s specific to the individual frame making the request and is defined by its scheme, host, and port. In practice, will look like a URL. + * `topFrameSite` string - The site of the top-level browsing context (the main frame or tab that contains the request). It’s less granular than `frameOrigin` and focuses on the broader "site" scope. In practice, will look like a URL. + +Returns `Promise<void>` - resolves when the dictionary cache has been cleared for the specified isolation key, both in memory and on disk. + #### `ses.setSpellCheckerEnabled(enable)` -* `enable` Boolean +* `enable` boolean Sets whether to enable the builtin spell checker. #### `ses.isSpellCheckerEnabled()` -Returns `Boolean` - Whether the builtin spell checker is enabled. +Returns `boolean` - Whether the builtin spell checker is enabled. #### `ses.setSpellCheckerLanguages(languages)` -* `languages` String[] - An array of language codes to enable the spellchecker for. +* `languages` string[] - An array of language codes to enable the spellchecker for. The built in spellchecker does not automatically detect what language a user is typing in. In order for the spell checker to correctly check their words you must call this API with an array of language codes. You can get the list of supported language codes with the `ses.availableSpellCheckerLanguages` property. -**Note:** On macOS the OS spellchecker is used and will detect your language automatically. This API is a no-op on macOS. +> [!NOTE] +> On macOS, the OS spellchecker is used and will detect your language automatically. This API is a no-op on macOS. #### `ses.getSpellCheckerLanguages()` -Returns `String[]` - An array of language codes the spellchecker is enabled for. If this list is empty the spellchecker +Returns `string[]` - An array of language codes the spellchecker is enabled for. If this list is empty the spellchecker will fallback to using `en-US`. By default on launch if this setting is an empty list Electron will try to populate this setting with the current OS locale. This setting is persisted across restarts. -**Note:** On macOS the OS spellchecker is used and has its own list of languages. This API is a no-op on macOS. +> [!NOTE] +> On macOS, the OS spellchecker is used and has its own list of languages. On macOS, this API will return whichever languages have been configured by the OS. #### `ses.setSpellCheckerDictionaryDownloadURL(url)` -* `url` String - A base URL for Electron to download hunspell dictionaries from. +* `url` string - A base URL for Electron to download hunspell dictionaries from. By default Electron will download hunspell dictionaries from the Chromium CDN. If you want to override this behavior you can use this API to point the dictionary downloader at your own hosted version of the hunspell dictionaries. We publish a `hunspell_dictionaries.zip` file with each release which contains the files you need -to host here, the file server must be **case insensitive** you must upload each file twice, once with the case it -has in the ZIP file and once with the filename as all lower case. +to host here. + +The file server must be **case insensitive**. If you cannot do this, you must upload each file twice: once with +the case it has in the ZIP file and once with the filename as all lowercase. If the files present in `hunspell_dictionaries.zip` are available at `https://example.com/dictionaries/language-code.bdic` then you should call this api with `ses.setSpellCheckerDictionaryDownloadURL('https://example.com/dictionaries/')`. Please note the trailing slash. The URL to the dictionaries is formed as `${url}${filename}`. -**Note:** On macOS the OS spellchecker is used and therefore we do not download any dictionary files. This API is a no-op on macOS. +> [!NOTE] +> On macOS, the OS spellchecker is used and therefore we do not download any dictionary files. This API is a no-op on macOS. #### `ses.listWordsInSpellCheckerDictionary()` -Returns `Promise<String[]>` - An array of all words in app's custom dictionary. +Returns `Promise<string[]>` - An array of all words in app's custom dictionary. Resolves when the full dictionary is loaded from disk. #### `ses.addWordToSpellCheckerDictionary(word)` -* `word` String - The word you want to add to the dictionary +* `word` string - The word you want to add to the dictionary -Returns `Boolean` - Whether the word was successfully written to the custom dictionary. This API +Returns `boolean` - Whether the word was successfully written to the custom dictionary. This API will not work on non-persistent (in-memory) sessions. -**Note:** On macOS and Windows 10 this word will be written to the OS custom dictionary as well +> [!NOTE] +> On macOS and Windows, this word will be written to the OS custom dictionary as well. #### `ses.removeWordFromSpellCheckerDictionary(word)` -* `word` String - The word you want to remove from the dictionary +* `word` string - The word you want to remove from the dictionary -Returns `Boolean` - Whether the word was successfully removed from the custom dictionary. This API +Returns `boolean` - Whether the word was successfully removed from the custom dictionary. This API will not work on non-persistent (in-memory) sessions. -**Note:** On macOS and Windows 10 this word will be removed from the OS custom dictionary as well +> [!NOTE] +> On macOS and Windows, this word will be removed from the OS custom dictionary as well. -#### `ses.loadExtension(path)` +#### `ses.loadExtension(path[, options])` _Deprecated_ -* `path` String - Path to a directory containing an unpacked Chrome extension +* `path` string - Path to a directory containing an unpacked Chrome extension +* `options` Object (optional) + * `allowFileAccess` boolean - Whether to allow the extension to read local files over `file://` + protocol and inject content scripts into `file://` pages. This is required e.g. for loading + DevTools extensions on `file://` URLs. Defaults to false. Returns `Promise<Extension>` - resolves when the extension is loaded. @@ -764,10 +1530,15 @@ extension to be loaded. ```js const { app, session } = require('electron') -const path = require('path') -app.on('ready', async () => { - await session.defaultSession.loadExtension(path.join(__dirname, 'react-devtools')) +const path = require('node:path') + +app.whenReady().then(async () => { + await session.defaultSession.loadExtension( + path.join(__dirname, 'react-devtools'), + // allowFileAccess is required to load the DevTools extension on file:// URLs. + { allowFileAccess: true } + ) // Note that in order to use the React DevTools extension, you'll need to // download and unzip a copy of the extension. }) @@ -775,36 +1546,91 @@ app.on('ready', async () => { This API does not support loading packed (.crx) extensions. -**Note:** This API cannot be called before the `ready` event of the `app` module -is emitted. +> [!NOTE] +> This API cannot be called before the `ready` event of the `app` module +> is emitted. + +> [!NOTE] +> Loading extensions into in-memory (non-persistent) sessions is not +> supported and will throw an error. -**Note:** Loading extensions into in-memory (non-persistent) sessions is not -supported and will throw an error. +**Deprecated:** Use the new `ses.extensions.loadExtension` API. -#### `ses.removeExtension(extensionId)` +#### `ses.removeExtension(extensionId)` _Deprecated_ -* `extensionId` String - ID of extension to remove +* `extensionId` string - ID of extension to remove Unloads an extension. -**Note:** This API cannot be called before the `ready` event of the `app` module -is emitted. +> [!NOTE] +> This API cannot be called before the `ready` event of the `app` module +> is emitted. + +**Deprecated:** Use the new `ses.extensions.removeExtension` API. -#### `ses.getExtension(extensionId)` +#### `ses.getExtension(extensionId)` _Deprecated_ -* `extensionId` String - ID of extension to query +* `extensionId` string - ID of extension to query -Returns `Extension` | `null` - The loaded extension with the given ID. +Returns `Extension | null` - The loaded extension with the given ID. -**Note:** This API cannot be called before the `ready` event of the `app` module -is emitted. +> [!NOTE] +> This API cannot be called before the `ready` event of the `app` module +> is emitted. -#### `ses.getAllExtensions()` +**Deprecated:** Use the new `ses.extensions.getExtension` API. + +#### `ses.getAllExtensions()` _Deprecated_ Returns `Extension[]` - A list of all loaded extensions. -**Note:** This API cannot be called before the `ready` event of the `app` module -is emitted. +> [!NOTE] +> This API cannot be called before the `ready` event of the `app` module +> is emitted. + +**Deprecated:** Use the new `ses.extensions.getAllExtensions` API. + +#### `ses.getStoragePath()` + +Returns `string | null` - The absolute file system path where data for this +session is persisted on disk. For in memory sessions this returns `null`. + +#### `ses.clearData([options])` + +* `options` Object (optional) + * `dataTypes` String[] (optional) - The types of data to clear. By default, this will clear all types of data. This + can potentially include data types not explicitly listed here. (See Chromium's + [`BrowsingDataRemover`][browsing-data-remover] for the full list.) + * `backgroundFetch` - Background Fetch + * `cache` - Cache (includes `cachestorage` and `shadercache`) + * `cookies` - Cookies + * `downloads` - Downloads + * `fileSystems` - File Systems + * `indexedDB` - IndexedDB + * `localStorage` - Local Storage + * `serviceWorkers` - Service Workers + * `webSQL` - WebSQL + * `origins` String[] (optional) - Clear data for only these origins. Cannot be used with `excludeOrigins`. + * `excludeOrigins` String[] (optional) - Clear data for all origins except these ones. Cannot be used with `origins`. + * `avoidClosingConnections` boolean (optional) - Skips deleting cookies that would close current network connections. (Default: `false`) + * `originMatchingMode` String (optional) - The behavior for matching data to origins. + * `third-parties-included` (default) - Storage is matched on origin in first-party contexts and top-level-site in third-party contexts. + * `origin-in-all-contexts` - Storage is matched on origin only in all contexts. + +Returns `Promise<void>` - resolves when all data has been cleared. + +Clears various different types of data. + +This method clears more types of data and is more thorough than the +`clearStorageData` method. + +> [!NOTE] +> Cookies are stored at a broader scope than origins. When removing cookies and filtering by `origins` (or `excludeOrigins`), the cookies will be removed at the [registrable domain](https://url.spec.whatwg.org/#host-registrable-domain) level. For example, clearing cookies for the origin `https://really.specific.origin.example.com/` will end up clearing all cookies for `example.com`. Clearing cookies for the origin `https://my.website.example.co.uk/` will end up clearing all cookies for `example.co.uk`. + +> [!NOTE] +> Clearing cache data will also clear the shared dictionary cache. This means that any dictionaries used for compression may be reloaded after clearing the cache. If you wish to clear the shared dictionary cache but leave other cached data intact, you may want to use the `clearSharedDictionaryCache` method. + +For more information, refer to Chromium's [`BrowsingDataRemover` interface][browsing-data-remover]. ### Instance Properties @@ -812,17 +1638,26 @@ The following properties are available on instances of `Session`: #### `ses.availableSpellCheckerLanguages` _Readonly_ -A `String[]` array which consists of all the known available spell checker languages. Providing a language +A `string[]` array which consists of all the known available spell checker languages. Providing a language code to the `setSpellCheckerLanguages` API that isn't in this array will result in an error. #### `ses.spellCheckerEnabled` -A `Boolean` indicating whether builtin spell checker is enabled. +A `boolean` indicating whether builtin spell checker is enabled. + +#### `ses.storagePath` _Readonly_ + +A `string | null` indicating the absolute file system path where data for this +session is persisted on disk. For in memory sessions this returns `null`. #### `ses.cookies` _Readonly_ A [`Cookies`](cookies.md) object for this session. +#### `ses.extensions` _Readonly_ + +A [`Extensions`](extensions-api.md) object for this session. + #### `ses.serviceWorkers` _Readonly_ A [`ServiceWorkers`](service-workers.md) object for this session. @@ -835,15 +1670,16 @@ A [`WebRequest`](web-request.md) object for this session. A [`Protocol`](protocol.md) object for this session. -```javascript +```js const { app, session } = require('electron') -const path = require('path') + +const path = require('node:path') app.whenReady().then(() => { const protocol = session.fromPartition('some-partition').protocol if (!protocol.registerFileProtocol('atom', (request, callback) => { const url = request.url.substr(7) - callback({ path: path.normalize(`${__dirname}/${url}`) }) + callback({ path: path.normalize(path.join(__dirname, url)) }) })) { console.error('Failed to register protocol') } @@ -854,7 +1690,7 @@ app.whenReady().then(() => { A [`NetLog`](net-log.md) object for this session. -```javascript +```js const { app, session } = require('electron') app.whenReady().then(async () => { @@ -865,3 +1701,5 @@ app.whenReady().then(async () => { console.log('Net-logs written to', path) }) ``` + +[browsing-data-remover]: https://source.chromium.org/chromium/chromium/src/+/main:content/public/browser/browsing_data_remover.h diff --git a/docs/api/share-menu.md b/docs/api/share-menu.md index 007028db3bc95..cb5ee3d01709f 100644 --- a/docs/api/share-menu.md +++ b/docs/api/share-menu.md @@ -1,8 +1,4 @@ -## Class: ShareMenu - -> Create share menu on macOS. - -Process: [Main](../glossary.md#main-process) +# ShareMenu The `ShareMenu` class creates [Share Menu][share-menu] on macOS, which can be used to share information from the current context to apps, social media @@ -11,6 +7,23 @@ accounts, and other services. For including the share menu as a submenu of other menus, please use the `shareMenu` role of [`MenuItem`](menu-item.md). +## Class: ShareMenu + +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/25629 +``` +--> + +> Create share menu on macOS. + +Process: [Main](../glossary.md#main-process) + +> [!WARNING] +> Electron's built-in classes cannot be subclassed in user code. +> For more information, see [the FAQ](../faq.md#class-inheritance-does-not-work-with-electron-built-in-modules). + ### `new ShareMenu(sharingItem)` * `sharingItem` SharingItem - The item to share. @@ -25,11 +38,11 @@ The `shareMenu` object has the following instance methods: * `options` PopupOptions (optional) * `browserWindow` [BrowserWindow](browser-window.md) (optional) - Default is the focused window. - * `x` Number (optional) - Default is the current mouse cursor position. + * `x` number (optional) - Default is the current mouse cursor position. Must be declared if `y` is declared. - * `y` Number (optional) - Default is the current mouse cursor position. + * `y` number (optional) - Default is the current mouse cursor position. Must be declared if `x` is declared. - * `positioningItem` Number (optional) _macOS_ - The index of the menu item to + * `positioningItem` number (optional) _macOS_ - The index of the menu item to be positioned under the mouse cursor at the specified coordinates. Default is -1. * `callback` Function (optional) - Called when menu is closed. diff --git a/docs/api/shared-texture.md b/docs/api/shared-texture.md new file mode 100644 index 0000000000000..d49f596447e45 --- /dev/null +++ b/docs/api/shared-texture.md @@ -0,0 +1,58 @@ +# sharedTexture + +> Import shared textures into Electron and converts platform specific handles into [`VideoFrame`](https://developer.mozilla.org/en-US/docs/Web/API/VideoFrame). Supports all Web rendering systems, and can be transferred across Electron processes. Read [here](../../shell/common/api/shared_texture/README.md) for more information. + +Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process) + +## Methods + +The `sharedTexture` module has the following methods: + +**Note:** Experimental APIs are marked as such and could be removed in the future. + +### `sharedTexture.importSharedTexture(options)` _Experimental_ + +* `options` Object - Options for importing shared textures. + * `textureInfo` [SharedTextureImportTextureInfo](structures/shared-texture-import-texture-info.md) - The information of the shared texture to import. + * `allReferencesReleased` Function (optional) - Called when all references in all processes are released. You should keep the imported texture valid until this callback is called. + +Imports the shared texture from the given options. + +> [!NOTE] +> This method is only available in the main process. + +Returns [`SharedTextureImported`](structures/shared-texture-imported.md) - The imported shared texture. + +### `sharedTexture.sendSharedTexture(options, ...args)` _Experimental_ + +* `options` Object - Options for sending shared texture. + * `frame` [WebFrameMain](web-frame-main.md) - The target frame to transfer the shared texture to. For `WebContents`, you can pass `webContents.mainFrame`. If you provide a `webFrameMain` that is not a main frame, you'll need to enable `webPreferences.nodeIntegrationInSubFrames` for this, since this feature requires [IPC](https://www.electronjs.org/docs/latest/api/web-frame-main#frameipc-readonly) between main and the frame. + * `importedSharedTexture` [SharedTextureImported](structures/shared-texture-imported.md) - The imported shared texture. +* `...args` any[] - Additional arguments to pass to the renderer process. + +Send the imported shared texture to a renderer process. You must register a receiver at renderer process before calling this method. This method has a 1000ms timeout. Ensure the receiver is set and the renderer process is alive before calling this method. + +> [!NOTE] +> This method is only available in the main process. + +Returns `Promise<void>` - Resolves when the transfer is complete. + +### `sharedTexture.setSharedTextureReceiver(callback)` _Experimental_ + +* `callback` Function\<Promise\<void\>\> - The function to receive the imported shared texture. + * `receivedSharedTextureData` Object - The data received from the main process. + * `importedSharedTexture` [SharedTextureImported](structures/shared-texture-imported.md) - The imported shared texture. + * `...args` any[] - Additional arguments passed from the main process. + +Set a callback to receive imported shared textures from the main process. + +> [!NOTE] +> This method is only available in the renderer process. + +## Properties + +The `sharedTexture` module has the following properties: + +### `sharedTexture.subtle` _Experimental_ + +A [`SharedTextureSubtle`](structures/shared-texture-subtle.md) property, provides subtle APIs for interacting with shared texture for advanced users. diff --git a/docs/api/shell.md b/docs/api/shell.md index 59abeb2259c2b..07f32c73fe43d 100644 --- a/docs/api/shell.md +++ b/docs/api/shell.md @@ -8,13 +8,14 @@ The `shell` module provides functions related to desktop integration. An example of opening a URL in the user's default browser: -```javascript +```js const { shell } = require('electron') shell.openExternal('https://github.com') ``` -**Note:** While the `shell` module can be used in the renderer process, it will not function in a sandboxed renderer. +> [!WARNING] +> While the `shell` module can be used in the renderer process, it will not function in a sandboxed renderer. ## Methods @@ -22,43 +23,62 @@ The `shell` module has the following methods: ### `shell.showItemInFolder(fullPath)` -* `fullPath` String +* `fullPath` string Show the given file in a file manager. If possible, select the file. ### `shell.openPath(path)` -* `path` String +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/20682 + breaking-changes-header: api-changed-shellopenitem-is-now-shellopenpath +``` +--> + +* `path` string -Returns `Promise<String>` - Resolves with a string containing the error message corresponding to the failure if a failure occurred, otherwise "". +Returns `Promise<string>` - Resolves with a string containing the error message corresponding to the failure if a failure occurred, otherwise "". Open the given file in the desktop's default manner. ### `shell.openExternal(url[, options])` -* `url` String - Max 2081 characters on windows. +<!-- +```YAML history +changes: + - pr-url: https://github.com/electron/electron/pull/4508 + description: "Added `activate` option." + - pr-url: https://github.com/electron/electron/pull/15065 + description: "Added `workingDirectory` option." + - pr-url: https://github.com/electron/electron/pull/37139 + description: "Added `logUsage` option." +``` +--> + +* `url` string - Max 2081 characters on Windows. * `options` Object (optional) - * `activate` Boolean (optional) _macOS_ - `true` to bring the opened application to the foreground. The default is `true`. - * `workingDirectory` String (optional) _Windows_ - The working directory. + * `activate` boolean (optional) _macOS_ - `true` to bring the opened application to the foreground. The default is `true`. + * `workingDirectory` string (optional) _Windows_ - The working directory. + * `logUsage` boolean (optional) _Windows_ - Indicates a user initiated launch that enables tracking of frequently used programs and other behaviors. + The default is `false`. Returns `Promise<void>` Open the given external protocol URL in the desktop's default manner. (For example, mailto: URLs in the user's default mail agent). -### `shell.moveItemToTrash(fullPath[, deleteOnFail])` _Deprecated_ - -* `fullPath` String -* `deleteOnFail` Boolean (optional) - Whether or not to unilaterally remove the item if the Trash is disabled or unsupported on the volume. _macOS_ - -Returns `Boolean` - Whether the item was successfully moved to the trash or otherwise deleted. - -> NOTE: This method is deprecated. Use `shell.trashItem` instead. - -Move the given file to trash and returns a boolean status for the operation. - ### `shell.trashItem(path)` -* `path` String - path to the item to be moved to the trash. +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/25114 + breaking-changes-header: deprecated-shellmoveitemtotrash +``` +--> + +* `path` string - path to the item to be moved to the trash. Returns `Promise<void>` - Resolves when the operation has been completed. Rejects if there was an error while deleting the requested item. @@ -66,27 +86,31 @@ Rejects if there was an error while deleting the requested item. This moves a path to the OS-specific trash location (Trash on macOS, Recycle Bin on Windows, and a desktop-environment-specific location on Linux). +The path must use the default path separator for the platform (backslash on +Windows). Use `path.resolve()` from the `node:path` module to ensure correct +handling on all filesystems. + ### `shell.beep()` Play the beep sound. ### `shell.writeShortcutLink(shortcutPath[, operation], options)` _Windows_ -* `shortcutPath` String -* `operation` String (optional) - Default is `create`, can be one of following: +* `shortcutPath` string +* `operation` string (optional) - Default is `create`, can be one of following: * `create` - Creates a new shortcut, overwriting if necessary. * `update` - Updates specified properties only on an existing shortcut. * `replace` - Overwrites an existing shortcut, fails if the shortcut doesn't exist. * `options` [ShortcutDetails](structures/shortcut-details.md) -Returns `Boolean` - Whether the shortcut was created successfully. +Returns `boolean` - Whether the shortcut was created successfully. Creates or updates a shortcut link at `shortcutPath`. ### `shell.readShortcutLink(shortcutPath)` _Windows_ -* `shortcutPath` String +* `shortcutPath` string Returns [`ShortcutDetails`](structures/shortcut-details.md) diff --git a/docs/api/structures/activation-arguments.md b/docs/api/structures/activation-arguments.md new file mode 100644 index 0000000000000..d42d14db6eb42 --- /dev/null +++ b/docs/api/structures/activation-arguments.md @@ -0,0 +1,9 @@ +# ActivationArguments Object + +> Used on Windows only. + +* `type` string - The type of activation that launched the app: `'click'`, `'action'`, or `'reply'`. +* `arguments` string - The raw activation arguments string from Windows. +* `actionIndex` number (optional) - For `'action'` type, the index of the button that was clicked. +* `reply` string (optional) - For `'reply'` type, the text the user entered in the reply field. +* `userInputs` Record\<string, string\> (optional) - A dictionary of all user inputs from the notification. diff --git a/docs/api/structures/base-window-options.md b/docs/api/structures/base-window-options.md new file mode 100644 index 0000000000000..7aed2fc33a971 --- /dev/null +++ b/docs/api/structures/base-window-options.md @@ -0,0 +1,164 @@ +# BaseWindowConstructorOptions Object + +* `width` Integer (optional) - Window's width in pixels. Default is `800`. +* `height` Integer (optional) - Window's height in pixels. Default is `600`. +* `x` Integer (optional) - (**required** if y is used) Window's left offset from screen. + Default is to center the window. +* `y` Integer (optional) - (**required** if x is used) Window's top offset from screen. + Default is to center the window. +* `useContentSize` boolean (optional) - The `width` and `height` would be used as web + page's size, which means the actual window's size will include window + frame's size and be slightly larger. Default is `false`. +* `center` boolean (optional) - Show window in the center of the screen. Default is `false`. +* `minWidth` Integer (optional) - Window's minimum width. Default is `0`. +* `minHeight` Integer (optional) - Window's minimum height. Default is `0`. +* `maxWidth` Integer (optional) - Window's maximum width. Default is no limit. +* `maxHeight` Integer (optional) - Window's maximum height. Default is no limit. +* `resizable` boolean (optional) - Whether window is resizable. Default is `true`. +* `movable` boolean (optional) _macOS_ _Windows_ - Whether window is + movable. This is not implemented on Linux. Default is `true`. +* `minimizable` boolean (optional) _macOS_ _Windows_ - Whether window is + minimizable. This is not implemented on Linux. Default is `true`. +* `maximizable` boolean (optional) _macOS_ _Windows_ - Whether window is + maximizable. This is not implemented on Linux. Default is `true`. +* `closable` boolean (optional) _macOS_ _Windows_ - Whether window is + closable. This is not implemented on Linux. Default is `true`. +* `focusable` boolean (optional) - Whether the window can be focused. Default is + `true`. On Windows setting `focusable: false` also implies setting + `skipTaskbar: true`. On Linux setting `focusable: false` makes the window + stop interacting with wm, so the window will always stay on top in all + workspaces. +* `alwaysOnTop` boolean (optional) - Whether the window should always stay on top of + other windows. Default is `false`. +* `fullscreen` boolean (optional) - Whether the window should show in fullscreen. When + explicitly set to `false` the fullscreen button will be hidden or disabled + on macOS. Default is `false`. +* `fullscreenable` boolean (optional) - Whether the window can be put into fullscreen + mode. On macOS, also whether the maximize/zoom button should toggle full + screen mode or maximize window. Default is `true`. +* `simpleFullscreen` boolean (optional) _macOS_ - Use pre-Lion fullscreen on + macOS. Default is `false`. +* `skipTaskbar` boolean (optional) _macOS_ _Windows_ - Whether to show the window in taskbar. + Default is `false`. +* `hiddenInMissionControl` boolean (optional) _macOS_ - Whether window should be hidden when the user toggles into mission control. +* `kiosk` boolean (optional) - Whether the window is in kiosk mode. Default is `false`. +* `title` string (optional) - Default window title. Default is `"Electron"`. If the HTML tag `<title>` is defined in the HTML file loaded by `loadURL()`, this property will be ignored. +* `icon` ([NativeImage](../native-image.md) | string) (optional) - The window icon. On Windows it is + recommended to use `ICO` icons to get best visual effects, you can also + leave it undefined so the executable's icon will be used. +* `show` boolean (optional) - Whether window should be shown when created. Default is + `true`. +* `frame` boolean (optional) - Specify `false` to create a + [frameless window](../../tutorial/custom-window-styles.md#frameless-windows). Default is `true`. +* `parent` BaseWindow (optional) - Specify parent window. Default is `null`. +* `modal` boolean (optional) - Whether this is a modal window. This only works when the + window is a child window. Default is `false`. +* `acceptFirstMouse` boolean (optional) _macOS_ - Whether clicking an + inactive window will also click through to the web contents. Default is + `false` on macOS. This option is not configurable on other platforms. +* `disableAutoHideCursor` boolean (optional) - Whether to hide cursor when typing. + Default is `false`. +* `autoHideMenuBar` boolean (optional) _Linux_ _Windows_ - Auto hide the menu bar + unless the `Alt` key is pressed. Default is `false`. +* `enableLargerThanScreen` boolean (optional) _macOS_ - Enable the window to + be resized larger than screen. Only relevant for macOS, as other OSes + allow larger-than-screen windows by default. Default is `false`. +* `backgroundColor` string (optional) - The window's background color in Hex, RGB, RGBA, HSL, HSLA or named CSS color format. Alpha in #AARRGGBB format is supported if `transparent` is set to `true`. Default is `#FFF` (white). See [win.setBackgroundColor](../browser-window.md#winsetbackgroundcolorbackgroundcolor) for more information. +* `hasShadow` boolean (optional) - Whether window should have a shadow. Default is `true`. +* `opacity` number (optional) _macOS_ _Windows_ - Set the initial opacity of + the window, between 0.0 (fully transparent) and 1.0 (fully opaque). This + is only implemented on Windows and macOS. +* `darkTheme` boolean (optional) - Forces using dark theme for the window, only works on + some GTK+3 desktop environments. Default is `false`. +* `transparent` boolean (optional) - Makes the window [transparent](../../tutorial/custom-window-styles.md#transparent-windows). + Default is `false`. On Windows, does not work unless the window is frameless. + When you add a [`View`](../view.md) to a `BaseWindow`, you'll need to call + [`view.setBackgroundColor`](../view.md#viewsetbackgroundcolorcolor) with a transparent + background color on that view to make its background transparent as well. +* `type` string (optional) - The type of window, default is normal window. See more about + this below. +* `visualEffectState` string (optional) _macOS_ - Specify how the material + appearance should reflect window activity state on macOS. Must be used + with the `vibrancy` property. Possible values are: + * `followWindow` - The backdrop should automatically appear active when the window is active, and inactive when it is not. This is the default. + * `active` - The backdrop should always appear active. + * `inactive` - The backdrop should always appear inactive. +* `titleBarStyle` string (optional) - The style of window title bar. + Default is `default`. Possible values are: + * `default` - Results in the standard title bar for macOS or Windows respectively. + * `hidden` - Results in a hidden title bar and a full size content window. On macOS, the window still has the standard window controls (“traffic lights”) in the top left. On Windows and Linux, when combined with `titleBarOverlay: true` it will activate the Window Controls Overlay (see `titleBarOverlay` for more information), otherwise no window controls will be shown. + * `hiddenInset` _macOS_ - Results in a hidden title bar + with an alternative look where the traffic light buttons are slightly + more inset from the window edge. + * `customButtonsOnHover` _macOS_ - Results in a hidden + title bar and a full size content window, the traffic light buttons will + display when being hovered over in the top left of the window. + **Note:** This option is currently experimental. +* `titleBarOverlay` Object | Boolean (optional) - When using a frameless window in conjunction with `win.setWindowButtonVisibility(true)` on macOS or using a `titleBarStyle` so that the standard window controls ("traffic lights" on macOS) are visible, this property enables the Window Controls Overlay [JavaScript APIs][overlay-javascript-apis] and [CSS Environment Variables][overlay-css-env-vars]. Specifying `true` will result in an overlay with default system colors. Default is `false`. + * `color` String (optional) _Windows_ _Linux_ - The CSS color of the Window Controls Overlay when enabled. Default is the system color. + * `symbolColor` String (optional) _Windows_ _Linux_ - The CSS color of the symbols on the Window Controls Overlay when enabled. Default is the system color. + * `height` Integer (optional) - The height of the title bar and Window Controls Overlay in pixels. Default is system height. +* `accentColor` boolean | string (optional) _Windows_ - The accent color for the window. By default, follows user preference in System Settings. Set to `false` to explicitly disable, or set the color in Hex, RGB, RGBA, HSL, HSLA or named CSS color format. Alpha values will be ignored. +* `trafficLightPosition` [Point](point.md) (optional) _macOS_ - + Set a custom position for the traffic light buttons in frameless windows. +* `roundedCorners` boolean (optional) _macOS_ _Windows_ - Whether frameless window + should have rounded corners. Default is `true`. On Windows versions older than + Windows 11 Build 22000 this property has no effect, and frameless windows will + not have rounded corners. +* `thickFrame` boolean (optional) _Windows_ - Use `WS_THICKFRAME` style for + frameless windows on Windows, which adds the standard window frame. Setting it + to `false` will remove window shadow and window animations, and disable window + resizing via dragging the window edges. Default is `true`. +* `vibrancy` string (optional) _macOS_ - Add a type of vibrancy effect to + the window, only on macOS. Can be `appearance-based`, `titlebar`, `selection`, + `menu`, `popover`, `sidebar`, `header`, `sheet`, `window`, `hud`, `fullscreen-ui`, + `tooltip`, `content`, `under-window`, or `under-page`. +* `backgroundMaterial` string (optional) _Windows_ - Set the window's + system-drawn background material, including behind the non-client area. + Can be `auto`, `none`, `mica`, `acrylic` or `tabbed`. See [win.setBackgroundMaterial](../browser-window.md#winsetbackgroundmaterialmaterial-windows) for more information. +* `zoomToPageWidth` boolean (optional) _macOS_ - Controls the behavior on + macOS when option-clicking the green stoplight button on the toolbar or by + clicking the Window > Zoom menu item. If `true`, the window will grow to + the preferred width of the web page when zoomed, `false` will cause it to + zoom to the width of the screen. This will also affect the behavior when + calling `maximize()` directly. Default is `false`. +* `tabbingIdentifier` string (optional) _macOS_ - Tab group name, allows + opening the window as a native tab. Windows with the same + tabbing identifier will be grouped together. This also adds a native new + tab button to your window's tab bar and allows your `app` and window to + receive the `new-window-for-tab` event. + +When setting minimum or maximum window size with `minWidth`/`maxWidth`/ +`minHeight`/`maxHeight`, it only constrains the users. It won't prevent you from +passing a size that does not follow size constraints to `setBounds`/`setSize` or +to the constructor of `BrowserWindow`. + +The possible values and behaviors of the `type` option are platform dependent. +Possible values are: + +* On Linux, possible types are `desktop`, `dock`, `toolbar`, `splash`, + `notification`. + * The `desktop` type places the window at the desktop background window level + (kCGDesktopWindowLevel - 1). However, note that a desktop window will not + receive focus, keyboard, or mouse events. You can still use globalShortcut to + receive input sparingly. + * The `dock` type creates a dock-like window behavior. + * The `toolbar` type creates a window with a toolbar appearance. + * The `splash` type behaves in a specific way. It is not + draggable, even if the CSS styling of the window's body contains + -webkit-app-region: drag. This type is commonly used for splash screens. + * The `notification` type creates a window that behaves like a system notification. +* On macOS, possible types are `desktop`, `textured`, `panel`. + * The `textured` type adds metal gradient appearance. This option is **deprecated**. + * The `desktop` type places the window at the desktop background window level + (`kCGDesktopWindowLevel - 1`). Note that desktop window will not receive + focus, keyboard or mouse events, but you can use `globalShortcut` to receive + input sparingly. + * The `panel` type enables the window to float on top of full-screened apps + by adding the `NSWindowStyleMaskNonactivatingPanel` style mask, normally + reserved for NSPanel, at runtime. Also, the window will appear on all + spaces (desktops). +* On Windows, possible type is `toolbar`. + +[overlay-css-env-vars]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md#css-environment-variables +[overlay-javascript-apis]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md#javascript-apis diff --git a/docs/api/structures/bluetooth-device.md b/docs/api/structures/bluetooth-device.md index 33d3bb51f94da..b3b408a2739b1 100644 --- a/docs/api/structures/bluetooth-device.md +++ b/docs/api/structures/bluetooth-device.md @@ -1,4 +1,4 @@ # BluetoothDevice Object -* `deviceName` String -* `deviceId` String +* `deviceName` string +* `deviceId` string diff --git a/docs/api/structures/browser-window-options.md b/docs/api/structures/browser-window-options.md new file mode 100644 index 0000000000000..a505798eb0a5b --- /dev/null +++ b/docs/api/structures/browser-window-options.md @@ -0,0 +1,4 @@ +# BrowserWindowConstructorOptions Object extends `BaseWindowConstructorOptions` + +* `webPreferences` [WebPreferences](web-preferences.md?inline) (optional) - Settings of web page's features. +* `paintWhenInitiallyHidden` boolean (optional) - Whether the renderer should be active when `show` is `false` and it has just been created. In order for `document.visibilityState` to work correctly on first load with `show: false` you should set this to `false`. Setting this to `false` will cause the `ready-to-show` event to not fire. Default is `true`. diff --git a/docs/api/structures/certificate-principal.md b/docs/api/structures/certificate-principal.md index 2eb5574bffe05..e070dfd137e1b 100644 --- a/docs/api/structures/certificate-principal.md +++ b/docs/api/structures/certificate-principal.md @@ -1,8 +1,8 @@ # CertificatePrincipal Object -* `commonName` String - Common Name. -* `organizations` String[] - Organization names. -* `organizationUnits` String[] - Organization Unit names. -* `locality` String - Locality. -* `state` String - State or province. -* `country` String - Country or region. +* `commonName` string - Common Name. +* `organizations` string[] - Organization names. +* `organizationUnits` string[] - Organization Unit names. +* `locality` string - Locality. +* `state` string - State or province. +* `country` string - Country or region. diff --git a/docs/api/structures/certificate.md b/docs/api/structures/certificate.md index 3c521b2d360e5..7fc240bf3b49b 100644 --- a/docs/api/structures/certificate.md +++ b/docs/api/structures/certificate.md @@ -1,12 +1,12 @@ # Certificate Object -* `data` String - PEM encoded data +* `data` string - PEM encoded data * `issuer` [CertificatePrincipal](certificate-principal.md) - Issuer principal -* `issuerName` String - Issuer's Common Name +* `issuerName` string - Issuer's Common Name * `issuerCert` Certificate - Issuer certificate (if not self-signed) * `subject` [CertificatePrincipal](certificate-principal.md) - Subject principal -* `subjectName` String - Subject's Common Name -* `serialNumber` String - Hex value represented string -* `validStart` Number - Start date of the certificate being valid in seconds -* `validExpiry` Number - End date of the certificate being valid in seconds -* `fingerprint` String - Fingerprint of the certificate +* `subjectName` string - Subject's Common Name +* `serialNumber` string - Hex value represented string +* `validStart` number - Start date of the certificate being valid in seconds +* `validExpiry` number - End date of the certificate being valid in seconds +* `fingerprint` string - Fingerprint of the certificate diff --git a/docs/api/structures/color-space.md b/docs/api/structures/color-space.md new file mode 100644 index 0000000000000..03ed809f4a57a --- /dev/null +++ b/docs/api/structures/color-space.md @@ -0,0 +1,195 @@ +# ColorSpace Object + +* `primaries` string - The color primaries of the color space. Can be one of the following values: + * `bt709` - BT709 primaries (also used for sRGB) + * `bt470m` - BT470M primaries + * `bt470bg` - BT470BG primaries + * `smpte170m` - SMPTE170M primaries + * `smpte240m` - SMPTE240M primaries + * `film` - Film primaries + * `bt2020` - BT2020 primaries + * `smptest428-1` - SMPTEST428-1 primaries + * `smptest431-2` - SMPTEST431-2 primaries + * `p3` - P3 primaries + * `xyz-d50` - XYZ D50 primaries + * `adobe-rgb` - Adobe RGB primaries + * `apple-generic-rgb` - Apple Generic RGB primaries + * `wide-gamut-color-spin` - Wide Gamut Color Spin primaries + * `ebu-3213-e` - EBU 3213-E primaries + * `custom` - Custom primaries + * `invalid` - Invalid primaries + +* `transfer` string - The transfer function of the color space. Can be one of the following values: + * `bt709` - BT709 transfer function + * `bt709-apple` - BT709 Apple transfer function + * `gamma18` - Gamma 1.8 transfer function + * `gamma22` - Gamma 2.2 transfer function + * `gamma24` - Gamma 2.4 transfer function + * `gamma28` - Gamma 2.8 transfer function + * `smpte170m` - SMPTE170M transfer function + * `smpte240m` - SMPTE240M transfer function + * `linear` - Linear transfer function + * `log` - Log transfer function + * `log-sqrt` - Log Square Root transfer function + * `iec61966-2-4` - IEC61966-2-4 transfer function + * `bt1361-ecg` - BT1361 ECG transfer function + * `srgb` - sRGB transfer function + * `bt2020-10` - BT2020-10 transfer function + * `bt2020-12` - BT2020-12 transfer function + * `pq` - PQ (Perceptual Quantizer) transfer function + * `smptest428-1` - SMPTEST428-1 transfer function + * `hlg` - HLG (Hybrid Log-Gamma) transfer function + * `srgb-hdr` - sRGB HDR transfer function + * `linear-hdr` - Linear HDR transfer function + * `custom` - Custom transfer function + * `custom-hdr` - Custom HDR transfer function + * `scrgb-linear-80-nits` - scRGB Linear 80 nits transfer function + * `invalid` - Invalid transfer function + +* `matrix` string - The color matrix of the color space. Can be one of the following values: + * `rgb` - RGB matrix + * `bt709` - BT709 matrix + * `fcc` - FCC matrix + * `bt470bg` - BT470BG matrix + * `smpte170m` - SMPTE170M matrix + * `smpte240m` - SMPTE240M matrix + * `ycocg` - YCoCg matrix + * `bt2020-ncl` - BT2020 NCL matrix + * `ydzdx` - YDzDx matrix + * `gbr` - GBR matrix + * `invalid` - Invalid matrix + +* `range` string - The color range of the color space. Can be one of the following values: + * `limited` - Limited color range (RGB values ranging from 16 to 235) + * `full` - Full color range (RGB values from 0 to 255) + * `derived` - Range defined by the transfer function and matrix + * `invalid` - Invalid range + +## Common `ColorSpace` definitions + +### Standard Color Spaces + +**sRGB**: + + ```js + const cs = { + primaries: 'bt709', + transfer: 'srgb', + matrix: 'rgb', + range: 'full' + } + ``` + +**Display P3**: + + ```js + const cs = { + primaries: 'p3', + transfer: 'srgb', + matrix: 'rgb', + range: 'full' + } + ``` + +**XYZ D50**: + + ```js + const cs = { + primaries: 'xyz-d50', + transfer: 'linear', + matrix: 'rgb', + range: 'full' + } + ``` + +### HDR Color Spaces + +**Extended sRGB** (extends sRGB to all real values): + + ```js + const cs = { + primaries: 'bt709', + transfer: 'srgb-hdr', + matrix: 'rgb', + range: 'full' + } + ``` + +**scRGB Linear** (linear transfer function for all real values): + + ```js + const cs = { + primaries: 'bt709', + transfer: 'linear-hdr', + matrix: 'rgb', + range: 'full' + } + ``` + +**scRGB Linear 80 Nits** (with an SDR white level of 80 nits): + + ```js + const cs = { + primaries: 'bt709', + transfer: 'scrgb-linear-80-nits', + matrix: 'rgb', + range: 'full' + } + ``` + +**HDR10** (BT.2020 primaries with PQ transfer function): + + ```js + const cs = { + primaries: 'bt2020', + transfer: 'pq', + matrix: 'rgb', + range: 'full' + } + ``` + +**HLG** (BT.2020 primaries with HLG transfer function): + + ```js + const cs = { + primaries: 'bt2020', + transfer: 'hlg', + matrix: 'rgb', + range: 'full' + } + ``` + +### Video Color Spaces + +**Rec. 601** (SDTV): + + ```js + const cs = { + primaries: 'smpte170m', + transfer: 'smpte170m', + matrix: 'smpte170m', + range: 'limited' + } + ``` + +**Rec. 709** (HDTV): + + ```js + const cs = { + primaries: 'bt709', + transfer: 'bt709', + matrix: 'bt709', + range: 'limited' + } + ``` + +**JPEG** (typical color space for JPEG images): + + ```js + const cs = { + primaries: 'bt709', + transfer: 'srgb', + matrix: 'smpte170m', + range: 'full' + } + ``` diff --git a/docs/api/structures/cookie.md b/docs/api/structures/cookie.md index 5cd84074921b0..a314cf84f5d7d 100644 --- a/docs/api/structures/cookie.md +++ b/docs/api/structures/cookie.md @@ -1,15 +1,15 @@ # Cookie Object -* `name` String - The name of the cookie. -* `value` String - The value of the cookie. -* `domain` String (optional) - The domain of the cookie; this will be normalized with a preceding dot so that it's also valid for subdomains. -* `hostOnly` Boolean (optional) - Whether the cookie is a host-only cookie; this will only be `true` if no domain was passed. -* `path` String (optional) - The path of the cookie. -* `secure` Boolean (optional) - Whether the cookie is marked as secure. -* `httpOnly` Boolean (optional) - Whether the cookie is marked as HTTP only. -* `session` Boolean (optional) - Whether the cookie is a session cookie or a persistent +* `name` string - The name of the cookie. +* `value` string - The value of the cookie. +* `domain` string (optional) - The domain of the cookie; this will be normalized with a preceding dot so that it's also valid for subdomains. +* `hostOnly` boolean (optional) - Whether the cookie is a host-only cookie; this will only be `true` if no domain was passed. +* `path` string (optional) - The path of the cookie. +* `secure` boolean (optional) - Whether the cookie is marked as secure. +* `httpOnly` boolean (optional) - Whether the cookie is marked as HTTP only. +* `session` boolean (optional) - Whether the cookie is a session cookie or a persistent cookie with an expiration date. * `expirationDate` Double (optional) - The expiration date of the cookie as the number of seconds since the UNIX epoch. Not provided for session cookies. -* `sameSite` String - The [Same Site](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#SameSite_cookies) policy applied to this cookie. Can be `unspecified`, `no_restriction`, `lax` or `strict`. +* `sameSite` string - The [Same Site](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#SameSite_cookies) policy applied to this cookie. Can be `unspecified`, `no_restriction`, `lax` or `strict`. diff --git a/docs/api/structures/cpu-usage.md b/docs/api/structures/cpu-usage.md index 4d896ee2dbe0c..645da762bab67 100644 --- a/docs/api/structures/cpu-usage.md +++ b/docs/api/structures/cpu-usage.md @@ -1,7 +1,9 @@ # CPUUsage Object -* `percentCPUUsage` Number - Percentage of CPU used since the last call to getCPUUsage. +* `percentCPUUsage` number - Percentage of CPU used since the last call to getCPUUsage. First call returns 0. -* `idleWakeupsPerSecond` Number - The number of average idle CPU wakeups per second +* `cumulativeCPUUsage` number (optional) - Total seconds of CPU time used since process + startup. +* `idleWakeupsPerSecond` number - The number of average idle CPU wakeups per second since the last call to getCPUUsage. First call returns 0. Will always return 0 on Windows. diff --git a/docs/api/structures/crash-report.md b/docs/api/structures/crash-report.md index 5248cba8043f2..c5de28a1a6f1f 100644 --- a/docs/api/structures/crash-report.md +++ b/docs/api/structures/crash-report.md @@ -1,4 +1,4 @@ # CrashReport Object * `date` Date -* `id` String +* `id` string diff --git a/docs/api/structures/custom-scheme.md b/docs/api/structures/custom-scheme.md index 7034a98eb861a..f5b2f709211ad 100644 --- a/docs/api/structures/custom-scheme.md +++ b/docs/api/structures/custom-scheme.md @@ -1,11 +1,15 @@ # CustomScheme Object -* `scheme` String - Custom schemes to be registered with options. +* `scheme` string - Custom schemes to be registered with options. * `privileges` Object (optional) - * `standard` Boolean (optional) - Default false. - * `secure` Boolean (optional) - Default false. - * `bypassCSP` Boolean (optional) - Default false. - * `allowServiceWorkers` Boolean (optional) - Default false. - * `supportFetchAPI` Boolean (optional) - Default false. - * `corsEnabled` Boolean (optional) - Default false. - * `stream` Boolean (optional) - Default false. + * `standard` boolean (optional) - Default false. + * `secure` boolean (optional) - Default false. + * `bypassCSP` boolean (optional) - Default false. + * `allowServiceWorkers` boolean (optional) - Default false. + * `supportFetchAPI` boolean (optional) - Default false. + * `corsEnabled` boolean (optional) - Default false. + * `stream` boolean (optional) - Default false. + * `codeCache` boolean (optional) - Enable V8 code cache for the scheme, only + works when `standard` is also set to true. Default false. + * `allowExtensions` boolean (optional) - Allow Chrome extensions to be used + on pages served over this protocol. Default false. diff --git a/docs/api/structures/desktop-capturer-source.md b/docs/api/structures/desktop-capturer-source.md index 2f11197b058fd..e898ebd523628 100644 --- a/docs/api/structures/desktop-capturer-source.md +++ b/docs/api/structures/desktop-capturer-source.md @@ -1,10 +1,13 @@ # DesktopCapturerSource Object -* `id` String - The identifier of a window or screen that can be used as a +* `id` string - The identifier of a window or screen that can be used as a `chromeMediaSourceId` constraint when calling - [`navigator.webkitGetUserMedia`]. The format of the identifier will be - `window:XX` or `screen:XX`, where `XX` is a random generated number. -* `name` String - A screen source will be named either `Entire Screen` or + [`navigator.getUserMedia`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/getUserMedia). The format of the identifier will be + `window:XX:YY` or `screen:ZZ:0`. XX is the windowID/handle. YY is 1 for + the current process, and 0 for all others. ZZ is a sequential number + that represents the screen, and it does not equal to the index in the + source's name. +* `name` string - A screen source will be named either `Entire Screen` or `Screen <index>`, while the name of a window source will match the window title. * `thumbnail` [NativeImage](../native-image.md) - A thumbnail image. **Note:** @@ -12,7 +15,7 @@ `thumbnailSize` specified in the `options` passed to `desktopCapturer.getSources`. The actual size depends on the scale of the screen or window. -* `display_id` String - A unique identifier that will correspond to the `id` of +* `display_id` string - A unique identifier that will correspond to the `id` of the matching [Display](display.md) returned by the [Screen API](../screen.md). On some platforms, this is equivalent to the `XX` portion of the `id` field above and on others it will differ. It will be an empty string if not diff --git a/docs/api/structures/display.md b/docs/api/structures/display.md index f10636d05b700..1cc9353787940 100644 --- a/docs/api/structures/display.md +++ b/docs/api/structures/display.md @@ -1,21 +1,25 @@ # Display Object -* `id` Number - Unique identifier associated with the display. -* `rotation` Number - Can be 0, 90, 180, 270, represents screen rotation in +* `accelerometerSupport` string - Can be `available`, `unavailable`, `unknown`. +* `bounds` [Rectangle](rectangle.md) - the bounds of the display in DIP points. +* `colorDepth` number - The number of bits per pixel. +* `colorSpace` string - represent a color space (three-dimensional object which contains all realizable color combinations) for the purpose of color conversions. +* `depthPerComponent` number - The number of bits per color component. +* `detected` boolean - `true` if the display is detected by the system. +* `displayFrequency` number - The display refresh rate. +* `id` number - Unique identifier associated with the display. A value of -1 means the display is invalid or the correct `id` is not yet known, and a value of -10 means the display is a virtual display assigned to a unified desktop. +* `internal` boolean - `true` for an internal display and `false` for an external display. +* `label` string - User-friendly label, determined by the platform. +* `maximumCursorSize` [Size](size.md) - Maximum cursor size in native pixels. +* `nativeOrigin` [Point](point.md) - Returns the display's origin in pixel coordinates. Only available on windowing systems like X11 that position displays in pixel coordinates. +* `rotation` number - Can be 0, 90, 180, 270, represents screen rotation in clock-wise degrees. -* `scaleFactor` Number - Output device's pixel scale factor. -* `touchSupport` String - Can be `available`, `unavailable`, `unknown`. -* `monochrome` Boolean - Whether or not the display is a monochrome display. -* `accelerometerSupport` String - Can be `available`, `unavailable`, `unknown`. -* `colorSpace` String - represent a color space (three-dimensional object which contains all realizable color combinations) for the purpose of color conversions -* `colorDepth` Number - The number of bits per pixel. -* `depthPerComponent` Number - The number of bits per color component. -* `displayFrequency` Number - The display refresh rate. -* `bounds` [Rectangle](rectangle.md) +* `scaleFactor` number - Output device's pixel scale factor. +* `touchSupport` string - Can be `available`, `unavailable`, `unknown`. +* `monochrome` boolean - Whether or not the display is a monochrome display. * `size` [Size](size.md) -* `workArea` [Rectangle](rectangle.md) -* `workAreaSize` [Size](size.md) -* `internal` Boolean - `true` for an internal display and `false` for an external display +* `workArea` [Rectangle](rectangle.md) - the work area of the display in DIP points. +* `workAreaSize` [Size](size.md) - The size of the work area. The `Display` object represents a physical display connected to the system. A fake `Display` may exist on a headless system, or a `Display` may correspond to diff --git a/docs/api/structures/enable-heap-profiling-options.md b/docs/api/structures/enable-heap-profiling-options.md new file mode 100644 index 0000000000000..fff29a366689d --- /dev/null +++ b/docs/api/structures/enable-heap-profiling-options.md @@ -0,0 +1,26 @@ +# EnableHeapProfilingOptions Object + +* `mode` string (optional) - Controls which processes are profiled. Equivalent to `--memlog` in + Chrome. Default is `all`. + * `all` - Profile all processes. + * `browser` - Profile only the browser process. + * `gpu` - Profile only the GPU process. + * `minimal` - Profile only the browser and GPU processes. + * `renderer-sampling` - Profile at most 1 renderer process. Each renderer process has a fixed + probability of being profiled when the renderer process is started or, for existing processes, + when heap profiling is enabled. + * `all-renderers` - Profile all renderer processes. + * `utility-sampling` - Each utility process has a fixed probability of being profiled. + * `all-utilities` - Profile all utility processes. + * `utility-and-browser` - Profile all utility processes and the browser process. +* `samplingRate` number (optional) - Controls the sampling interval in bytes. The lower the + interval, the more precise the profile is. However it comes at the cost of performance. Default + is `100000` (100KB). That is enough to observe allocation sites that make allocations >500KB + total, where total equals to a single allocation size times the number of such allocations at the + same call site. Equivalent to `--memlog-sampling-rate` in Chrome. Must be an integer between + `1000` and `10000000`. +* `stackMode` string (optional) - Controls the type of metadata recorded for each allocation. + Equivalent to `--memlog-stack-mode` in Chrome. Default is `native`. + * `native` - Instruction addresses from unwinding the stack. + * `native-with-thread-names` - Instruction addresses from unwinding the stack. Includes the thread + name as the first frame. diff --git a/docs/api/structures/event.md b/docs/api/structures/event.md deleted file mode 100644 index 415d269feec98..0000000000000 --- a/docs/api/structures/event.md +++ /dev/null @@ -1,3 +0,0 @@ -# Event Object extends `GlobalEvent` - -* `preventDefault` VoidFunction diff --git a/docs/api/structures/extension-info.md b/docs/api/structures/extension-info.md index 966e5b835dc6b..1e8adec301c73 100644 --- a/docs/api/structures/extension-info.md +++ b/docs/api/structures/extension-info.md @@ -1,4 +1,4 @@ # ExtensionInfo Object -* `name` String -* `version` String +* `name` string +* `version` string diff --git a/docs/api/structures/extension.md b/docs/api/structures/extension.md index df9e77c202699..c679398778a38 100644 --- a/docs/api/structures/extension.md +++ b/docs/api/structures/extension.md @@ -1,8 +1,8 @@ # Extension Object -* `id` String +* `id` string * `manifest` any - Copy of the [extension's manifest data](https://developer.chrome.com/extensions/manifest). -* `name` String -* `path` String - The extension's file path. -* `version` String -* `url` String - The extension's `chrome-extension://` URL. +* `name` string +* `path` string - The extension's file path. +* `version` string +* `url` string - The extension's `chrome-extension://` URL. diff --git a/docs/api/structures/file-filter.md b/docs/api/structures/file-filter.md index 014350a60f861..1da4feafd5be4 100644 --- a/docs/api/structures/file-filter.md +++ b/docs/api/structures/file-filter.md @@ -1,4 +1,4 @@ # FileFilter Object -* `name` String -* `extensions` String[] +* `name` string +* `extensions` string[] diff --git a/docs/api/structures/file-path-with-headers.md b/docs/api/structures/file-path-with-headers.md index 9bb1526edcd10..cc55a18fae904 100644 --- a/docs/api/structures/file-path-with-headers.md +++ b/docs/api/structures/file-path-with-headers.md @@ -1,4 +1,4 @@ # FilePathWithHeaders Object -* `path` String - The path to the file to send. -* `headers` Record<string, string> (optional) - Additional headers to be sent. +* `path` string - The path to the file to send. +* `headers` Record\<string, string\> (optional) - Additional headers to be sent. diff --git a/docs/api/structures/filesystem-permission-request.md b/docs/api/structures/filesystem-permission-request.md new file mode 100644 index 0000000000000..8d813708cac7f --- /dev/null +++ b/docs/api/structures/filesystem-permission-request.md @@ -0,0 +1,5 @@ +# FilesystemPermissionRequest Object extends `PermissionRequest` + +* `filePath` string (optional) - The path of the `fileSystem` request. +* `isDirectory` boolean (optional) - Whether the `fileSystem` request is a directory. +* `fileAccessType` string (optional) - The access type of the `fileSystem` request. Can be `writable` or `readable`. diff --git a/docs/api/structures/gpu-feature-status.md b/docs/api/structures/gpu-feature-status.md index b0e5b8d15165b..eb5ee96926a54 100644 --- a/docs/api/structures/gpu-feature-status.md +++ b/docs/api/structures/gpu-feature-status.md @@ -1,18 +1,18 @@ # GPUFeatureStatus Object -* `2d_canvas` String - Canvas. -* `flash_3d` String - Flash. -* `flash_stage3d` String - Flash Stage3D. -* `flash_stage3d_baseline` String - Flash Stage3D Baseline profile. -* `gpu_compositing` String - Compositing. -* `multiple_raster_threads` String - Multiple Raster Threads. -* `native_gpu_memory_buffers` String - Native GpuMemoryBuffers. -* `rasterization` String - Rasterization. -* `video_decode` String - Video Decode. -* `video_encode` String - Video Encode. -* `vpx_decode` String - VPx Video Decode. -* `webgl` String - WebGL. -* `webgl2` String - WebGL2. +* `2d_canvas` string - Canvas. +* `flash_3d` string - Flash. +* `flash_stage3d` string - Flash Stage3D. +* `flash_stage3d_baseline` string - Flash Stage3D Baseline profile. +* `gpu_compositing` string - Compositing. +* `multiple_raster_threads` string - Multiple Raster Threads. +* `native_gpu_memory_buffers` string - Native GpuMemoryBuffers. +* `rasterization` string - Rasterization. +* `video_decode` string - Video Decode. +* `video_encode` string - Video Encode. +* `vpx_decode` string - VPx Video Decode. +* `webgl` string - WebGL. +* `webgl2` string - WebGL2. Possible values: diff --git a/docs/api/structures/hid-device.md b/docs/api/structures/hid-device.md new file mode 100644 index 0000000000000..7c8712cd8605b --- /dev/null +++ b/docs/api/structures/hid-device.md @@ -0,0 +1,16 @@ +# HIDDevice Object + +* `deviceId` string - Unique identifier for the device. +* `name` string - Name of the device. +* `vendorId` Integer - The USB vendor ID. +* `productId` Integer - The USB product ID. +* `serialNumber` string (optional) - The USB device serial number. +* `guid` string (optional) - Unique identifier for the HID interface. A device may have multiple HID interfaces. +* `collections` Object[] - an array of report formats. See [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/HIDDevice/collections) for more. + * `usage` Integer - An integer representing the usage ID component of the HID usage associated with this collection. + * `usagePage` Integer - An integer representing the usage page component of the HID usage associated with this collection. + * `type` Integer - An 8-bit value representing the collection type, which describes a different relationship between the grouped items. + * `children` Object[] - An array of sub-collections which takes the same format as a top-level collection. + * `inputReports` Object[] - An array of inputReport items which represent individual input reports described in this collection. + * `outputReports` Object[] - An array of outputReport items which represent individual output reports described in this collection. + * `featureReports` Object[] - An array of featureReport items which represent individual feature reports described in this collection. diff --git a/docs/api/structures/input-event.md b/docs/api/structures/input-event.md index c7bcb2f4b368a..34b6891faf283 100644 --- a/docs/api/structures/input-event.md +++ b/docs/api/structures/input-event.md @@ -1,6 +1,17 @@ # InputEvent Object -* `modifiers` String[] (optional) - An array of modifiers of the event, can - be `shift`, `control`, `ctrl`, `alt`, `meta`, `command`, `cmd`, `isKeypad`, - `isAutoRepeat`, `leftButtonDown`, `middleButtonDown`, `rightButtonDown`, - `capsLock`, `numLock`, `left`, `right`. +* `type` string - Can be `undefined`, `mouseDown`, `mouseUp`, `mouseMove`, + `mouseEnter`, `mouseLeave`, `contextMenu`, `mouseWheel`, `rawKeyDown`, + `keyDown`, `keyUp`, `char`, `gestureScrollBegin`, `gestureScrollEnd`, + `gestureScrollUpdate`, `gestureFlingStart`, `gestureFlingCancel`, + `gesturePinchBegin`, `gesturePinchEnd`, `gesturePinchUpdate`, + `gestureTapDown`, `gestureShowPress`, `gestureTap`, `gestureTapCancel`, + `gestureShortPress`, `gestureLongPress`, `gestureLongTap`, + `gestureTwoFingerTap`, `gestureTapUnconfirmed`, `gestureDoubleTap`, + `touchStart`, `touchMove`, `touchEnd`, `touchCancel`, `touchScrollStarted`, + `pointerDown`, `pointerUp`, `pointerMove`, `pointerRawUpdate`, + `pointerCancel` or `pointerCausedUaAction`. +* `modifiers` string[] (optional) - An array of modifiers of the event, can + be `shift`, `control`, `ctrl`, `alt`, `meta`, `command`, `cmd`, `iskeypad`, + `isautorepeat`, `leftbuttondown`, `middlebuttondown`, `rightbuttondown`, + `capslock`, `numlock`, `left`, `right`. diff --git a/docs/api/structures/io-counters.md b/docs/api/structures/io-counters.md deleted file mode 100644 index 62ad39a90b098..0000000000000 --- a/docs/api/structures/io-counters.md +++ /dev/null @@ -1,8 +0,0 @@ -# IOCounters Object - -* `readOperationCount` Number - The number of I/O read operations. -* `writeOperationCount` Number - The number of I/O write operations. -* `otherOperationCount` Number - Then number of I/O other operations. -* `readTransferCount` Number - The number of I/O read transfers. -* `writeTransferCount` Number - The number of I/O write transfers. -* `otherTransferCount` Number - Then number of I/O other transfers. diff --git a/docs/api/structures/ipc-main-event.md b/docs/api/structures/ipc-main-event.md index f222de35b86dc..dd9fea6777381 100644 --- a/docs/api/structures/ipc-main-event.md +++ b/docs/api/structures/ipc-main-event.md @@ -1,9 +1,12 @@ # IpcMainEvent Object extends `Event` +* `type` String - Possible values include `frame` +* `processId` Integer - The internal ID of the renderer process that sent this message * `frameId` Integer - The ID of the renderer frame that sent this message * `returnValue` any - Set this to the value to be returned in a synchronous message -* `sender` WebContents - Returns the `webContents` that sent the message -* `ports` MessagePortMain[] - A list of MessagePorts that were transferred with this message +* `sender` [WebContents](../web-contents.md) - Returns the `webContents` that sent the message +* `senderFrame` [WebFrameMain](../web-frame-main.md) | null _Readonly_ - The frame that sent this message. May be `null` if accessed after the frame has either navigated or been destroyed. +* `ports` [MessagePortMain](../message-port-main.md)[] - A list of MessagePorts that were transferred with this message * `reply` Function - A function that will send an IPC message to the renderer frame that sent the original message that you are currently handling. You should use this method to "reply" to the sent message in order to guarantee the reply will go to the correct process and frame. - * `channel` String + * `channel` string * `...args` any[] diff --git a/docs/api/structures/ipc-main-invoke-event.md b/docs/api/structures/ipc-main-invoke-event.md index 235b219c2d6ea..b9cbbfb4fb59f 100644 --- a/docs/api/structures/ipc-main-invoke-event.md +++ b/docs/api/structures/ipc-main-invoke-event.md @@ -1,4 +1,7 @@ # IpcMainInvokeEvent Object extends `Event` +* `type` String - Possible values include `frame` +* `processId` Integer - The internal ID of the renderer process that sent this message * `frameId` Integer - The ID of the renderer frame that sent this message -* `sender` WebContents - Returns the `webContents` that sent the message +* `sender` [WebContents](../web-contents.md) - Returns the `webContents` that sent the message +* `senderFrame` [WebFrameMain](../web-frame-main.md) | null _Readonly_ - The frame that sent this message. May be `null` if accessed after the frame has either navigated or been destroyed. diff --git a/docs/api/structures/ipc-main-service-worker-event.md b/docs/api/structures/ipc-main-service-worker-event.md new file mode 100644 index 0000000000000..00d4ec5f3a6d3 --- /dev/null +++ b/docs/api/structures/ipc-main-service-worker-event.md @@ -0,0 +1,11 @@ +# IpcMainServiceWorkerEvent Object extends `Event` + +* `type` String - Possible values include `service-worker`. +* `serviceWorker` [ServiceWorkerMain](../service-worker-main.md) _Readonly_ - The service worker that sent this message +* `versionId` Number - The service worker version ID. +* `session` Session - The [`Session`](../session.md) instance with which the event is associated. +* `returnValue` any - Set this to the value to be returned in a synchronous message +* `ports` [MessagePortMain](../message-port-main.md)[] - A list of MessagePorts that were transferred with this message +* `reply` Function - A function that will send an IPC message to the renderer frame that sent the original message that you are currently handling. You should use this method to "reply" to the sent message in order to guarantee the reply will go to the correct process and frame. + * `channel` string + * `...args` any[] diff --git a/docs/api/structures/ipc-main-service-worker-invoke-event.md b/docs/api/structures/ipc-main-service-worker-invoke-event.md new file mode 100644 index 0000000000000..9e548dccb2c07 --- /dev/null +++ b/docs/api/structures/ipc-main-service-worker-invoke-event.md @@ -0,0 +1,6 @@ +# IpcMainServiceWorkerInvokeEvent Object extends `Event` + +* `type` String - Possible values include `service-worker`. +* `serviceWorker` [ServiceWorkerMain](../service-worker-main.md) _Readonly_ - The service worker that sent this message +* `versionId` Number - The service worker version ID. +* `session` Session - The [`Session`](../session.md) instance with which the event is associated. diff --git a/docs/api/structures/ipc-renderer-event.md b/docs/api/structures/ipc-renderer-event.md index 1ac2def46d4aa..135834f2098d8 100644 --- a/docs/api/structures/ipc-renderer-event.md +++ b/docs/api/structures/ipc-renderer-event.md @@ -1,7 +1,6 @@ # IpcRendererEvent Object extends `Event` -* `sender` IpcRenderer - The `IpcRenderer` instance that emitted the event originally -* `senderId` Integer - The `webContents.id` that sent the message, you can call `event.sender.sendTo(event.senderId, ...)` to reply to the message, see [ipcRenderer.sendTo][ipc-renderer-sendto] for more information. This only applies to messages sent from a different renderer. Messages sent directly from the main process set `event.senderId` to `0`. -* `ports` MessagePort[] - A list of MessagePorts that were transferred with this message +* `sender` [IpcRenderer](../ipc-renderer.md) - The `IpcRenderer` instance that emitted the event originally +* `ports` [MessagePort][][] - A list of MessagePorts that were transferred with this message -[ipc-renderer-sendto]: ../ipc-renderer.md#ipcrenderersendtowebcontentsid-channel-args +[MessagePort]: https://developer.mozilla.org/en-US/docs/Web/API/MessagePort diff --git a/docs/api/structures/jump-list-category.md b/docs/api/structures/jump-list-category.md index 07627e78c98e7..ad5747ceed62f 100644 --- a/docs/api/structures/jump-list-category.md +++ b/docs/api/structures/jump-list-category.md @@ -1,6 +1,6 @@ # JumpListCategory Object -* `type` String (optional) - One of the following: +* `type` string (optional) - One of the following: * `tasks` - Items in this category will be placed into the standard `Tasks` category. There can be only one such category, and it will always be displayed at the bottom of the Jump List. @@ -10,12 +10,18 @@ of the category and its items are set by Windows. Items may be added to this category indirectly using `app.addRecentDocument(path)`. * `custom` - Displays tasks or file links, `name` must be set by the app. -* `name` String (optional) - Must be set if `type` is `custom`, otherwise it should be +* `name` string (optional) - Must be set if `type` is `custom`, otherwise it should be omitted. * `items` JumpListItem[] (optional) - Array of [`JumpListItem`](jump-list-item.md) objects if `type` is `tasks` or `custom`, otherwise it should be omitted. -**Note:** If a `JumpListCategory` object has neither the `type` nor the `name` -property set then its `type` is assumed to be `tasks`. If the `name` property -is set but the `type` property is omitted then the `type` is assumed to be -`custom`. +> [!NOTE] +> If a `JumpListCategory` object has neither the `type` nor the `name` +> property set then its `type` is assumed to be `tasks`. If the `name` property +> is set but the `type` property is omitted then the `type` is assumed to be +> `custom`. + +> [!NOTE] +> The maximum length of a Jump List item's `description` property is +> 260 characters. Beyond this limit, the item will not be added to the Jump +> List, nor will it be displayed. diff --git a/docs/api/structures/jump-list-item.md b/docs/api/structures/jump-list-item.md index d75637cb472dc..1731602215bb3 100644 --- a/docs/api/structures/jump-list-item.md +++ b/docs/api/structures/jump-list-item.md @@ -1,29 +1,29 @@ # JumpListItem Object -* `type` String (optional) - One of the following: +* `type` string (optional) - One of the following: * `task` - A task will launch an app with specific arguments. * `separator` - Can be used to separate items in the standard `Tasks` category. * `file` - A file link will open a file using the app that created the Jump List, for this to work the app must be registered as a handler for the file type (though it doesn't have to be the default handler). -* `path` String (optional) - Path of the file to open, should only be set if `type` is +* `path` string (optional) - Path of the file to open, should only be set if `type` is `file`. -* `program` String (optional) - Path of the program to execute, usually you should +* `program` string (optional) - Path of the program to execute, usually you should specify `process.execPath` which opens the current program. Should only be set if `type` is `task`. -* `args` String (optional) - The command line arguments when `program` is executed. Should +* `args` string (optional) - The command line arguments when `program` is executed. Should only be set if `type` is `task`. -* `title` String (optional) - The text to be displayed for the item in the Jump List. +* `title` string (optional) - The text to be displayed for the item in the Jump List. Should only be set if `type` is `task`. -* `description` String (optional) - Description of the task (displayed in a tooltip). - Should only be set if `type` is `task`. -* `iconPath` String (optional) - The absolute path to an icon to be displayed in a +* `description` string (optional) - Description of the task (displayed in a tooltip). + Should only be set if `type` is `task`. Maximum length 260 characters. +* `iconPath` string (optional) - The absolute path to an icon to be displayed in a Jump List, which can be an arbitrary resource file that contains an icon (e.g. `.ico`, `.exe`, `.dll`). You can usually specify `process.execPath` to show the program icon. -* `iconIndex` Number (optional) - The index of the icon in the resource file. If a +* `iconIndex` number (optional) - The index of the icon in the resource file. If a resource file contains multiple icons this value can be used to specify the zero-based index of the icon that should be displayed for this task. If a resource file contains only one icon, this property should be set to zero. -* `workingDirectory` String (optional) - The working directory. Default is empty. +* `workingDirectory` string (optional) - The working directory. Default is empty. diff --git a/docs/api/structures/keyboard-event.md b/docs/api/structures/keyboard-event.md index 209cdefebecf1..b68c4dad136e0 100644 --- a/docs/api/structures/keyboard-event.md +++ b/docs/api/structures/keyboard-event.md @@ -1,7 +1,7 @@ # KeyboardEvent Object -* `ctrlKey` Boolean (optional) - whether the Control key was used in an accelerator to trigger the Event -* `metaKey` Boolean (optional) - whether a meta key was used in an accelerator to trigger the Event -* `shiftKey` Boolean (optional) - whether a Shift key was used in an accelerator to trigger the Event -* `altKey` Boolean (optional) - whether an Alt key was used in an accelerator to trigger the Event -* `triggeredByAccelerator` Boolean (optional) - whether an accelerator was used to trigger the event as opposed to another user gesture like mouse click +* `ctrlKey` boolean (optional) - whether the Control key was used in an accelerator to trigger the Event +* `metaKey` boolean (optional) - whether a meta key was used in an accelerator to trigger the Event +* `shiftKey` boolean (optional) - whether a Shift key was used in an accelerator to trigger the Event +* `altKey` boolean (optional) - whether an Alt key was used in an accelerator to trigger the Event +* `triggeredByAccelerator` boolean (optional) - whether an accelerator was used to trigger the event as opposed to another user gesture like mouse click diff --git a/docs/api/structures/keyboard-input-event.md b/docs/api/structures/keyboard-input-event.md index 96ce3bf77f458..8ee819ad0ce8a 100644 --- a/docs/api/structures/keyboard-input-event.md +++ b/docs/api/structures/keyboard-input-event.md @@ -1,6 +1,6 @@ # KeyboardInputEvent Object extends `InputEvent` -* `type` String - The type of the event, can be `keyDown`, `keyUp` or `char`. -* `keyCode` String - The character that will be sent - as the keyboard event. Should only use the valid key codes in - [Accelerator](../accelerator.md). +* `type` string - The type of the event, can be `rawKeyDown`, `keyDown`, `keyUp` or `char`. +* `keyCode` string - The character that will be sent + as the keyboard event. Should only use valid [Accelerator](../../tutorial/keyboard-shortcuts.md#accelerators) + key codes. diff --git a/docs/api/structures/media-access-permission-request.md b/docs/api/structures/media-access-permission-request.md new file mode 100644 index 0000000000000..6a9cca661adbf --- /dev/null +++ b/docs/api/structures/media-access-permission-request.md @@ -0,0 +1,5 @@ +# MediaAccessPermissionRequest Object extends `PermissionRequest` + +* `securityOrigin` string (optional) - The security origin of the request. +* `mediaTypes` string[] (optional) - The types of media access being requested - elements can be `video` + or `audio`. diff --git a/docs/api/structures/memory-usage-details.md b/docs/api/structures/memory-usage-details.md index d77e07dedfc26..2b55f98b6ee62 100644 --- a/docs/api/structures/memory-usage-details.md +++ b/docs/api/structures/memory-usage-details.md @@ -1,5 +1,5 @@ # MemoryUsageDetails Object -* `count` Number -* `size` Number -* `liveSize` Number +* `count` number +* `size` number +* `liveSize` number diff --git a/docs/api/structures/mime-typed-buffer.md b/docs/api/structures/mime-typed-buffer.md index 494de5172008b..0a8459335c7bb 100644 --- a/docs/api/structures/mime-typed-buffer.md +++ b/docs/api/structures/mime-typed-buffer.md @@ -1,5 +1,5 @@ # MimeTypedBuffer Object -* `mimeType` String (optional) - MIME type of the buffer. -* `charset` String (optional) - Charset of the buffer. +* `mimeType` string (optional) - MIME type of the buffer. +* `charset` string (optional) - Charset of the buffer. * `data` Buffer - The actual Buffer content. diff --git a/docs/api/structures/mouse-input-event.md b/docs/api/structures/mouse-input-event.md index 879f669cf2ca1..8bc04ac48fe36 100644 --- a/docs/api/structures/mouse-input-event.md +++ b/docs/api/structures/mouse-input-event.md @@ -1,10 +1,10 @@ # MouseInputEvent Object extends `InputEvent` -* `type` String - The type of the event, can be `mouseDown`, +* `type` string - The type of the event, can be `mouseDown`, `mouseUp`, `mouseEnter`, `mouseLeave`, `contextMenu`, `mouseWheel` or `mouseMove`. * `x` Integer * `y` Integer -* `button` String (optional) - The button pressed, can be `left`, `middle`, `right`. +* `button` string (optional) - The button pressed, can be `left`, `middle`, `right`. * `globalX` Integer (optional) * `globalY` Integer (optional) * `movementX` Integer (optional) diff --git a/docs/api/structures/mouse-wheel-input-event.md b/docs/api/structures/mouse-wheel-input-event.md index 50540e7cd8786..6a1c71ba1f75a 100644 --- a/docs/api/structures/mouse-wheel-input-event.md +++ b/docs/api/structures/mouse-wheel-input-event.md @@ -1,11 +1,11 @@ # MouseWheelInputEvent Object extends `MouseInputEvent` -* `type` String - The type of the event, can be `mouseWheel`. +* `type` string - The type of the event, can be `mouseWheel`. * `deltaX` Integer (optional) * `deltaY` Integer (optional) * `wheelTicksX` Integer (optional) * `wheelTicksY` Integer (optional) * `accelerationRatioX` Integer (optional) * `accelerationRatioY` Integer (optional) -* `hasPreciseScrollingDeltas` Boolean (optional) -* `canScroll` Boolean (optional) +* `hasPreciseScrollingDeltas` boolean (optional) +* `canScroll` boolean (optional) diff --git a/docs/api/structures/navigation-entry.md b/docs/api/structures/navigation-entry.md new file mode 100644 index 0000000000000..72afc3d30d410 --- /dev/null +++ b/docs/api/structures/navigation-entry.md @@ -0,0 +1,7 @@ +# NavigationEntry Object + +* `url` string +* `title` string +* `pageState` string (optional) - A base64 encoded data string containing Chromium page state + including information like the current scroll position or form values. It is committed by + Chromium before a navigation event and on a regular interval. diff --git a/docs/api/structures/new-window-web-contents-event.md b/docs/api/structures/new-window-web-contents-event.md deleted file mode 100644 index b56da02603b89..0000000000000 --- a/docs/api/structures/new-window-web-contents-event.md +++ /dev/null @@ -1,3 +0,0 @@ -# NewWindowWebContentsEvent Object extends `Event` - -* `newGuest` BrowserWindow (optional) diff --git a/docs/api/structures/notification-action.md b/docs/api/structures/notification-action.md index e5e14f87f2290..24229682daaad 100644 --- a/docs/api/structures/notification-action.md +++ b/docs/api/structures/notification-action.md @@ -1,13 +1,15 @@ # NotificationAction Object -* `type` String - The type of action, can be `button`. -* `text` String (optional) - The label for the given action. +* `type` string - The type of action, can be `button` or `selection`. `selection` is only supported on Windows. +* `text` string (optional) - The label for the given action. +* `items` string[] (optional) _Windows_ - The list of items for the `selection` action `type`. ## Platform / Action Support | Action Type | Platform Support | Usage of `text` | Default `text` | Limitations | |-------------|------------------|-----------------|----------------|-------------| -| `button` | macOS | Used as the label for the button | "Show" (or a localized string by system default if first of such `button`, otherwise empty) | Only the first one is used. If multiple are provided, those beyond the first will be listed as additional actions (displayed when mouse active over the action button). Any such action also is incompatible with `hasReply` and will be ignored if `hasReply` is `true`. | +| `button` | macOS, Windows | Used as the label for the button | "Show" on macOS (localized) if first `button`, otherwise empty; Windows uses provided `text` | macOS: Only the first one is used as primary; others shown as additional actions (hover). Incompatible with `hasReply` (beyond first ignored). | +| `selection` | Windows | Used as the label for the submit button for the selection menu | "Select" | Requires an `items` array property specifying option labels. Emits the `action` event with `(index, selectedIndex)` where `selectedIndex` is the chosen option (>= 0). Ignored on platforms that do not support selection actions. | ### Button support on macOS @@ -15,6 +17,37 @@ In order for extra notification buttons to work on macOS your app must meet the following criteria. * App is signed -* App has it's `NSUserNotificationAlertStyle` set to `alert` in the `Info.plist`. +* App has its `NSUserNotificationAlertStyle` set to `alert` in the `Info.plist`. If either of these requirements are not met the button won't appear. + +### Selection support on Windows + +To add a selection (combo box) style action, include an action with `type: 'selection'`, a `text` label for the submit button, and an `items` array of strings: + +```js +const { Notification, app } = require('electron') + +app.whenReady().then(() => { + const items = ['One', 'Two', 'Three'] + const n = new Notification({ + title: 'Choose an option', + actions: [{ + type: 'selection', + text: 'Apply', + items + }] + }) + + n.on('action', (e) => { + console.log(`User triggered action at index: ${e.actionIndex}`) + if (e.selectionIndex > 0) { + console.log(`User chose selection item '${items[e.selectionIndex]}'`) + } + }) + + n.show() +}) +``` + +When the user activates the selection action, the notification's `action` event will be emitted with two parameters: `actionIndex` (the action's index in the `actions` array) and `selectedIndex` (the zero-based index of the chosen item, or `-1` if unavailable). On non-Windows platforms selection actions are ignored. diff --git a/docs/api/structures/notification-response.md b/docs/api/structures/notification-response.md index f6c3e1081a22f..eb5f1882a5d21 100644 --- a/docs/api/structures/notification-response.md +++ b/docs/api/structures/notification-response.md @@ -1,7 +1,7 @@ # NotificationResponse Object -* `actionIdentifier` String - The identifier string of the action that the user selected. -* `date` Number - The delivery date of the notification. -* `identifier` String - The unique identifier for this notification request. -* `userInfo` Record<String, any> - A dictionary of custom information associated with the notification. -* `userText` String (optional) - The text entered or chosen by the user. +* `actionIdentifier` string - The identifier string of the action that the user selected. +* `date` number - The delivery date of the notification. +* `identifier` string - The unique identifier for this notification request. +* `userInfo` Record\<string, any\> - A dictionary of custom information associated with the notification. +* `userText` string (optional) - The text entered or chosen by the user. diff --git a/docs/api/structures/offscreen-shared-texture.md b/docs/api/structures/offscreen-shared-texture.md new file mode 100644 index 0000000000000..e434287747409 --- /dev/null +++ b/docs/api/structures/offscreen-shared-texture.md @@ -0,0 +1,21 @@ +# OffscreenSharedTexture Object + +* `textureInfo` Object - The shared texture info. + * `widgetType` string - The widget type of the texture. Can be `popup` or `frame`. + * `pixelFormat` string - The pixel format of the texture. + * `rgba` - The texture format is 8-bit unorm RGBA. + * `bgra` - The texture format is 8-bit unorm BGRA. + * `rgbaf16` - The texture format is 16-bit float RGBA. + * `codedSize` [Size](size.md) - The full dimensions of the video frame. + * `colorSpace` [ColorSpace](color-space.md) - The color space of the video frame. + * `visibleRect` [Rectangle](rectangle.md) - A subsection of [0, 0, codedSize.width, codedSize.height]. In OSR case, it is expected to have the full section area. + * `contentRect` [Rectangle](rectangle.md) - The region of the video frame that capturer would like to populate. In OSR case, it is the same with `dirtyRect` that needs to be painted. + * `timestamp` number - The time in microseconds since the capture start. + * `metadata` Object - Extra metadata. See comments in src\media\base\video_frame_metadata.h for accurate details. + * `captureUpdateRect` [Rectangle](rectangle.md) (optional) - Updated area of frame, can be considered as the `dirty` area. + * `regionCaptureRect` [Rectangle](rectangle.md) (optional) - May reflect the frame's contents origin if region capture is used internally. + * `sourceSize` [Rectangle](rectangle.md) (optional) - Full size of the source frame. + * `frameCount` number (optional) - The increasing count of captured frame. May contain gaps if frames are dropped between two consecutively received frames. + * `handle` [SharedTextureHandle](shared-texture-handle.md) - The shared texture handle data. +* `release` Function - Release the resources. The `texture` cannot be directly passed to another process, users need to maintain texture lifecycles in + main process, but it is safe to pass the `textureInfo` to another process. Only a limited number of textures can exist at the same time, so it's important that you call `texture.release()` as soon as you're done with the texture. diff --git a/docs/api/structures/open-external-permission-request.md b/docs/api/structures/open-external-permission-request.md new file mode 100644 index 0000000000000..d7b7f68fc9cfc --- /dev/null +++ b/docs/api/structures/open-external-permission-request.md @@ -0,0 +1,3 @@ +# OpenExternalPermissionRequest Object extends `PermissionRequest` + +* `externalURL` string (optional) - The url of the `openExternal` request. diff --git a/docs/api/structures/payment-discount.md b/docs/api/structures/payment-discount.md new file mode 100644 index 0000000000000..95e095397808b --- /dev/null +++ b/docs/api/structures/payment-discount.md @@ -0,0 +1,7 @@ +# PaymentDiscount Object + +* `identifier` string - A string used to uniquely identify a discount offer for a product. +* `keyIdentifier` string - A string that identifies the key used to generate the signature. +* `nonce` string - A universally unique ID (UUID) value that you define. +* `signature` string - A UTF-8 string representing the properties of a specific discount offer, cryptographically signed. +* `timestamp` number - The date and time of the signature's creation in milliseconds, formatted in Unix epoch time. diff --git a/docs/api/structures/permission-request.md b/docs/api/structures/permission-request.md new file mode 100644 index 0000000000000..4858f84a324ce --- /dev/null +++ b/docs/api/structures/permission-request.md @@ -0,0 +1,4 @@ +# PermissionRequest Object + +* `requestingUrl` string - The last URL the requesting frame loaded. +* `isMainFrame` boolean - Whether the frame making the request is the main frame. diff --git a/docs/api/structures/point.md b/docs/api/structures/point.md index 34e85ef6e55e4..9294dc7db54ba 100644 --- a/docs/api/structures/point.md +++ b/docs/api/structures/point.md @@ -1,8 +1,9 @@ # Point Object -* `x` Number -* `y` Number +* `x` number +* `y` number -**Note:** Both `x` and `y` must be whole integers, when providing a point object -as input to an Electron API we will automatically round your `x` and `y` values -to the nearest whole integer. +> [!NOTE] +> Both `x` and `y` must be whole integers, when providing a point object +> as input to an Electron API we will automatically round your `x` and `y` values +> to the nearest whole integer. diff --git a/docs/api/structures/post-body.md b/docs/api/structures/post-body.md index baa479dda3f05..0488988ce456e 100644 --- a/docs/api/structures/post-body.md +++ b/docs/api/structures/post-body.md @@ -1,23 +1,9 @@ # PostBody Object -* `data` Array<[PostData](./post-data.md)> - The post data to be sent to the +* `data` ([UploadRawData](upload-raw-data.md) | [UploadFile](upload-file.md))[] - The post data to be sent to the new window. -* `contentType` String - The `content-type` header used for the data. One of +* `contentType` string - The `content-type` header used for the data. One of `application/x-www-form-urlencoded` or `multipart/form-data`. Corresponds to the `enctype` attribute of the submitted HTML form. -* `boundary` String (optional) - The boundary used to separate multiple parts of +* `boundary` string (optional) - The boundary used to separate multiple parts of the message. Only valid when `contentType` is `multipart/form-data`. - -Note that keys starting with `--` are not currently supported. For example, this will errantly submit as `multipart/form-data` when `nativeWindowOpen` is set to `false` in webPreferences: - -```html -<form - target="_blank" - method="POST" - enctype="application/x-www-form-urlencoded" - action="https://postman-echo.com/post" -> - <input type="text" name="--theKey"> - <input type="submit"> -</form> -``` diff --git a/docs/api/structures/post-data.md b/docs/api/structures/post-data.md deleted file mode 100644 index b63f20a95051b..0000000000000 --- a/docs/api/structures/post-data.md +++ /dev/null @@ -1,21 +0,0 @@ -# PostData Object - -* `type` String - One of the following: - * `rawData` - The data is available as a `Buffer`, in the `rawData` field. - * `file` - The object represents a file. The `filePath`, `offset`, `length` - and `modificationTime` fields will be used to describe the file. - * `blob` - The object represents a `Blob`. The `blobUUID` field will be used - to describe the `Blob`. -* `bytes` String (optional) - The raw bytes of the post data in a `Buffer`. - Required for the `rawData` type. -* `filePath` String (optional) - The path of the file being uploaded. Required - for the `file` type. -* `blobUUID` String (optional) - The `UUID` of the `Blob` being uploaded. - Required for the `blob` type. -* `offset` Integer (optional) - The offset from the beginning of the file being - uploaded, in bytes. Only valid for `file` types. -* `length` Integer (optional) - The length of the file being uploaded, in bytes. - If set to `-1`, the whole file will be uploaded. Only valid for `file` types. -* `modificationTime` Double (optional) - The modification time of the file - represented by a double, which is the number of seconds since the `UNIX Epoch` - (Jan 1, 1970). Only valid for `file` types. diff --git a/docs/api/structures/preload-script-registration.md b/docs/api/structures/preload-script-registration.md new file mode 100644 index 0000000000000..efb5be49ee002 --- /dev/null +++ b/docs/api/structures/preload-script-registration.md @@ -0,0 +1,6 @@ +# PreloadScriptRegistration Object + +* `type` string - Context type where the preload script will be executed. + Possible values include `frame` or `service-worker`. +* `id` string (optional) - Unique ID of preload script. Defaults to a random UUID. +* `filePath` string - Path of the script file. Must be an absolute path. diff --git a/docs/api/structures/preload-script.md b/docs/api/structures/preload-script.md new file mode 100644 index 0000000000000..e29812e046480 --- /dev/null +++ b/docs/api/structures/preload-script.md @@ -0,0 +1,6 @@ +# PreloadScript Object + +* `type` string - Context type where the preload script will be executed. + Possible values include `frame` or `service-worker`. +* `id` string - Unique ID of preload script. +* `filePath` string - Path of the script file. Must be an absolute path. diff --git a/docs/api/structures/printer-info.md b/docs/api/structures/printer-info.md index 7878b4b73b12e..958d99993c8ad 100644 --- a/docs/api/structures/printer-info.md +++ b/docs/api/structures/printer-info.md @@ -1,26 +1,24 @@ # PrinterInfo Object -* `name` String - the name of the printer as understood by the OS. -* `displayName` String - the name of the printer as shown in Print Preview. -* `description` String - a longer description of the printer's type. -* `status` Number - the current status of the printer. -* `isDefault` Boolean - whether or not a given printer is set as the default printer on the OS. +* `name` string - the name of the printer as understood by the OS. +* `displayName` string - the name of the printer as shown in Print Preview. +* `description` string - a longer description of the printer's type. * `options` Object - an object containing a variable number of platform-specific printer information. -The number represented by `status` means different things on different platforms: on Windows its potential values can be found [here](https://docs.microsoft.com/en-us/windows/win32/printdocs/printer-info-2), and on Linux and macOS they can be found [here](https://www.cups.org/doc/cupspm.html). +The number represented by `status` means different things on different platforms: on Windows its potential values can be found [here](https://learn.microsoft.com/en-us/windows/win32/printdocs/printer-info-2), and on Linux and macOS they can be found [here](https://www.cups.org/doc/cupspm.html). ## Example Below is an example of some of the additional options that may be set which may be different on each platform. -```javascript +<!-- eslint-skip --> + +```js { name: 'Austin_4th_Floor_Printer___C02XK13BJHD4', displayName: 'Austin 4th Floor Printer @ C02XK13BJHD4', description: 'TOSHIBA ColorMFP', - status: 3, - isDefault: false, options: { copies: '1', 'device-uri': 'dnssd://Austin%204th%20Floor%20Printer%20%40%20C02XK13BJHD4._ipps._tcp.local./?uuid=71687f1e-1147-3274-6674-22de61b110bd', diff --git a/docs/api/structures/process-metric.md b/docs/api/structures/process-metric.md index 764912bca0f6b..ca5ef674d3037 100644 --- a/docs/api/structures/process-metric.md +++ b/docs/api/structures/process-metric.md @@ -1,7 +1,7 @@ # ProcessMetric Object * `pid` Integer - Process id of the process. -* `type` String - Process type. One of the following values: +* `type` string - Process type. One of the following values: * `Browser` * `Tab` * `Utility` @@ -11,17 +11,17 @@ * `Pepper Plugin` * `Pepper Plugin Broker` * `Unknown` -* `serviceName` String (optional) - The non-localized name of the process. -* `name` String (optional) - The name of the process. +* `serviceName` string (optional) - The non-localized name of the process. +* `name` string (optional) - The name of the process. Examples for utility: `Audio Service`, `Content Decryption Module Service`, `Network Service`, `Video Capture`, etc. * `cpu` [CPUUsage](cpu-usage.md) - CPU usage of the process. -* `creationTime` Number - Creation time for this process. +* `creationTime` number - Creation time for this process. The time is represented as number of milliseconds since epoch. Since the `pid` can be reused after a process dies, it is useful to use both the `pid` and the `creationTime` to uniquely identify a process. * `memory` [MemoryInfo](memory-info.md) - Memory information for the process. -* `sandboxed` Boolean (optional) _macOS_ _Windows_ - Whether the process is sandboxed on OS level. -* `integrityLevel` String (optional) _Windows_ - One of the following values: +* `sandboxed` boolean (optional) _macOS_ _Windows_ - Whether the process is sandboxed on OS level. +* `integrityLevel` string (optional) _Windows_ - One of the following values: * `untrusted` * `low` * `medium` diff --git a/docs/api/structures/product-discount.md b/docs/api/structures/product-discount.md new file mode 100644 index 0000000000000..d0debc5f872c2 --- /dev/null +++ b/docs/api/structures/product-discount.md @@ -0,0 +1,9 @@ +# ProductDiscount Object + +* `identifier` string - A string used to uniquely identify a discount offer for a product. +* `type` number - The type of discount offer. +* `price` number - The discount price of the product in the local currency. +* `priceLocale` string - The locale used to format the discount price of the product. +* `paymentMode` string - The payment mode for this product discount. Can be `payAsYouGo`, `payUpFront`, or `freeTrial`. +* `numberOfPeriods` number - An integer that indicates the number of periods the product discount is available. +* `subscriptionPeriod` [ProductSubscriptionPeriod](product-subscription-period.md) (optional) - An object that defines the period for the product discount. diff --git a/docs/api/structures/product-subscription-period.md b/docs/api/structures/product-subscription-period.md new file mode 100644 index 0000000000000..3551f80d054e3 --- /dev/null +++ b/docs/api/structures/product-subscription-period.md @@ -0,0 +1,4 @@ +# ProductSubscriptionPeriod Object + +* `numberOfUnits` number - The number of units per subscription period. +* `unit` string - The increment of time that a subscription period is specified in. Can be `day`, `week`, `month`, `year`. diff --git a/docs/api/structures/product.md b/docs/api/structures/product.md index 9180f597a0446..5268e4f336fa8 100644 --- a/docs/api/structures/product.md +++ b/docs/api/structures/product.md @@ -1,11 +1,16 @@ # Product Object -* `productIdentifier` String - The string that identifies the product to the Apple App Store. -* `localizedDescription` String - A description of the product. -* `localizedTitle` String - The name of the product. -* `contentVersion` String - A string that identifies the version of the content. -* `contentLengths` Number[] - The total size of the content, in bytes. -* `price` Number - The cost of the product in the local currency. -* `formattedPrice` String - The locale formatted price of the product. -* `currencyCode` String - 3 character code presenting a product's currency based on the ISO 4217 standard. -* `isDownloadable` Boolean - A Boolean value that indicates whether the App Store has downloadable content for this product. `true` if at least one file has been associated with the product. +* `productIdentifier` string - The string that identifies the product to the Apple App Store. +* `localizedDescription` string - A description of the product. +* `localizedTitle` string - The name of the product. +* `price` number - The cost of the product in the local currency. +* `formattedPrice` string - The locale formatted price of the product. +* `currencyCode` string - 3 character code presenting a product's currency based on the ISO 4217 standard. +* `introductoryPrice` [ProductDiscount](product-discount.md) (optional) - The object containing introductory price information for the product. +available for the product. +* `discounts` [ProductDiscount](product-discount.md)[] - An array of discount offers +* `subscriptionGroupIdentifier` string - The identifier of the subscription group to which the subscription belongs. +* `subscriptionPeriod` [ProductSubscriptionPeriod](product-subscription-period.md) (optional) - The period details for products that are subscriptions. +* `isDownloadable` boolean - A boolean value that indicates whether the App Store has downloadable content for this product. `true` if at least one file has been associated with the product. +* `downloadContentVersion` string - A string that identifies the version of the content. +* `downloadContentLengths` number[] - The total size of the content, in bytes. diff --git a/docs/api/structures/protocol-request.md b/docs/api/structures/protocol-request.md index 0030e87f8af4e..586a64bba9dfe 100644 --- a/docs/api/structures/protocol-request.md +++ b/docs/api/structures/protocol-request.md @@ -1,7 +1,7 @@ # ProtocolRequest Object -* `url` String -* `referrer` String -* `method` String +* `url` string +* `referrer` string +* `method` string * `uploadData` [UploadData[]](upload-data.md) (optional) -* `headers` Record<String, String> +* `headers` Record\<string, string\> diff --git a/docs/api/structures/protocol-response-upload-data.md b/docs/api/structures/protocol-response-upload-data.md index 225d18bae0bbf..f26dade70d7cd 100644 --- a/docs/api/structures/protocol-response-upload-data.md +++ b/docs/api/structures/protocol-response-upload-data.md @@ -1,4 +1,4 @@ # ProtocolResponseUploadData Object -* `contentType` String - MIME type of the content. -* `data` String | Buffer - Content to be sent. +* `contentType` string - MIME type of the content. +* `data` string | Buffer - Content to be sent. diff --git a/docs/api/structures/protocol-response.md b/docs/api/structures/protocol-response.md index 423d2218bd488..c408cca0bc568 100644 --- a/docs/api/structures/protocol-response.md +++ b/docs/api/structures/protocol-response.md @@ -3,32 +3,31 @@ * `error` Integer (optional) - When assigned, the `request` will fail with the `error` number . For the available error numbers you can use, please see the [net error list][net-error]. -* `statusCode` Number (optional) - The HTTP response code, default is 200. -* `charset` String (optional) - The charset of response body, default is +* `statusCode` number (optional) - The HTTP response code, default is 200. +* `charset` string (optional) - The charset of response body, default is `"utf-8"`. -* `mimeType` String (optional) - The MIME type of response body, default is +* `mimeType` string (optional) - The MIME type of response body, default is `"text/html"`. Setting `mimeType` would implicitly set the `content-type` header in response, but if `content-type` is already set in `headers`, the `mimeType` would be ignored. -* `headers` Record<string, string | string[]> (optional) - An object containing the response headers. The - keys must be String, and values must be either String or Array of String. -* `data` (Buffer | String | ReadableStream) (optional) - The response body. When +* `headers` Record\<string, string | string[]\> (optional) - An object containing the response headers. The + keys must be string, and values must be either string or Array of string. +* `data` (Buffer | string | ReadableStream) (optional) - The response body. When returning stream as response, this is a Node.js readable stream representing the response body. When returning `Buffer` as response, this is a `Buffer`. - When returning `String` as response, this is a `String`. This is ignored for + When returning `string` as response, this is a `string`. This is ignored for other types of responses. -* `path` String (optional) - Path to the file which would be sent as response +* `path` string (optional) - Path to the file which would be sent as response body. This is only used for file responses. -* `url` String (optional) - Download the `url` and pipe the result as response +* `url` string (optional) - Download the `url` and pipe the result as response body. This is only used for URL responses. -* `referrer` String (optional) - The `referrer` URL. This is only used for file +* `referrer` string (optional) - The `referrer` URL. This is only used for file and URL responses. -* `method` String (optional) - The HTTP `method`. This is only used for file +* `method` string (optional) - The HTTP `method`. This is only used for file and URL responses. -* `session` Session (optional) - The session used for requesting URL, by default - the HTTP request will reuse the current session. Setting `session` to `null` - would use a random independent session. This is only used for URL responses. +* `session` Session (optional) - The session used for requesting URL. + The HTTP request will reuse the current session by default. * `uploadData` [ProtocolResponseUploadData](protocol-response-upload-data.md) (optional) - The data used as upload data. This is only used for URL responses when `method` is `"POST"`. -[net-error]: https://source.chromium.org/chromium/chromium/src/+/master:net/base/net_error_list.h +[net-error]: https://source.chromium.org/chromium/chromium/src/+/main:net/base/net_error_list.h diff --git a/docs/api/structures/proxy-config.md b/docs/api/structures/proxy-config.md new file mode 100644 index 0000000000000..eb68d37e651ac --- /dev/null +++ b/docs/api/structures/proxy-config.md @@ -0,0 +1,86 @@ +# ProxyConfig Object + +* `mode` string (optional) - The proxy mode. Should be one of `direct`, +`auto_detect`, `pac_script`, `fixed_servers` or `system`. +Defaults to `pac_script` proxy mode if `pacScript` option is specified +otherwise defaults to `fixed_servers`. + * `direct` - In direct mode all connections are created directly, without any proxy involved. + * `auto_detect` - In auto_detect mode the proxy configuration is determined by a PAC script that can + be downloaded at http://wpad/wpad.dat. + * `pac_script` - In pac_script mode the proxy configuration is determined by a PAC script that is + retrieved from the URL specified in the `pacScript`. This is the default mode if `pacScript` is specified. + * `fixed_servers` - In fixed_servers mode the proxy configuration is specified in `proxyRules`. + This is the default mode if `proxyRules` is specified. + * `system` - In system mode the proxy configuration is taken from the operating system. + Note that the system mode is different from setting no proxy configuration. + In the latter case, Electron falls back to the system settings only if no + command-line options influence the proxy configuration. +* `pacScript` string (optional) - The URL associated with the PAC file. +* `proxyRules` string (optional) - Rules indicating which proxies to use. +* `proxyBypassRules` string (optional) - Rules indicating which URLs should +bypass the proxy settings. + +When `mode` is unspecified, `pacScript` and `proxyRules` are provided together, the `proxyRules` +option is ignored and `pacScript` configuration is applied. + +The `proxyRules` has to follow the rules below: + +```sh +proxyRules = schemeProxies[";"<schemeProxies>] +schemeProxies = [<urlScheme>"="]<proxyURIList> +urlScheme = "http" | "https" | "ftp" | "socks" +proxyURIList = <proxyURL>[","<proxyURIList>] +proxyURL = [<proxyScheme>"://"]<proxyHost>[":"<proxyPort>] +``` + +For example: + +* `http=foopy:80;ftp=foopy2` - Use HTTP proxy `foopy:80` for `http://` URLs, and + HTTP proxy `foopy2:80` for `ftp://` URLs. +* `foopy:80` - Use HTTP proxy `foopy:80` for all URLs. +* `foopy:80,bar,direct://` - Use HTTP proxy `foopy:80` for all URLs, failing + over to `bar` if `foopy:80` is unavailable, and after that using no proxy. +* `socks4://foopy` - Use SOCKS v4 proxy `foopy:1080` for all URLs. +* `http=foopy,socks5://bar.com` - Use HTTP proxy `foopy` for http URLs, and fail + over to the SOCKS5 proxy `bar.com` if `foopy` is unavailable. +* `http=foopy,direct://` - Use HTTP proxy `foopy` for http URLs, and use no + proxy if `foopy` is unavailable. +* `http=foopy;socks=foopy2` - Use HTTP proxy `foopy` for http URLs, and use + `socks4://foopy2` for all other URLs. + +The `proxyBypassRules` is a comma separated list of rules described below: + +* `[ URL_SCHEME "://" ] HOSTNAME_PATTERN [ ":" <port> ]` + + Match all hostnames that match the pattern HOSTNAME_PATTERN. + + Examples: + "foobar.com", "\*foobar.com", "\*.foobar.com", "\*foobar.com:99", + "https://x.\*.y.com:99" + +* `"." HOSTNAME_SUFFIX_PATTERN [ ":" PORT ]` + + Match a particular domain suffix. + + Examples: + ".google.com", ".com", "http://.google.com" + +* `[ SCHEME "://" ] IP_LITERAL [ ":" PORT ]` + + Match URLs which are IP address literals. + + Examples: + "127.0.1", "\[0:0::1]", "\[::1]", "http://\[::1]:99" + +* `IP_LITERAL "/" PREFIX_LENGTH_IN_BITS` + + Match any URL that is to an IP literal that falls between the + given range. IP range is specified using CIDR notation. + + Examples: + "192.168.1.1/16", "fefe:13::abc/33". + +* `<local>` + + Match local addresses. The meaning of `<local>` is whether the + host matches one of: "127.0.0.1", "::1", "localhost". diff --git a/docs/api/structures/rectangle.md b/docs/api/structures/rectangle.md index 9f7a000967d09..58ea74c0e28c0 100644 --- a/docs/api/structures/rectangle.md +++ b/docs/api/structures/rectangle.md @@ -1,6 +1,6 @@ # Rectangle Object -* `x` Number - The x coordinate of the origin of the rectangle (must be an integer). -* `y` Number - The y coordinate of the origin of the rectangle (must be an integer). -* `width` Number - The width of the rectangle (must be an integer). -* `height` Number - The height of the rectangle (must be an integer). +* `x` number - The x coordinate of the origin of the rectangle (must be an integer). +* `y` number - The y coordinate of the origin of the rectangle (must be an integer). +* `width` number - The width of the rectangle (must be an integer). +* `height` number - The height of the rectangle (must be an integer). diff --git a/docs/api/structures/referrer.md b/docs/api/structures/referrer.md index 54741d5797c88..96fdad11edea3 100644 --- a/docs/api/structures/referrer.md +++ b/docs/api/structures/referrer.md @@ -1,7 +1,7 @@ # Referrer Object -* `url` String - HTTP Referrer URL. -* `policy` String - Can be `default`, `unsafe-url`, +* `url` string - HTTP Referrer URL. +* `policy` string - Can be `default`, `unsafe-url`, `no-referrer-when-downgrade`, `no-referrer`, `origin`, `strict-origin-when-cross-origin`, `same-origin` or `strict-origin`. See the [Referrer-Policy spec][1] for more details on the diff --git a/docs/api/structures/render-process-gone-details.md b/docs/api/structures/render-process-gone-details.md new file mode 100644 index 0000000000000..633d9bbc9ddb6 --- /dev/null +++ b/docs/api/structures/render-process-gone-details.md @@ -0,0 +1,14 @@ +# RenderProcessGoneDetails Object + +* `reason` string - The reason the render process is gone. Possible values: + * `clean-exit` - Process exited with an exit code of zero + * `abnormal-exit` - Process exited with a non-zero exit code + * `killed` - Process was sent a SIGTERM or otherwise killed externally + * `crashed` - Process crashed + * `oom` - Process ran out of memory + * `launch-failed` - Process never successfully launched + * `integrity-failure` - Windows code integrity checks failed + * `memory-eviction` - Process proactively terminated to prevent a future out-of-memory (OOM) situation +* `exitCode` Integer - The exit code of the process, unless `reason` is + `launch-failed`, in which case `exitCode` will be a platform-specific + launch failure error code. diff --git a/docs/api/structures/resolved-endpoint.md b/docs/api/structures/resolved-endpoint.md new file mode 100644 index 0000000000000..0847429f04129 --- /dev/null +++ b/docs/api/structures/resolved-endpoint.md @@ -0,0 +1,7 @@ +# ResolvedEndpoint Object + +* `address` string +* `family` string - One of the following: + * `ipv4` - Corresponds to `AF_INET` + * `ipv6` - Corresponds to `AF_INET6` + * `unspec` - Corresponds to `AF_UNSPEC` diff --git a/docs/api/structures/resolved-host.md b/docs/api/structures/resolved-host.md new file mode 100644 index 0000000000000..43c577f1fb003 --- /dev/null +++ b/docs/api/structures/resolved-host.md @@ -0,0 +1,3 @@ +# ResolvedHost Object + +* `endpoints` [ResolvedEndpoint[]](resolved-endpoint.md) - resolved DNS entries for the hostname diff --git a/docs/api/structures/scrubber-item.md b/docs/api/structures/scrubber-item.md index 538579684242b..ce631ea9f9bc3 100644 --- a/docs/api/structures/scrubber-item.md +++ b/docs/api/structures/scrubber-item.md @@ -1,4 +1,4 @@ # ScrubberItem Object -* `label` String (optional) - The text to appear in this item. +* `label` string (optional) - The text to appear in this item. * `icon` NativeImage (optional) - The image to appear in this item. diff --git a/docs/api/structures/segmented-control-segment.md b/docs/api/structures/segmented-control-segment.md index 47dfaa2402755..3b2f468a19d64 100644 --- a/docs/api/structures/segmented-control-segment.md +++ b/docs/api/structures/segmented-control-segment.md @@ -1,5 +1,5 @@ # SegmentedControlSegment Object -* `label` String (optional) - The text to appear in this segment. +* `label` string (optional) - The text to appear in this segment. * `icon` NativeImage (optional) - The image to appear in this segment. -* `enabled` Boolean (optional) - Whether this segment is selectable. Default: true. +* `enabled` boolean (optional) - Whether this segment is selectable. Default: true. diff --git a/docs/api/structures/serial-port.md b/docs/api/structures/serial-port.md index 5f7d25dd05a19..21d607c8827b6 100644 --- a/docs/api/structures/serial-port.md +++ b/docs/api/structures/serial-port.md @@ -1,10 +1,10 @@ # SerialPort Object -* `portId` String - Unique identifier for the port. -* `portName` String - Name of the port. -* `displayName` String - A string suitable for display to the user for describing this device. -* `vendorId` String - Optional USB vendor ID. -* `productId` String - Optional USB product ID. -* `serialNumber` String - The USB device serial number. -* `usbDriverName` String (optional) - Represents a single serial port on macOS can be enumerated by multiple drivers. -* `deviceInstanceId` String (optional) - A stable identifier on Windows that can be used for device permissions. +* `portId` string - Unique identifier for the port. +* `portName` string - Name of the port. +* `displayName` string (optional) - A string suitable for display to the user for describing this device. +* `vendorId` string (optional) - The USB vendor ID. +* `productId` string (optional) - The USB product ID. +* `serialNumber` string (optional) - The USB device serial number. +* `usbDriverName` string (optional) _macOS_ - Represents a single serial port on macOS can be enumerated by multiple drivers. +* `deviceInstanceId` string (optional) _Windows_ - A stable identifier on Windows that can be used for device permissions. diff --git a/docs/api/structures/service-worker-info.md b/docs/api/structures/service-worker-info.md index 578ef347744a2..c1192a6ccdce3 100644 --- a/docs/api/structures/service-worker-info.md +++ b/docs/api/structures/service-worker-info.md @@ -1,5 +1,6 @@ # ServiceWorkerInfo Object -* `scriptUrl` String - The full URL to the script that this service worker runs -* `scope` String - The base URL that this service worker is active for. -* `renderProcessId` Number - The virtual ID of the process that this service worker is running in. This is not an OS level PID. This aligns with the ID set used for `webContents.getProcessId()`. +* `scriptUrl` string - The full URL to the script that this service worker runs +* `scope` string - The base URL that this service worker is active for. +* `renderProcessId` number - The virtual ID of the process that this service worker is running in. This is not an OS level PID. This aligns with the ID set used for `webContents.getProcessId()`. +* `versionId` number - ID of the service worker version diff --git a/docs/api/structures/shared-dictionary-info.md b/docs/api/structures/shared-dictionary-info.md new file mode 100644 index 0000000000000..09710d5fd6fad --- /dev/null +++ b/docs/api/structures/shared-dictionary-info.md @@ -0,0 +1,12 @@ +# SharedDictionaryInfo Object + +* `match` string - The matching path pattern for the dictionary which was declared in 'use-as-dictionary' response header's `match` option. +* `matchDestinations` string[] - An array of matching destinations for the dictionary which was declared in 'use-as-dictionary' response header's `match-dest` option. +* `id` string - The Id for the dictionary which was declared in 'use-as-dictionary' response header's `id` option. +* `dictionaryUrl` string - URL of the dictionary. +* `lastFetchTime` Date - The time of when the dictionary was received from the network layer. +* `responseTime` Date - The time of when the dictionary was received from the server. For cached responses, this time could be "far" in the past. +* `expirationDuration` number - The expiration time for the dictionary which was declared in 'use-as-dictionary' response header's `expires` option in seconds. +* `lastUsedTime` Date - The time when the dictionary was last used. +* `size` number - The amount of bytes stored for this shared dictionary information object in Chromium's internal storage (usually Sqlite). +* `hash` string - The sha256 hash of the dictionary binary. diff --git a/docs/api/structures/shared-dictionary-usage-info.md b/docs/api/structures/shared-dictionary-usage-info.md new file mode 100644 index 0000000000000..c0b9217d1878c --- /dev/null +++ b/docs/api/structures/shared-dictionary-usage-info.md @@ -0,0 +1,5 @@ +# SharedDictionaryUsageInfo Object + +* `frameOrigin` string - The origin of the frame where the request originates. It’s specific to the individual frame making the request and is defined by its scheme, host, and port. In practice, will look like a URL. +* `topFrameSite` string - The site of the top-level browsing context (the main frame or tab that contains the request). It’s less granular than `frameOrigin` and focuses on the broader "site" scope. In practice, will look like a URL. +* `totalSizeBytes` number - The amount of bytes stored for this shared dictionary information object in Chromium's internal storage (usually Sqlite). diff --git a/docs/api/structures/shared-texture-handle.md b/docs/api/structures/shared-texture-handle.md new file mode 100644 index 0000000000000..6bcfe322d6d09 --- /dev/null +++ b/docs/api/structures/shared-texture-handle.md @@ -0,0 +1,12 @@ +# SharedTextureHandle Object + +* `ntHandle` Buffer (optional) _Windows_ - NT HANDLE holds the shared texture. Note that this NT HANDLE is local to current process. Output textures of `rgba`, `bgra`, `rgbaf16` formats don't have a keyed mutex on the texture handle, but `nv12` format texture handles do have a keyed mutex. +* `ioSurface` Buffer (optional) _macOS_ - IOSurfaceRef holds the shared texture. Note that this IOSurface is local to current process (not global). +* `nativePixmap` Object (optional) _Linux_ - Structure contains planes of shared texture. + * `planes` Object[] _Linux_ - Each plane's info of the shared texture. + * `stride` number - The strides and offsets in bytes to be used when accessing the buffers via a memory mapping. One per plane per entry. + * `offset` number - The strides and offsets in bytes to be used when accessing the buffers via a memory mapping. One per plane per entry. + * `size` number - Size in bytes of the plane. This is necessary to map the buffers. + * `fd` number - File descriptor for the underlying memory object (usually dmabuf). + * `modifier` string _Linux_ - The modifier is retrieved from GBM library and passed to EGL driver. + * `supportsZeroCopyWebGpuImport` boolean _Linux_ - Indicates whether supports zero copy import to WebGPU. diff --git a/docs/api/structures/shared-texture-import-texture-info.md b/docs/api/structures/shared-texture-import-texture-info.md new file mode 100644 index 0000000000000..bfe83fc51f3e4 --- /dev/null +++ b/docs/api/structures/shared-texture-import-texture-info.md @@ -0,0 +1,14 @@ +# SharedTextureImportTextureInfo Object + +* `pixelFormat` string - The pixel format of the texture. + * `bgra` - 32bpp BGRA (byte-order), 1 plane. + * `rgba` - 32bpp RGBA (byte-order), 1 plane. + * `rgbaf16` - Half float RGBA, 1 plane. + * `nv12` - 12bpp with Y plane followed by a 2x2 interleaved UV plane. + * `nv16` - 16bpp with Y plane followed by a 2x1 interleaved UV plane. + * `p010le` - 4:2:0 10-bit YUV (little-endian), Y plane followed by a 2x2 interleaved UV plane. +* `colorSpace` [ColorSpace](color-space.md) (optional) - The color space of the texture. +* `codedSize` [Size](size.md) - The full dimensions of the shared texture. +* `visibleRect` [Rectangle](rectangle.md) (optional) - A subsection of [0, 0, codedSize.width, codedSize.height]. In common cases, it is the full section area. +* `timestamp` number (optional) - A timestamp in microseconds that will be reflected to `VideoFrame`. +* `handle` [SharedTextureHandle](shared-texture-handle.md) - The shared texture handle. diff --git a/docs/api/structures/shared-texture-imported-subtle.md b/docs/api/structures/shared-texture-imported-subtle.md new file mode 100644 index 0000000000000..c0c934ee1a281 --- /dev/null +++ b/docs/api/structures/shared-texture-imported-subtle.md @@ -0,0 +1,9 @@ +# SharedTextureImportedSubtle Object + +* `getVideoFrame` Function\<[VideoFrame](https://developer.mozilla.org/en-US/docs/Web/API/VideoFrame)\> - Create a `VideoFrame` that uses the imported shared texture in the current process. You can call `VideoFrame.close()` once you've finished using the object. The underlying resources will wait for GPU finish internally. +* `release` Function - Release the resources. If you transferred and get multiple `SharedTextureImported` objects, you have to `release` every one of them. The resource on the GPU process will be destroyed when the last one is released. + * `callback` Function (optional) - Callback when the GPU command buffer finishes using this shared texture. It provides a precise event to safely release dependent resources. For example, if this object is created by `finishTransferSharedTexture`, you can use this callback to safely release the original one that called `startTransferSharedTexture` in other processes. You can also release the source shared texture that was used to `importSharedTexture` safely. +* `startTransferSharedTexture` Function\<[SharedTextureTransfer](shared-texture-transfer.md)\> - Create a `SharedTextureTransfer` that can be serialized and transferred to other processes. +* `getFrameCreationSyncToken` Function\<[SharedTextureSyncToken](shared-texture-sync-token.md)\> - This method is for advanced users. If used, it is typically called after `finishTransferSharedTexture`, and should be passed to the object which was called `startTransferSharedTexture` to prevent the source object release the underlying resource before the target object actually acquire the reference at gpu process asyncly. +* `setReleaseSyncToken` Function - This method is for advanced users. If used, this object's underlying resource will not be released until the set sync token is fulfilled at gpu process. By using sync tokens, users are not required to use release callbacks for lifetime management. + * `syncToken` [SharedTextureSyncToken](shared-texture-sync-token.md) - The sync token to set. diff --git a/docs/api/structures/shared-texture-imported.md b/docs/api/structures/shared-texture-imported.md new file mode 100644 index 0000000000000..e6fea2f420488 --- /dev/null +++ b/docs/api/structures/shared-texture-imported.md @@ -0,0 +1,6 @@ +# SharedTextureImported Object + +* `textureId` string - The unique identifier of the imported shared texture. +* `getVideoFrame` Function\<[VideoFrame](https://developer.mozilla.org/en-US/docs/Web/API/VideoFrame)\> - Create a `VideoFrame` that uses the imported shared texture in the current process. You can call `VideoFrame.close()` once you've finished using the object. The underlying resources will wait for GPU finish internally. +* `release` Function - Release this object's reference of the imported shared texture. The underlying resource will be alive until every reference is released. +* `subtle` [SharedTextureImportedSubtle](shared-texture-imported-subtle.md) - Provides subtle APIs to interact with the imported shared texture for advanced users. diff --git a/docs/api/structures/shared-texture-subtle.md b/docs/api/structures/shared-texture-subtle.md new file mode 100644 index 0000000000000..a20f4ff8928ab --- /dev/null +++ b/docs/api/structures/shared-texture-subtle.md @@ -0,0 +1,6 @@ +# SharedTextureSubtle Object + +* `importSharedTexture` Function\<[SharedTextureImportedSubtle](shared-texture-imported-subtle.md)\> - Imports the shared texture from the given options. Returns the imported shared texture. + * `textureInfo` [SharedTextureImportTextureInfo](shared-texture-import-texture-info.md) - The information of shared texture to import. +* `finishTransferSharedTexture` Function\<[SharedTextureImportedSubtle](shared-texture-imported-subtle.md)\> - Finishes the transfer of the shared texture and gets the transferred shared texture. Returns the imported shared texture from the transfer object. + * `transfer` [SharedTextureTransfer](shared-texture-transfer.md) - The transfer object of the shared texture. diff --git a/docs/api/structures/shared-texture-sync-token.md b/docs/api/structures/shared-texture-sync-token.md new file mode 100644 index 0000000000000..abc3b6e28748a --- /dev/null +++ b/docs/api/structures/shared-texture-sync-token.md @@ -0,0 +1,3 @@ +# SharedTextureSyncToken Object + +* `syncToken` string - The opaque data for sync token. diff --git a/docs/api/structures/shared-texture-transfer.md b/docs/api/structures/shared-texture-transfer.md new file mode 100644 index 0000000000000..3d36ab650bf2a --- /dev/null +++ b/docs/api/structures/shared-texture-transfer.md @@ -0,0 +1,10 @@ +# SharedTextureTransfer Object + +* `transfer` string _Readonly_ - The opaque transfer data of the shared texture. This can be transferred across Electron processes. +* `syncToken` string _Readonly_ - The opaque sync token data for frame creation. +* `pixelFormat` string _Readonly_ - The pixel format of the transferring texture. +* `codedSize` [Size](size.md) _Readonly_ - The full dimensions of the shared texture. +* `visibleRect` [Rectangle](rectangle.md) _Readonly_ - A subsection of [0, 0, codedSize.width(), codedSize.height()]. In common cases, it is the full section area. +* `timestamp` number _Readonly_ - A timestamp in microseconds that will be reflected to `VideoFrame`. + +Use `sharedTexture.subtle.finishTransferSharedTexture` to get [`SharedTextureImportedSubtle`](shared-texture-imported-subtle.md) back. diff --git a/docs/api/structures/shared-worker-info.md b/docs/api/structures/shared-worker-info.md index 1e47c0c3ce348..dac1b52bfd5c3 100644 --- a/docs/api/structures/shared-worker-info.md +++ b/docs/api/structures/shared-worker-info.md @@ -1,4 +1,4 @@ # SharedWorkerInfo Object -* `id` String - The unique id of the shared worker. -* `url` String - The url of the shared worker. +* `id` string - The unique id of the shared worker. +* `url` string - The url of the shared worker. diff --git a/docs/api/structures/sharing-item.md b/docs/api/structures/sharing-item.md index aab5b09c10f6e..6e9f451b32b01 100644 --- a/docs/api/structures/sharing-item.md +++ b/docs/api/structures/sharing-item.md @@ -1,5 +1,5 @@ # SharingItem Object -* `texts` String[] (optional) - An array of text to share. -* `filePaths` String[] (optional) - An array of files to share. -* `urls` String[] (optional) - An array of URLs to share. +* `texts` string[] (optional) - An array of text to share. +* `filePaths` string[] (optional) - An array of files to share. +* `urls` string[] (optional) - An array of URLs to share. diff --git a/docs/api/structures/shortcut-details.md b/docs/api/structures/shortcut-details.md index d45ae4d017657..27d9c4e88bd2e 100644 --- a/docs/api/structures/shortcut-details.md +++ b/docs/api/structures/shortcut-details.md @@ -1,17 +1,17 @@ # ShortcutDetails Object -* `target` String - The target to launch from this shortcut. -* `cwd` String (optional) - The working directory. Default is empty. -* `args` String (optional) - The arguments to be applied to `target` when +* `target` string - The target to launch from this shortcut. +* `cwd` string (optional) - The working directory. Default is empty. +* `args` string (optional) - The arguments to be applied to `target` when launching from this shortcut. Default is empty. -* `description` String (optional) - The description of the shortcut. Default +* `description` string (optional) - The description of the shortcut. Default is empty. -* `icon` String (optional) - The path to the icon, can be a DLL or EXE. `icon` +* `icon` string (optional) - The path to the icon, can be a DLL or EXE. `icon` and `iconIndex` have to be set together. Default is empty, which uses the target's icon. -* `iconIndex` Number (optional) - The resource ID of icon when `icon` is a +* `iconIndex` number (optional) - The resource ID of icon when `icon` is a DLL or EXE. Default is 0. -* `appUserModelId` String (optional) - The Application User Model ID. Default +* `appUserModelId` string (optional) - The Application User Model ID. Default is empty. -* `toastActivatorClsid` String (optional) - The Application Toast Activator CLSID. Needed +* `toastActivatorClsid` string (optional) - The Application Toast Activator CLSID. Needed for participating in Action Center. diff --git a/docs/api/structures/size.md b/docs/api/structures/size.md index 1d9c8b1f5a123..417c57761b606 100644 --- a/docs/api/structures/size.md +++ b/docs/api/structures/size.md @@ -1,4 +1,4 @@ # Size Object -* `width` Number -* `height` Number +* `width` number +* `height` number diff --git a/docs/api/structures/task.md b/docs/api/structures/task.md index 161a9afecc610..b8ea501086c8a 100644 --- a/docs/api/structures/task.md +++ b/docs/api/structures/task.md @@ -1,15 +1,15 @@ # Task Object -* `program` String - Path of the program to execute, usually you should +* `program` string - Path of the program to execute, usually you should specify `process.execPath` which opens the current program. -* `arguments` String - The command line arguments when `program` is +* `arguments` string - The command line arguments when `program` is executed. -* `title` String - The string to be displayed in a JumpList. -* `description` String - Description of this task. -* `iconPath` String - The absolute path to an icon to be displayed in a +* `title` string - The string to be displayed in a JumpList. +* `description` string - Description of this task. +* `iconPath` string - The absolute path to an icon to be displayed in a JumpList, which can be an arbitrary resource file that contains an icon. You can usually specify `process.execPath` to show the icon of the program. -* `iconIndex` Number - The icon index in the icon file. If an icon file +* `iconIndex` number - The icon index in the icon file. If an icon file consists of two or more icons, set this value to identify the icon. If an icon file consists of one icon, this value is 0. -* `workingDirectory` String (optional) - The working directory. Default is empty. +* `workingDirectory` string (optional) - The working directory. Default is empty. diff --git a/docs/api/structures/thumbar-button.md b/docs/api/structures/thumbar-button.md index 259195852a4f2..a5e5815147251 100644 --- a/docs/api/structures/thumbar-button.md +++ b/docs/api/structures/thumbar-button.md @@ -3,11 +3,11 @@ * `icon` [NativeImage](../native-image.md) - The icon showing in thumbnail toolbar. * `click` Function -* `tooltip` String (optional) - The text of the button's tooltip. -* `flags` String[] (optional) - Control specific states and behaviors of the +* `tooltip` string (optional) - The text of the button's tooltip. +* `flags` string[] (optional) - Control specific states and behaviors of the button. By default, it is `['enabled']`. -The `flags` is an array that can include following `String`s: +The `flags` is an array that can include following `string`s: * `enabled` - The button is active and available to the user. * `disabled` - The button is disabled. It is present, but has a visual state diff --git a/docs/api/structures/trace-categories-and-options.md b/docs/api/structures/trace-categories-and-options.md index 8db0638c9b112..5965ec093bd1f 100644 --- a/docs/api/structures/trace-categories-and-options.md +++ b/docs/api/structures/trace-categories-and-options.md @@ -1,11 +1,11 @@ # TraceCategoriesAndOptions Object -* `categoryFilter` String - A filter to control what category groups +* `categoryFilter` string - A filter to control what category groups should be traced. A filter can have an optional '-' prefix to exclude category groups that contain a matching category. Having both included and excluded category patterns in the same list is not supported. Examples: `test_MyTest*`, `test_MyTest*,test_OtherStuff`, `-excluded_category1,-excluded_category2`. -* `traceOptions` String - Controls what kind of tracing is enabled, +* `traceOptions` string - Controls what kind of tracing is enabled, it is a comma-delimited sequence of the following strings: `record-until-full`, `record-continuously`, `trace-to-console`, `enable-sampling`, `enable-systrace`, e.g. `'record-until-full,enable-sampling'`. diff --git a/docs/api/structures/trace-config.md b/docs/api/structures/trace-config.md index bb31ad64dfdfd..d63ed37d31d65 100644 --- a/docs/api/structures/trace-config.md +++ b/docs/api/structures/trace-config.md @@ -1,31 +1,33 @@ # TraceConfig Object -* `recording_mode` String (optional) - Can be `record-until-full`, `record-continuously`, `record-as-much-as-possible` or `trace-to-console`. Defaults to `record-until-full`. +* `recording_mode` string (optional) - Can be `record-until-full`, `record-continuously`, `record-as-much-as-possible` or `trace-to-console`. Defaults to `record-until-full`. * `trace_buffer_size_in_kb` number (optional) - maximum size of the trace recording buffer in kilobytes. Defaults to 100MB. * `trace_buffer_size_in_events` number (optional) - maximum size of the trace recording buffer in events. * `enable_argument_filter` boolean (optional) - if true, filter event data according to a specific list of events that have been manually vetted to not - include any PII. See [the implementation in - Chromium][trace_event_args_whitelist.cc] for specifics. -* `included_categories` String[] (optional) - a list of tracing categories to + include any PII. See [the implementation in Chromium][trace_event_args_allowlist.cc] + for specifics. +* `included_categories` string[] (optional) - a list of tracing categories to include. Can include glob-like patterns using `*` at the end of the category name. See [tracing categories][] for the list of categories. -* `excluded_categories` String[] (optional) - a list of tracing categories to +* `excluded_categories` string[] (optional) - a list of tracing categories to exclude. Can include glob-like patterns using `*` at the end of the category name. See [tracing categories][] for the list of categories. * `included_process_ids` number[] (optional) - a list of process IDs to include in the trace. If not specified, trace all processes. -* `histogram_names` String[] (optional) - a list of [histogram][] names to report +* `histogram_names` string[] (optional) - a list of [histogram][] names to report with the trace. -* `memory_dump_config` Record<String, any> (optional) - if the +* `memory_dump_config` Record\<string, any\> (optional) - if the `disabled-by-default-memory-infra` category is enabled, this contains - optional additional configuration for data collection. See the [Chromium - memory-infra docs][memory-infra docs] for more information. + optional additional configuration for data collection. See the + [Chromium memory-infra docs][memory-infra docs] for more information. An example TraceConfig that roughly matches what Chrome DevTools records: +<!-- eslint-skip --> + ```js { recording_mode: 'record-until-full', @@ -45,7 +47,7 @@ An example TraceConfig that roughly matches what Chrome DevTools records: } ``` -[tracing categories]: https://chromium.googlesource.com/chromium/src/+/master/base/trace_event/builtin_categories.h -[memory-infra docs]: https://chromium.googlesource.com/chromium/src/+/master/docs/memory-infra/memory_infra_startup_tracing.md#the-advanced-way -[trace_event_args_whitelist.cc]: https://chromium.googlesource.com/chromium/src/+/master/services/tracing/public/cpp/trace_event_args_whitelist.cc +[tracing categories]: https://chromium.googlesource.com/chromium/src/+/main/base/trace_event/builtin_categories.h +[memory-infra docs]: https://chromium.googlesource.com/chromium/src/+/main/docs/memory-infra/memory_infra_startup_tracing.md#the-advanced-way +[trace_event_args_allowlist.cc]: https://chromium.googlesource.com/chromium/src/+/main/services/tracing/public/cpp/trace_event_args_allowlist.cc [histogram]: https://chromium.googlesource.com/chromium/src.git/+/HEAD/tools/metrics/histograms/README.md diff --git a/docs/api/structures/transaction.md b/docs/api/structures/transaction.md index 7349c0996f8bf..0c12ef9961958 100644 --- a/docs/api/structures/transaction.md +++ b/docs/api/structures/transaction.md @@ -1,11 +1,13 @@ # Transaction Object -* `transactionIdentifier` String - A string that uniquely identifies a successful payment transaction. -* `transactionDate` String - The date the transaction was added to the App Store’s payment queue. -* `originalTransactionIdentifier` String - The identifier of the restored transaction by the App Store. -* `transactionState` String - The transaction state, can be `purchasing`, `purchased`, `failed`, `restored` or `deferred`. +* `transactionIdentifier` string - A string that uniquely identifies a successful payment transaction. +* `transactionDate` string - The date the transaction was added to the App Store’s payment queue. +* `originalTransactionIdentifier` string - The identifier of the restored transaction by the App Store. +* `transactionState` string - The transaction state, can be `purchasing`, `purchased`, `failed`, `restored` or `deferred`. * `errorCode` Integer - The error code if an error occurred while processing the transaction. -* `errorMessage` String - The error message if an error occurred while processing the transaction. +* `errorMessage` string - The error message if an error occurred while processing the transaction. * `payment` Object - * `productIdentifier` String - The identifier of the purchased product. + * `productIdentifier` string - The identifier of the purchased product. * `quantity` Integer - The quantity purchased. + * `applicationUsername` string - An opaque identifier for the user’s account on your system. + * `paymentDiscount` [PaymentDiscount](payment-discount.md) (optional) - The details of the discount offer to apply to the payment. diff --git a/docs/api/structures/upload-data.md b/docs/api/structures/upload-data.md index bcbed755b2b9b..7aa4261e5ec80 100644 --- a/docs/api/structures/upload-data.md +++ b/docs/api/structures/upload-data.md @@ -1,6 +1,6 @@ # UploadData Object * `bytes` Buffer - Content being sent. -* `file` String (optional) - Path of file being uploaded. -* `blobUUID` String (optional) - UUID of blob data. Use [ses.getBlobData](../session.md#sesgetblobdataidentifier) method +* `file` string (optional) - Path of file being uploaded. +* `blobUUID` string (optional) - UUID of blob data. Use [ses.getBlobData](../session.md#sesgetblobdataidentifier) method to retrieve the data. diff --git a/docs/api/structures/upload-file.md b/docs/api/structures/upload-file.md index ae231bdaf895f..a3f31b13c8d34 100644 --- a/docs/api/structures/upload-file.md +++ b/docs/api/structures/upload-file.md @@ -1,9 +1,9 @@ # UploadFile Object -* `type` String - `file`. -* `filePath` String - Path of file to be uploaded. -* `offset` Integer - Defaults to `0`. -* `length` Integer - Number of bytes to read from `offset`. +* `type` 'file' - `file`. +* `filePath` string - Path of file to be uploaded. +* `offset` Integer (optional) - Defaults to `0`. +* `length` Integer (optional) - Number of bytes to read from `offset`. Defaults to `0`. -* `modificationTime` Double - Last Modification time in - number of seconds since the UNIX epoch. +* `modificationTime` Double (optional) - Last Modification time in + number of seconds since the UNIX epoch. Defaults to `0`. diff --git a/docs/api/structures/upload-raw-data.md b/docs/api/structures/upload-raw-data.md index 4fe162311fa1f..e80eaa9075833 100644 --- a/docs/api/structures/upload-raw-data.md +++ b/docs/api/structures/upload-raw-data.md @@ -1,4 +1,4 @@ # UploadRawData Object -* `type` String - `rawData`. +* `type` 'rawData' - `rawData`. * `bytes` Buffer - Data to be uploaded. diff --git a/docs/api/structures/usb-device.md b/docs/api/structures/usb-device.md new file mode 100644 index 0000000000000..38a39c288555e --- /dev/null +++ b/docs/api/structures/usb-device.md @@ -0,0 +1,35 @@ +# USBDevice Object + +* `configuration` Object (optional) - A [USBConfiguration](https://developer.mozilla.org/en-US/docs/Web/API/USBConfiguration) object containing information about the currently selected configuration of a USB device. + * `configurationValue` Integer - the configuration value of this configuration. + * `configurationName` string - the name provided by the device to describe this configuration. + * `interfaces` Object[] - An array of [USBInterface](https://developer.mozilla.org/en-US/docs/Web/API/USBInterface) objects containing information about an interface provided by the USB device. + * `interfaceNumber` Integer - the interface number of this interface. + * `alternate` Object - the currently selected alternative configuration of this interface. + * `alternateSetting` Integer - the alternate setting number of this interface. + * `interfaceClass` Integer - the class of this interface. See [USB.org](https://www.usb.org/defined-class-codes) for class code descriptions. + * `interfaceSubclass` Integer - the subclass of this interface. + * `interfaceProtocol` Integer - the protocol supported by this interface. + * `interfaceName` string (optional) - the name of the interface, if one is provided by the device. + * `endpoints` Object[] - an array containing instances of the [USBEndpoint interface](https://developer.mozilla.org/en-US/docs/Web/API/USBEndpoint) describing each of the endpoints that are part of this interface. + * `endpointNumber` Integer - this endpoint's "endpoint number" which is a value from 1 to 15. + * `direction` string - the direction in which this endpoint transfers data - can be either 'in' or 'out'. + * `type` string - the type of this endpoint - can be either 'bulk', 'interrupt', or 'isochronous'. + * `packetSize` Integer - the size of the packets that data sent through this endpoint will be divided into. + * `alternates` Object[] - an array containing instances of the [USBAlternateInterface](https://developer.mozilla.org/en-US/docs/Web/API/USBAlternateInterface) interface describing each of the alternative configurations possible for this interface. +* `configurations` Object[] - An array of [USBConfiguration](https://developer.mozilla.org/en-US/docs/Web/API/USBConfiguration) interfaces for controlling a paired USB device. +* `deviceClass` Integer - The device class for the communication interface supported by the device. +* `deviceId` string - Unique identifier for the device. +* `deviceProtocol` Integer - The device protocol for the communication interface supported by the device. +* `deviceSubclass` Integer - The device subclass for the communication interface supported by the device. +* `deviceVersionMajor` Integer - The major version number of the device as defined by the device manufacturer. +* `deviceVersionMinor` Integer - The minor version number of the device as defined by the device manufacturer. +* `deviceVersionSubminor` Integer - The subminor version number of the device as defined by the device manufacturer. +* `manufacturerName` string (optional) - The manufacturer name of the device. +* `productId` Integer - The USB product ID. +* `productName` string (optional) - Name of the device. +* `serialNumber` string (optional) - The USB device serial number. +* `usbVersionMajor` Integer - The USB protocol major version supported by the device. +* `usbVersionMinor` Integer - The USB protocol minor version supported by the device. +* `usbVersionSubminor` Integer - The USB protocol subminor version supported by the device. +* `vendorId` Integer - The USB vendor ID. diff --git a/docs/api/structures/user-default-types.md b/docs/api/structures/user-default-types.md new file mode 100644 index 0000000000000..f11d43474bba1 --- /dev/null +++ b/docs/api/structures/user-default-types.md @@ -0,0 +1,12 @@ +# UserDefaultTypes Object + +* `string` string +* `boolean` boolean +* `integer` number +* `float` number +* `double` number +* `url` string +* `array` Array\<unknown> +* `dictionary` Record\<string, unknown> + +This type is a helper alias, no object will ever exist of this type. diff --git a/docs/api/structures/web-preferences.md b/docs/api/structures/web-preferences.md new file mode 100644 index 0000000000000..b6ebb6f2b24b5 --- /dev/null +++ b/docs/api/structures/web-preferences.md @@ -0,0 +1,165 @@ +# WebPreferences Object + +* `devTools` boolean (optional) - Whether to enable DevTools. If it is set to `false`, can not use `BrowserWindow.webContents.openDevTools()` to open DevTools. Default is `true`. +* `nodeIntegration` boolean (optional) - Whether node integration is enabled. + Default is `false`. +* `nodeIntegrationInWorker` boolean (optional) - Whether node integration is + enabled in web workers. Default is `false`. More about this can be found + in [Multithreading](../../tutorial/multithreading.md). +* `nodeIntegrationInSubFrames` boolean (optional) - Experimental option for + enabling Node.js support in sub-frames such as iframes and child windows. All your preloads will load for + every iframe, you can use `process.isMainFrame` to determine if you are + in the main frame or not. +* `preload` string (optional) - Specifies a script that will be loaded before other + scripts run in the page. This script will always have access to node APIs + no matter whether node integration is turned on or off. The value should + be the absolute file path to the script. + When node integration is turned off, the preload script can reintroduce + Node global symbols back to the global scope. See example + [here](../context-bridge.md#exposing-node-global-symbols). +* `sandbox` boolean (optional) - If set, this will sandbox the renderer + associated with the window, making it compatible with the Chromium + OS-level sandbox and disabling the Node.js engine. This is not the same as + the `nodeIntegration` option and the APIs available to the preload script + are more limited. Default is `true` since Electron 20. The sandbox will + automatically be disabled when `nodeIntegration` is set to `true`. + Read more about the option [here](../../tutorial/sandbox.md). +* `session` [Session](../session.md#class-session) (optional) - Sets the session used by the + page. Instead of passing the Session object directly, you can also choose to + use the `partition` option instead, which accepts a partition string. When + both `session` and `partition` are provided, `session` will be preferred. + Default is the default session. +* `partition` string (optional) - Sets the session used by the page according to the + session's partition string. If `partition` starts with `persist:`, the page + will use a persistent session available to all pages in the app with the + same `partition`. If there is no `persist:` prefix, the page will use an + in-memory session. By assigning the same `partition`, multiple pages can share + the same session. Default is the default session. +* `zoomFactor` number (optional) - The default zoom factor of the page, `3.0` represents + `300%`. Default is `1.0`. +* `javascript` boolean (optional) - Enables JavaScript support. Default is `true`. +* `webSecurity` boolean (optional) - When `false`, it will disable the + same-origin policy (usually using testing websites by people), and set + `allowRunningInsecureContent` to `true` if this option has not been set + by user. Default is `true`. +* `allowRunningInsecureContent` boolean (optional) - Allow an https page to run + JavaScript, CSS or plugins from http URLs. Default is `false`. +* `images` boolean (optional) - Enables image support. Default is `true`. +* `imageAnimationPolicy` string (optional) - Specifies how to run image animations (E.g. GIFs). Can be `animate`, `animateOnce` or `noAnimation`. Default is `animate`. +* `textAreasAreResizable` boolean (optional) - Make TextArea elements resizable. Default + is `true`. +* `webgl` boolean (optional) - Enables WebGL support. Default is `true`. +* `plugins` boolean (optional) - Whether plugins should be enabled. Default is `false`. +* `experimentalFeatures` boolean (optional) - Enables Chromium's experimental features. + Default is `false`. +* `scrollBounce` boolean (optional) _macOS_ - Enables scroll bounce + (rubber banding) effect on macOS. Default is `false`. +* `enableBlinkFeatures` string (optional) - A list of feature strings separated by `,`, like + `CSSVariables,KeyboardEventKey` to enable. The full list of supported feature + strings can be found in the [RuntimeEnabledFeatures.json5][runtime-enabled-features] + file. +* `disableBlinkFeatures` string (optional) - A list of feature strings separated by `,`, + like `CSSVariables,KeyboardEventKey` to disable. The full list of supported + feature strings can be found in the + [RuntimeEnabledFeatures.json5][runtime-enabled-features] file. +* `defaultFontFamily` Object (optional) - Sets the default font for the font-family. + * `standard` string (optional) - Defaults to `Times New Roman`. + * `serif` string (optional) - Defaults to `Times New Roman`. + * `sansSerif` string (optional) - Defaults to `Arial`. + * `monospace` string (optional) - Defaults to `Courier New`. + * `cursive` string (optional) - Defaults to `Script`. + * `fantasy` string (optional) - Defaults to `Impact`. + * `math` string (optional) - Defaults to `Latin Modern Math`. +* `defaultFontSize` Integer (optional) - Defaults to `16`. +* `defaultMonospaceFontSize` Integer (optional) - Defaults to `13`. +* `minimumFontSize` Integer (optional) - Defaults to `0`. +* `defaultEncoding` string (optional) - Defaults to `ISO-8859-1`. +* `backgroundThrottling` boolean (optional) - Whether to throttle animations and timers + when the page becomes background. This also affects the + [Page Visibility API](../browser-window.md#page-visibility). When at least one + [webContents](../web-contents.md) displayed in a single + [browserWindow](../browser-window.md) has disabled `backgroundThrottling` then + frames will be drawn and swapped for the whole window and other + [webContents](../web-contents.md) displayed by it. Defaults to `true`. +* `offscreen` Object | boolean (optional) - Whether to enable offscreen rendering for the browser + window. Defaults to `false`. See the + [offscreen rendering tutorial](../../tutorial/offscreen-rendering.md) for + more details. + * `useSharedTexture` boolean (optional) _Experimental_ - Whether to use GPU shared texture for accelerated + paint event. Defaults to `false`. See the + [offscreen rendering tutorial](../../tutorial/offscreen-rendering.md) for + more details. + * `sharedTexturePixelFormat` string (optional) _Experimental_ - The requested output format of the shared texture. Defaults to `argb`. + The name is originated from Chromium [`media::VideoPixelFormat`](https://source.chromium.org/chromium/chromium/src/+/main:media/base/video_types.h) enum suffix and only subset of them are supported. + The actual output pixel format and color space of the texture should refer to [`OffscreenSharedTexture`](../structures/offscreen-shared-texture.md) object in the `paint` event. + * `argb` - The requested output texture format is 8-bit unorm RGBA, with SRGB SDR color space. + * `rgbaf16` - The requested output texture format is 16-bit float RGBA, with scRGB HDR color space. + * `nv12` - The requested output texture format is 12bpp with Y plane followed by a 2x2 interleaved UV plane, with REC709 color space. + * `deviceScaleFactor` number (optional) _Experimental_ - The device scale factor of the offscreen rendering output. If not set, will use `1` as default. +* `contextIsolation` boolean (optional) - Whether to run Electron APIs and + the specified `preload` script in a separate JavaScript context. Defaults + to `true`. The context that the `preload` script runs in will only have + access to its own dedicated `document` and `window` globals, as well as + its own set of JavaScript builtins (`Array`, `Object`, `JSON`, etc.), + which are all invisible to the loaded content. The Electron API will only + be available in the `preload` script and not the loaded page. This option + should be used when loading potentially untrusted remote content to ensure + the loaded content cannot tamper with the `preload` script and any + Electron APIs being used. This option uses the same technique used by + [Chrome Content Scripts][chrome-content-scripts]. You can access this + context in the dev tools by selecting the 'Electron Isolated Context' + entry in the combo box at the top of the Console tab. +* `webviewTag` boolean (optional) - Whether to enable the [`<webview>` tag](../webview-tag.md). + Defaults to `false`. **Note:** The + `preload` script configured for the `<webview>` will have node integration + enabled when it is executed so you should ensure remote/untrusted content + is not able to create a `<webview>` tag with a possibly malicious `preload` + script. You can use the `will-attach-webview` event on [webContents](../web-contents.md) + to strip away the `preload` script and to validate or alter the + `<webview>`'s initial settings. +* `additionalArguments` string[] (optional) - A list of strings that will be appended + to `process.argv` in the renderer process of this app. Useful for passing small + bits of data down to renderer process preload scripts. +* `safeDialogs` boolean (optional) - Whether to enable browser style + consecutive dialog protection. Default is `false`. +* `safeDialogsMessage` string (optional) - The message to display when + consecutive dialog protection is triggered. If not defined the default + message would be used, note that currently the default message is in + English and not localized. +* `disableDialogs` boolean (optional) - Whether to disable dialogs + completely. Overrides `safeDialogs`. Default is `false`. +* `navigateOnDragDrop` boolean (optional) - Whether dragging and dropping a + file or link onto the page causes a navigation. Default is `false`. +* `autoplayPolicy` string (optional) - Autoplay policy to apply to + content in the window, can be `no-user-gesture-required`, + `user-gesture-required`, `document-user-activation-required`. Defaults to + `no-user-gesture-required`. +* `disableHtmlFullscreenWindowResize` boolean (optional) - Whether to + prevent the window from resizing when entering HTML Fullscreen. Default + is `false`. +* `accessibleTitle` string (optional) - An alternative title string provided only + to accessibility tools such as screen readers. This string is not directly + visible to users. +* `spellcheck` boolean (optional) - Whether to enable the builtin spellchecker. + Default is `true`. +* `enableWebSQL` boolean (optional) - Whether to enable the [WebSQL api](https://www.w3.org/TR/webdatabase/). + Default is `true`. +* `v8CacheOptions` string (optional) - Enforces the v8 code caching policy + used by blink. Accepted values are + * `none` - Disables code caching + * `code` - Heuristic based code caching + * `bypassHeatCheck` - Bypass code caching heuristics but with lazy compilation + * `bypassHeatCheckAndEagerCompile` - Same as above except compilation is eager. + Default policy is `code`. +* `enablePreferredSizeMode` boolean (optional) - Whether to enable + preferred size mode. The preferred size is the minimum size needed to + contain the layout of the document—without requiring scrolling. Enabling + this will cause the `preferred-size-changed` event to be emitted on the + `WebContents` when the preferred size changes. Default is `false`. +* `transparent` boolean (optional) - Whether to enable background transparency for the guest page. Default is `true`. **Note:** The guest page's text and background colors are derived from the [color scheme](https://developer.mozilla.org/en-US/docs/Web/CSS/color-scheme) of its root element. When transparency is enabled, the text color will still change accordingly but the background will remain transparent. +* `enableDeprecatedPaste` boolean (optional) _Deprecated_ - Whether to enable the `paste` [execCommand](https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand). Default is `false`. +* `focusOnNavigation` boolean (optional) - Whether to focus the WebContents + when navigating. Default is `true`. + +[chrome-content-scripts]: https://developer.chrome.com/extensions/content_scripts#execution-environment +[runtime-enabled-features]: https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/platform/runtime_enabled_features.json5 diff --git a/docs/api/structures/web-request-filter.md b/docs/api/structures/web-request-filter.md new file mode 100644 index 0000000000000..480a94f7b9489 --- /dev/null +++ b/docs/api/structures/web-request-filter.md @@ -0,0 +1,5 @@ +# WebRequestFilter Object + +* `urls` string[] - Array of [URL patterns](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Match_patterns) used to include requests that match these patterns. Use the pattern `<all_urls>` to match all URLs. +* `excludeUrls` string[] (optional) - Array of [URL patterns](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Match_patterns) used to exclude requests that match these patterns. +* `types` string[] (optional) - Array of types that will be used to filter out the requests that do not match the types. When not specified, all types will be matched. Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media` or `webSocket`. diff --git a/docs/api/structures/web-source.md b/docs/api/structures/web-source.md index 74c34f372d31e..0a1de87bb1721 100644 --- a/docs/api/structures/web-source.md +++ b/docs/api/structures/web-source.md @@ -1,5 +1,4 @@ # WebSource Object -* `code` String -* `url` String (optional) -* `startLine` Integer (optional) - Default is 1. +* `code` string +* `url` string (optional) diff --git a/docs/api/structures/window-open-handler-response.md b/docs/api/structures/window-open-handler-response.md new file mode 100644 index 0000000000000..6ea1c99628156 --- /dev/null +++ b/docs/api/structures/window-open-handler-response.md @@ -0,0 +1,7 @@ +# WindowOpenHandlerResponse Object + +* `action` string - Can be `allow` or `deny`. Controls whether new window should be created. +* `overrideBrowserWindowOptions` BrowserWindowConstructorOptions (optional) - Allows customization of the created window. +* `outlivesOpener` boolean (optional) - By default, child windows are closed when their opener is closed. This can be + changed by specifying `outlivesOpener: true`, in which case the opened window will not be closed when its opener is closed. +* `createWindow` (options: BrowserWindowConstructorOptions) => WebContents (optional) - If specified, will be called instead of `new BrowserWindow` to create the new child window and event [`did-create-window`](../web-contents.md#event-did-create-window) will not be emitted. Constructed child window should use passed `options` object. This can be used for example to have the new window open as a BrowserView instead of in a separate window. diff --git a/docs/api/structures/window-session-end-event.md b/docs/api/structures/window-session-end-event.md new file mode 100644 index 0000000000000..a5a062b6b4495 --- /dev/null +++ b/docs/api/structures/window-session-end-event.md @@ -0,0 +1,7 @@ +# WindowSessionEndEvent Object extends `Event` + +* `reasons` string[] - List of reasons for shutdown. Can be 'shutdown', 'close-app', 'critical', or 'logoff'. + +Unfortunately, Windows does not offer a way to differentiate between a shutdown and a reboot, meaning the 'shutdown' +reason is triggered in both scenarios. For more details on the `WM_ENDSESSION` message and its associated reasons, +refer to the [MSDN documentation](https://learn.microsoft.com/en-us/windows/win32/shutdown/wm-endsession). diff --git a/docs/api/synopsis.md b/docs/api/synopsis.md deleted file mode 100644 index ce1349615e32b..0000000000000 --- a/docs/api/synopsis.md +++ /dev/null @@ -1,95 +0,0 @@ -# Synopsis - -> How to use Node.js and Electron APIs. - -All of [Node.js's built-in modules](https://nodejs.org/api/) are available in -Electron and third-party node modules also fully supported as well (including -the [native modules](../tutorial/using-native-node-modules.md)). - -Electron also provides some extra built-in modules for developing native -desktop applications. Some modules are only available in the main process, some -are only available in the renderer process (web page), and some can be used in -either process type. - -The basic rule is: if a module is [GUI][gui] or low-level system related, then -it should be only available in the main process. You need to be familiar with -the concept of [main process vs. renderer process](../tutorial/quick-start.md#main-and-renderer-processes) -scripts to be able to use those modules. - -The main process script is like a normal Node.js script: - -```javascript -const { app, BrowserWindow } = require('electron') -let win = null - -app.whenReady().then(() => { - win = new BrowserWindow({ width: 800, height: 600 }) - win.loadURL('https://github.com') -}) -``` - -The renderer process is no different than a normal web page, except for the -extra ability to use node modules if `nodeIntegration` is enabled: - -```html -<!DOCTYPE html> -<html> -<body> -<script> - const fs = require('fs') - console.log(fs.readFileSync(__filename, 'utf8')) -</script> -</body> -</html> -``` - -To run your app, read [Run your app](../tutorial/quick-start.md#run-your-application). - -## Destructuring assignment - -As of 0.37, you can use -[destructuring assignment][destructuring-assignment] to make it easier to use -built-in modules. - -```javascript -const { app, BrowserWindow } = require('electron') - -let win - -app.whenReady().then(() => { - win = new BrowserWindow() - win.loadURL('https://github.com') -}) -``` - -If you need the entire `electron` module, you can require it and then using -destructuring to access the individual modules from `electron`. - -```javascript -const electron = require('electron') -const { app, BrowserWindow } = electron - -let win - -app.whenReady().then(() => { - win = new BrowserWindow() - win.loadURL('https://github.com') -}) -``` - -This is equivalent to the following code: - -```javascript -const electron = require('electron') -const app = electron.app -const BrowserWindow = electron.BrowserWindow -let win - -app.whenReady().then(() => { - win = new BrowserWindow() - win.loadURL('https://github.com') -}) -``` - -[gui]: https://en.wikipedia.org/wiki/Graphical_user_interface -[destructuring-assignment]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment diff --git a/docs/api/system-preferences.md b/docs/api/system-preferences.md index 3936cd7c2f8d6..ce5f4bf8b5e71 100644 --- a/docs/api/system-preferences.md +++ b/docs/api/system-preferences.md @@ -2,23 +2,24 @@ > Get system preferences. -Process: [Main](../glossary.md#main-process) +Process: [Main](../glossary.md#main-process), [Utility](../glossary.md#utility-process) -```javascript +```js const { systemPreferences } = require('electron') -console.log(systemPreferences.isDarkMode()) + +console.log(systemPreferences.getEffectiveAppearance()) ``` ## Events The `systemPreferences` object emits the following events: -### Event: 'accent-color-changed' _Windows_ +### Event: 'accent-color-changed' _Windows_ _Linux_ Returns: * `event` Event -* `newColor` String - The new RGBA color the user assigned to be their system +* `newColor` string - The new RGBA color the user assigned to be their system accent color. ### Event: 'color-changed' _Windows_ @@ -27,70 +28,46 @@ Returns: * `event` Event -### Event: 'inverted-color-scheme-changed' _Windows_ _Deprecated_ - -Returns: - -* `event` Event -* `invertedColorScheme` Boolean - `true` if an inverted color scheme (a high contrast color scheme with light text and dark backgrounds) is being used, `false` otherwise. - -**Deprecated:** Should use the new [`updated`](native-theme.md#event-updated) event on the `nativeTheme` module. - -### Event: 'high-contrast-color-scheme-changed' _Windows_ _Deprecated_ - -Returns: - -* `event` Event -* `highContrastColorScheme` Boolean - `true` if a high contrast theme is being used, `false` otherwise. - -**Deprecated:** Should use the new [`updated`](native-theme.md#event-updated) event on the `nativeTheme` module. - ## Methods -### `systemPreferences.isDarkMode()` _macOS_ _Windows_ _Deprecated_ - -Returns `Boolean` - Whether the system is in Dark Mode. - -**Deprecated:** Should use the new [`nativeTheme.shouldUseDarkColors`](native-theme.md#nativethemeshouldusedarkcolors-readonly) API. - ### `systemPreferences.isSwipeTrackingFromScrollEventsEnabled()` _macOS_ -Returns `Boolean` - Whether the Swipe between pages setting is on. +Returns `boolean` - Whether the Swipe between pages setting is on. ### `systemPreferences.postNotification(event, userInfo[, deliverImmediately])` _macOS_ -* `event` String -* `userInfo` Record<String, any> -* `deliverImmediately` Boolean (optional) - `true` to post notifications immediately even when the subscribing app is inactive. +* `event` string +* `userInfo` Record\<string, any\> +* `deliverImmediately` boolean (optional) - `true` to post notifications immediately even when the subscribing app is inactive. Posts `event` as native notifications of macOS. The `userInfo` is an Object that contains the user information dictionary sent along with the notification. ### `systemPreferences.postLocalNotification(event, userInfo)` _macOS_ -* `event` String -* `userInfo` Record<String, any> +* `event` string +* `userInfo` Record\<string, any\> Posts `event` as native notifications of macOS. The `userInfo` is an Object that contains the user information dictionary sent along with the notification. ### `systemPreferences.postWorkspaceNotification(event, userInfo)` _macOS_ -* `event` String -* `userInfo` Record<String, any> +* `event` string +* `userInfo` Record\<string, any\> Posts `event` as native notifications of macOS. The `userInfo` is an Object that contains the user information dictionary sent along with the notification. ### `systemPreferences.subscribeNotification(event, callback)` _macOS_ -* `event` String +* `event` string | null * `callback` Function - * `event` String - * `userInfo` Record<String, unknown> - * `object` String + * `event` string + * `userInfo` Record\<string, unknown\> + * `object` string -Returns `Number` - The ID of this subscription +Returns `number` - The ID of this subscription Subscribes to native notifications of macOS, `callback` will be called with `callback(event, userInfo)` when the corresponding `event` happens. The @@ -109,30 +86,38 @@ example values of `event` are: * `AppleColorPreferencesChangedNotification` * `AppleShowScrollBarsSettingChanged` +If `event` is null, the `NSDistributedNotificationCenter` doesn’t use it as criteria for delivery to the observer. See [docs](https://developer.apple.com/documentation/foundation/nsnotificationcenter/1411723-addobserverforname?language=objc) for more information. + ### `systemPreferences.subscribeLocalNotification(event, callback)` _macOS_ -* `event` String +* `event` string | null * `callback` Function - * `event` String - * `userInfo` Record<String, unknown> - * `object` String + * `event` string + * `userInfo` Record\<string, unknown\> + * `object` string -Returns `Number` - The ID of this subscription +Returns `number` - The ID of this subscription Same as `subscribeNotification`, but uses `NSNotificationCenter` for local defaults. This is necessary for events such as `NSUserDefaultsDidChangeNotification`. +If `event` is null, the `NSNotificationCenter` doesn’t use it as criteria for delivery to the observer. See [docs](https://developer.apple.com/documentation/foundation/nsnotificationcenter/1411723-addobserverforname?language=objc) for more information. + ### `systemPreferences.subscribeWorkspaceNotification(event, callback)` _macOS_ -* `event` String +* `event` string | null * `callback` Function - * `event` String - * `userInfo` Record<String, unknown> - * `object` String + * `event` string + * `userInfo` Record\<string, unknown\> + * `object` string + +Returns `number` - The ID of this subscription Same as `subscribeNotification`, but uses `NSWorkspace.sharedWorkspace.notificationCenter`. This is necessary for events such as `NSWorkspaceDidActivateApplicationNotification`. +If `event` is null, the `NSWorkspaceNotificationCenter` doesn’t use it as criteria for delivery to the observer. See [docs](https://developer.apple.com/documentation/foundation/nsnotificationcenter/1411723-addobserverforname?language=objc) for more information. + ### `systemPreferences.unsubscribeNotification(id)` _macOS_ * `id` Integer @@ -153,17 +138,17 @@ Same as `unsubscribeNotification`, but removes the subscriber from `NSWorkspace. ### `systemPreferences.registerDefaults(defaults)` _macOS_ -* `defaults` Record<String, String | Boolean | Number> - a dictionary of (`key: value`) user defaults +* `defaults` Record\<string, string | boolean | number\> - a dictionary of (`key: value`) user defaults Add the specified defaults to your application's `NSUserDefaults`. -### `systemPreferences.getUserDefault(key, type)` _macOS_ +### `systemPreferences.getUserDefault<Type extends keyof UserDefaultTypes>(key, type)` _macOS_ -* `key` String -* `type` String - Can be `string`, `boolean`, `integer`, `float`, `double`, +* `key` string +* `type` Type - Can be `string`, `boolean`, `integer`, `float`, `double`, `url`, `array` or `dictionary`. -Returns `any` - The value of `key` in `NSUserDefaults`. +Returns [`UserDefaultTypes[Type]`](structures/user-default-types.md) - The value of `key` in `NSUserDefaults`. Some popular `key` and `type`s are: @@ -175,11 +160,11 @@ Some popular `key` and `type`s are: * `NSPreferredWebServices`: `dictionary` * `NSUserDictionaryReplacementItems`: `array` -### `systemPreferences.setUserDefault(key, type, value)` _macOS_ +### `systemPreferences.setUserDefault<Type extends keyof UserDefaultTypes>(key, type, value)` _macOS_ -* `key` String -* `type` String - Can be `string`, `boolean`, `integer`, `float`, `double`, `url`, `array` or `dictionary`. -* `value` String +* `key` string +* `type` Type - Can be `string`, `boolean`, `integer`, `float`, `double`, `url`, `array` or `dictionary`. +* `value` UserDefaultTypes\[Type] Set the value of `key` in `NSUserDefaults`. @@ -192,46 +177,14 @@ Some popular `key` and `type`s are: ### `systemPreferences.removeUserDefault(key)` _macOS_ -* `key` String +* `key` string Removes the `key` in `NSUserDefaults`. This can be used to restore the default or global value of a `key` previously set with `setUserDefault`. -### `systemPreferences.isAeroGlassEnabled()` _Windows_ - -Returns `Boolean` - `true` if [DWM composition][dwm-composition] (Aero Glass) is -enabled, and `false` otherwise. - -An example of using it to determine if you should create a transparent window or -not (transparent windows won't work correctly when DWM composition is disabled): +### `systemPreferences.getAccentColor()` -```javascript -const { BrowserWindow, systemPreferences } = require('electron') -const browserOptions = { width: 1000, height: 800 } - -// Make the window transparent only if the platform supports it. -if (process.platform !== 'win32' || systemPreferences.isAeroGlassEnabled()) { - browserOptions.transparent = true - browserOptions.frame = false -} - -// Create the window. -const win = new BrowserWindow(browserOptions) - -// Navigate. -if (browserOptions.transparent) { - win.loadURL(`file://${__dirname}/index.html`) -} else { - // No transparency, so we load a fallback that uses basic styles. - win.loadURL(`file://${__dirname}/fallback.html`) -} -``` - -[dwm-composition]:https://msdn.microsoft.com/en-us/library/windows/desktop/aa969540.aspx - -### `systemPreferences.getAccentColor()` _Windows_ _macOS_ - -Returns `String` - The users current system wide accent color preference in RGBA +Returns `string` - The users current system wide accent color preference in RGBA hexadecimal form. ```js @@ -246,7 +199,7 @@ This API is only available on macOS 10.14 Mojave or newer. ### `systemPreferences.getColor(color)` _Windows_ _macOS_ -* `color` String - One of the following values: +* `color` string - One of the following values: * On **Windows**: * `3d-dark-shadow` - Dark shadow for three-dimensional display elements. * `3d-face` - Face color for three-dimensional display elements and for dialog @@ -289,7 +242,6 @@ This API is only available on macOS 10.14 Mojave or newer. * `window-frame` - Window frame. * `window-text` - Text in windows. * On **macOS** - * `alternate-selected-control-text` - The text on a selected surface in a list or table. _deprecated_ * `control-background` - The background of a large interface element, such as a browser or table. * `control` - The surface of a control. * `control-text` -The text of a control that isn’t disabled. @@ -323,17 +275,17 @@ This API is only available on macOS 10.14 Mojave or newer. * `window-background` - The background of a window. * `window-frame-text` - The text in the window's titlebar area. -Returns `String` - The system color setting in RGB hexadecimal form (`#ABCDEF`). +Returns `string` - The system color setting in RGBA hexadecimal form (`#RRGGBBAA`). See the [Windows docs][windows-colors] and the [macOS docs][macos-colors] for more details. The following colors are only available on macOS 10.14: `find-highlight`, `selected-content-background`, `separator`, `unemphasized-selected-content-background`, `unemphasized-selected-text-background`, and `unemphasized-selected-text`. -[windows-colors]:https://msdn.microsoft.com/en-us/library/windows/desktop/ms724371(v=vs.85).aspx -[macos-colors]:https://developer.apple.com/design/human-interface-guidelines/macos/visual-design/color#dynamic-system-colors +[windows-colors]: https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getsyscolor +[macos-colors]: https://developer.apple.com/design/human-interface-guidelines/macos/visual-design/color#dynamic-system-colors ### `systemPreferences.getSystemColor(color)` _macOS_ -* `color` String - One of the following values: +* `color` string - One of the following values: * `blue` * `brown` * `gray` @@ -344,57 +296,28 @@ The following colors are only available on macOS 10.14: `find-highlight`, `selec * `red` * `yellow` -Returns `String` - The standard system color formatted as `#RRGGBBAA`. +Returns `string` - The standard system color formatted as `#RRGGBBAA`. Returns one of several standard system colors that automatically adapt to vibrancy and changes in accessibility settings like 'Increase contrast' and 'Reduce transparency'. See [Apple Documentation](https://developer.apple.com/design/human-interface-guidelines/macos/visual-design/color#system-colors) for more details. -### `systemPreferences.isInvertedColorScheme()` _Windows_ _Deprecated_ - -Returns `Boolean` - `true` if an inverted color scheme (a high contrast color scheme with light text and dark backgrounds) is active, `false` otherwise. - -**Deprecated:** Should use the new [`nativeTheme.shouldUseInvertedColorScheme`](native-theme.md#nativethemeshoulduseinvertedcolorscheme-macos-windows-readonly) API. - -### `systemPreferences.isHighContrastColorScheme()` _macOS_ _Windows_ _Deprecated_ - -Returns `Boolean` - `true` if a high contrast theme is active, `false` otherwise. - -**Deprecated:** Should use the new [`nativeTheme.shouldUseHighContrastColors`](native-theme.md#nativethemeshouldusehighcontrastcolors-macos-windows-readonly) API. - ### `systemPreferences.getEffectiveAppearance()` _macOS_ -Returns `String` - Can be `dark`, `light` or `unknown`. +Returns `string` - Can be `dark`, `light` or `unknown`. Gets the macOS appearance setting that is currently applied to your application, maps to [NSApplication.effectiveAppearance](https://developer.apple.com/documentation/appkit/nsapplication/2967171-effectiveappearance?language=objc) -### `systemPreferences.getAppLevelAppearance()` _macOS_ _Deprecated_ - -Returns `String` | `null` - Can be `dark`, `light` or `unknown`. - -Gets the macOS appearance setting that you have declared you want for -your application, maps to [NSApplication.appearance](https://developer.apple.com/documentation/appkit/nsapplication/2967170-appearance?language=objc). -You can use the `setAppLevelAppearance` API to set this value. - -### `systemPreferences.setAppLevelAppearance(appearance)` _macOS_ _Deprecated_ - -* `appearance` String | null - Can be `dark` or `light` - -Sets the appearance setting for your application, this should override the -system default and override the value of `getEffectiveAppearance`. - ### `systemPreferences.canPromptTouchID()` _macOS_ -Returns `Boolean` - whether or not this device has the ability to use Touch ID. - -**NOTE:** This API will return `false` on macOS systems older than Sierra 10.12.2. +Returns `boolean` - whether or not this device has the ability to use Touch ID. ### `systemPreferences.promptTouchID(reason)` _macOS_ -* `reason` String - The reason you are asking for Touch ID authentication +* `reason` string - The reason you are asking for Touch ID authentication Returns `Promise<void>` - resolves if the user has successfully authenticated with Touch ID. -```javascript +```js const { systemPreferences } = require('electron') systemPreferences.promptTouchID('To get consent for a Security-Gated Thing').then(success => { @@ -406,21 +329,19 @@ systemPreferences.promptTouchID('To get consent for a Security-Gated Thing').the This API itself will not protect your user data; rather, it is a mechanism to allow you to do so. Native apps will need to set [Access Control Constants](https://developer.apple.com/documentation/security/secaccesscontrolcreateflags?language=objc) like [`kSecAccessControlUserPresence`](https://developer.apple.com/documentation/security/secaccesscontrolcreateflags/ksecaccesscontroluserpresence?language=objc) on their keychain entry so that reading it would auto-prompt for Touch ID biometric consent. This could be done with [`node-keytar`](https://github.com/atom/node-keytar), such that one would store an encryption key with `node-keytar` and only fetch it if `promptTouchID()` resolves. -**NOTE:** This API will return a rejected Promise on macOS systems older than Sierra 10.12.2. - ### `systemPreferences.isTrustedAccessibilityClient(prompt)` _macOS_ -* `prompt` Boolean - whether or not the user will be informed via prompt if the current process is untrusted. +* `prompt` boolean - whether or not the user will be informed via prompt if the current process is untrusted. -Returns `Boolean` - `true` if the current process is a trusted accessibility client and `false` if it is not. +Returns `boolean` - `true` if the current process is a trusted accessibility client and `false` if it is not. ### `systemPreferences.getMediaAccessStatus(mediaType)` _Windows_ _macOS_ -* `mediaType` String - Can be `microphone`, `camera` or `screen`. +* `mediaType` string - Can be `microphone`, `camera` or `screen`. -Returns `String` - Can be `not-determined`, `granted`, `denied`, `restricted` or `unknown`. +Returns `string` - Can be `not-determined`, `granted`, `denied`, `restricted` or `unknown`. -This user consent was not required on macOS 10.13 High Sierra or lower so this method will always return `granted`. +This user consent was not required on macOS 10.13 High Sierra so this method will always return `granted`. macOS 10.14 Mojave or higher requires consent for `microphone` and `camera` access. macOS 10.15 Catalina or higher requires consent for `screen` access. @@ -429,39 +350,35 @@ It will always return `granted` for `screen` and for all media types on older ve ### `systemPreferences.askForMediaAccess(mediaType)` _macOS_ -* `mediaType` String - the type of media being requested; can be `microphone`, `camera`. +* `mediaType` string - the type of media being requested; can be `microphone`, `camera`. -Returns `Promise<Boolean>` - A promise that resolves with `true` if consent was granted and `false` if it was denied. If an invalid `mediaType` is passed, the promise will be rejected. If an access request was denied and later is changed through the System Preferences pane, a restart of the app will be required for the new permissions to take effect. If access has already been requested and denied, it _must_ be changed through the preference pane; an alert will not pop up and the promise will resolve with the existing access status. +Returns `Promise<boolean>` - A promise that resolves with `true` if consent was granted and `false` if it was denied. If an invalid `mediaType` is passed, the promise will be rejected. If an access request was denied and later is changed through the System Preferences pane, a restart of the app will be required for the new permissions to take effect. If access has already been requested and denied, it _must_ be changed through the preference pane; an alert will not pop up and the promise will resolve with the existing access status. -**Important:** In order to properly leverage this API, you [must set](https://developer.apple.com/documentation/avfoundation/cameras_and_media_capture/requesting_authorization_for_media_capture_on_macos?language=objc) the `NSMicrophoneUsageDescription` and `NSCameraUsageDescription` strings in your app's `Info.plist` file. The values for these keys will be used to populate the permission dialogs so that the user will be properly informed as to the purpose of the permission request. See [Electron Application Distribution](https://electronjs.org/docs/tutorial/application-distribution#macos) for more information about how to set these in the context of Electron. +**Important:** In order to properly leverage this API, you [must set](https://developer.apple.com/documentation/avfoundation/cameras_and_media_capture/requesting_authorization_for_media_capture_on_macos?language=objc) the `NSMicrophoneUsageDescription` and `NSCameraUsageDescription` strings in your app's `Info.plist` file. The values for these keys will be used to populate the permission dialogs so that the user will be properly informed as to the purpose of the permission request. See [Electron Application Distribution](../tutorial/application-distribution.md#rebranding-with-downloaded-binaries) for more information about how to set these in the context of Electron. -This user consent was not required until macOS 10.14 Mojave, so this method will always return `true` if your system is running 10.13 High Sierra or lower. +This user consent was not required until macOS 10.14 Mojave, so this method will always return `true` if your system is running 10.13 High Sierra. ### `systemPreferences.getAnimationSettings()` Returns `Object`: -* `shouldRenderRichAnimation` Boolean - Returns true if rich animations should be rendered. Looks at session type (e.g. remote desktop) and accessibility settings to give guidance for heavy animations. -* `scrollAnimationsEnabledBySystem` Boolean - Determines on a per-platform basis whether scroll animations (e.g. produced by home/end key) should be enabled. -* `prefersReducedMotion` Boolean - Determines whether the user desires reduced motion based on platform APIs. +* `shouldRenderRichAnimation` boolean - Returns true if rich animations should be rendered. Looks at session type (e.g. remote desktop) and accessibility settings to give guidance for heavy animations. +* `scrollAnimationsEnabledBySystem` boolean - Determines on a per-platform basis whether scroll animations (e.g. produced by home/end key) should be enabled. +* `prefersReducedMotion` boolean - Determines whether the user desires reduced motion based on platform APIs. Returns an object with system animation settings. ## Properties -### `systemPreferences.appLevelAppearance` _macOS_ - -A `String` property that can be `dark`, `light` or `unknown`. It determines the macOS appearance setting for -your application. This maps to values in: [NSApplication.appearance](https://developer.apple.com/documentation/appkit/nsapplication/2967170-appearance?language=objc). Setting this will override the -system default as well as the value of `getEffectiveAppearance`. +### `systemPreferences.accessibilityDisplayShouldReduceTransparency` _macOS_ _Deprecated_ -Possible values that can be set are `dark` and `light`, and possible return values are `dark`, `light`, and `unknown`. +A `boolean` property which determines whether the app avoids using semitransparent backgrounds. This maps to [NSWorkspace.accessibilityDisplayShouldReduceTransparency](https://developer.apple.com/documentation/appkit/nsworkspace/1533006-accessibilitydisplayshouldreduce) -This property is only available on macOS 10.14 Mojave or newer. +**Deprecated:** Use the new [`nativeTheme.prefersReducedTransparency`](native-theme.md#nativethemeprefersreducedtransparency-readonly) API. ### `systemPreferences.effectiveAppearance` _macOS_ _Readonly_ -A `String` property that can be `dark`, `light` or `unknown`. +A `string` property that can be `dark`, `light` or `unknown`. Returns the macOS appearance setting that is currently applied to your application, maps to [NSApplication.effectiveAppearance](https://developer.apple.com/documentation/appkit/nsapplication/2967171-effectiveappearance?language=objc) diff --git a/docs/api/touch-bar-button.md b/docs/api/touch-bar-button.md index 290e0d0a40782..4d9caaf4822f0 100644 --- a/docs/api/touch-bar-button.md +++ b/docs/api/touch-bar-button.md @@ -2,19 +2,20 @@ > Create a button in the touch bar for native macOS applications -Process: [Main](../glossary.md#main-process) +Process: [Main](../glossary.md#main-process)<br /> +_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ ### `new TouchBarButton(options)` * `options` Object - * `label` String (optional) - Button text. - * `accessibilityLabel` String (optional) - A short description of the button for use by screenreaders like VoiceOver. - * `backgroundColor` String (optional) - Button background color in hex format, + * `label` string (optional) - Button text. + * `accessibilityLabel` string (optional) - A short description of the button for use by screenreaders like VoiceOver. + * `backgroundColor` string (optional) - Button background color in hex format, i.e `#ABCDEF`. - * `icon` [NativeImage](native-image.md) | String (optional) - Button icon. - * `iconPosition` String (optional) - Can be `left`, `right` or `overlay`. Defaults to `overlay`. + * `icon` [NativeImage](native-image.md) | string (optional) - Button icon. + * `iconPosition` string (optional) - Can be `left`, `right` or `overlay`. Defaults to `overlay`. * `click` Function (optional) - Function to call when the button is clicked. - * `enabled` Boolean (optional) - Whether the button is in an enabled state. Default is `true`. + * `enabled` boolean (optional) - Whether the button is in an enabled state. Default is `true`. When defining `accessibilityLabel`, ensure you have considered macOS [best practices](https://developer.apple.com/documentation/appkit/nsaccessibilitybutton/1524910-accessibilitylabel?language=objc). @@ -24,16 +25,16 @@ The following properties are available on instances of `TouchBarButton`: #### `touchBarButton.accessibilityLabel` -A `String` representing the description of the button to be read by a screen reader. Will only be read by screen readers if no label is set. +A `string` representing the description of the button to be read by a screen reader. Will only be read by screen readers if no label is set. #### `touchBarButton.label` -A `String` representing the button's current text. Changing this value immediately updates the button +A `string` representing the button's current text. Changing this value immediately updates the button in the touch bar. #### `touchBarButton.backgroundColor` -A `String` hex code representing the button's current background color. Changing this value immediately updates +A `string` hex code representing the button's current background color. Changing this value immediately updates the button in the touch bar. #### `touchBarButton.icon` @@ -43,8 +44,8 @@ in the touch bar. #### `touchBarButton.iconPosition` -A `String` - Can be `left`, `right` or `overlay`. Defaults to `overlay`. +A `string` - Can be `left`, `right` or `overlay`. Defaults to `overlay`. #### `touchBarButton.enabled` -A `Boolean` representing whether the button is in an enabled state. +A `boolean` representing whether the button is in an enabled state. diff --git a/docs/api/touch-bar-color-picker.md b/docs/api/touch-bar-color-picker.md index 9a50a0d531fa4..a80954adbb6a6 100644 --- a/docs/api/touch-bar-color-picker.md +++ b/docs/api/touch-bar-color-picker.md @@ -2,17 +2,18 @@ > Create a color picker in the touch bar for native macOS applications -Process: [Main](../glossary.md#main-process) +Process: [Main](../glossary.md#main-process)<br /> +_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ ### `new TouchBarColorPicker(options)` * `options` Object - * `availableColors` String[] (optional) - Array of hex color strings to + * `availableColors` string[] (optional) - Array of hex color strings to appear as possible colors to select. - * `selectedColor` String (optional) - The selected hex color in the picker, + * `selectedColor` string (optional) - The selected hex color in the picker, i.e `#ABCDEF`. * `change` Function (optional) - Function to call when a color is selected. - * `color` String - The color that the user selected from the picker. + * `color` string - The color that the user selected from the picker. ### Instance Properties @@ -20,10 +21,10 @@ The following properties are available on instances of `TouchBarColorPicker`: #### `touchBarColorPicker.availableColors` -A `String[]` array representing the color picker's available colors to select. Changing this value immediately +A `string[]` array representing the color picker's available colors to select. Changing this value immediately updates the color picker in the touch bar. #### `touchBarColorPicker.selectedColor` -A `String` hex code representing the color picker's currently selected color. Changing this value immediately +A `string` hex code representing the color picker's currently selected color. Changing this value immediately updates the color picker in the touch bar. diff --git a/docs/api/touch-bar-group.md b/docs/api/touch-bar-group.md index 4c1f0866d283c..a04b2279d0b5d 100644 --- a/docs/api/touch-bar-group.md +++ b/docs/api/touch-bar-group.md @@ -2,7 +2,8 @@ > Create a group in the touch bar for native macOS applications -Process: [Main](../glossary.md#main-process) +Process: [Main](../glossary.md#main-process)<br /> +_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ ### `new TouchBarGroup(options)` diff --git a/docs/api/touch-bar-label.md b/docs/api/touch-bar-label.md index 33fd244db490c..c774fb804690b 100644 --- a/docs/api/touch-bar-label.md +++ b/docs/api/touch-bar-label.md @@ -2,14 +2,15 @@ > Create a label in the touch bar for native macOS applications -Process: [Main](../glossary.md#main-process) +Process: [Main](../glossary.md#main-process)<br /> +_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ ### `new TouchBarLabel(options)` * `options` Object - * `label` String (optional) - Text to display. - * `accessibilityLabel` String (optional) - A short description of the button for use by screenreaders like VoiceOver. - * `textColor` String (optional) - Hex color of text, i.e `#ABCDEF`. + * `label` string (optional) - Text to display. + * `accessibilityLabel` string (optional) - A short description of the button for use by screenreaders like VoiceOver. + * `textColor` string (optional) - Hex color of text, i.e `#ABCDEF`. When defining `accessibilityLabel`, ensure you have considered macOS [best practices](https://developer.apple.com/documentation/appkit/nsaccessibilitybutton/1524910-accessibilitylabel?language=objc). @@ -19,14 +20,14 @@ The following properties are available on instances of `TouchBarLabel`: #### `touchBarLabel.label` -A `String` representing the label's current text. Changing this value immediately updates the label in +A `string` representing the label's current text. Changing this value immediately updates the label in the touch bar. #### `touchBarLabel.accessibilityLabel` -A `String` representing the description of the label to be read by a screen reader. +A `string` representing the description of the label to be read by a screen reader. #### `touchBarLabel.textColor` -A `String` hex code representing the label's current text color. Changing this value immediately updates the +A `string` hex code representing the label's current text color. Changing this value immediately updates the label in the touch bar. diff --git a/docs/api/touch-bar-other-items-proxy.md b/docs/api/touch-bar-other-items-proxy.md index a4e76def11edb..efad02d070c70 100644 --- a/docs/api/touch-bar-other-items-proxy.md +++ b/docs/api/touch-bar-other-items-proxy.md @@ -4,9 +4,11 @@ > from Chromium at the space indicated by the proxy. By default, this proxy is added > to each TouchBar at the end of the input. For more information, see the AppKit docs on > [NSTouchBarItemIdentifierOtherItemsProxy](https://developer.apple.com/documentation/appkit/nstouchbaritemidentifierotheritemsproxy) -> -> Note: Only one instance of this class can be added per TouchBar. -Process: [Main](../glossary.md#main-process) +> [!NOTE] +> Only one instance of this class can be added per TouchBar. + +Process: [Main](../glossary.md#main-process)<br /> +_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ ### `new TouchBarOtherItemsProxy()` diff --git a/docs/api/touch-bar-popover.md b/docs/api/touch-bar-popover.md index 961f7072a4daa..2fae3b1af3f6e 100644 --- a/docs/api/touch-bar-popover.md +++ b/docs/api/touch-bar-popover.md @@ -2,15 +2,16 @@ > Create a popover in the touch bar for native macOS applications -Process: [Main](../glossary.md#main-process) +Process: [Main](../glossary.md#main-process)<br /> +_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ ### `new TouchBarPopover(options)` * `options` Object - * `label` String (optional) - Popover button text. + * `label` string (optional) - Popover button text. * `icon` [NativeImage](native-image.md) (optional) - Popover button icon. * `items` [TouchBar](touch-bar.md) - Items to display in the popover. - * `showCloseButton` Boolean (optional) - `true` to display a close button + * `showCloseButton` boolean (optional) - `true` to display a close button on the left of the popover, `false` to not show it. Default is `true`. ### Instance Properties @@ -19,7 +20,7 @@ The following properties are available on instances of `TouchBarPopover`: #### `touchBarPopover.label` -A `String` representing the popover's current button text. Changing this value immediately updates the +A `string` representing the popover's current button text. Changing this value immediately updates the popover in the touch bar. #### `touchBarPopover.icon` diff --git a/docs/api/touch-bar-scrubber.md b/docs/api/touch-bar-scrubber.md index c21f6e1383fd2..a64f309c388f7 100644 --- a/docs/api/touch-bar-scrubber.md +++ b/docs/api/touch-bar-scrubber.md @@ -2,7 +2,8 @@ > Create a scrubber (a scrollable selector) -Process: [Main](../glossary.md#main-process) +Process: [Main](../glossary.md#main-process)<br /> +_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ ### `new TouchBarScrubber(options)` @@ -12,11 +13,11 @@ Process: [Main](../glossary.md#main-process) * `selectedIndex` Integer - The index of the item the user selected. * `highlight` Function (optional) - Called when the user taps any item. * `highlightedIndex` Integer - The index of the item the user touched. - * `selectedStyle` String (optional) - Selected item style. Can be `background`, `outline` or `none`. Defaults to `none`. - * `overlayStyle` String (optional) - Selected overlay item style. Can be `background`, `outline` or `none`. Defaults to `none`. - * `showArrowButtons` Boolean (optional) - Defaults to `false`. - * `mode` String (optional) - Can be `fixed` or `free`. The default is `free`. - * `continuous` Boolean (optional) - Defaults to `true`. + * `selectedStyle` string (optional) - Selected item style. Can be `background`, `outline` or `none`. Defaults to `none`. + * `overlayStyle` string (optional) - Selected overlay item style. Can be `background`, `outline` or `none`. Defaults to `none`. + * `showArrowButtons` boolean (optional) - Whether to show arrow buttons. Defaults to `false` and is only shown if `items` is non-empty. + * `mode` string (optional) - Can be `fixed` or `free`. The default is `free`. + * `continuous` boolean (optional) - Defaults to `true`. ### Instance Properties @@ -29,7 +30,7 @@ updates the control in the touch bar. Updating deep properties inside this array #### `touchBarScrubber.selectedStyle` -A `String` representing the style that selected items in the scrubber should have. Updating this value immediately +A `string` representing the style that selected items in the scrubber should have. Updating this value immediately updates the control in the touch bar. Possible values: * `background` - Maps to `[NSScrubberSelectionStyle roundedBackgroundStyle]`. @@ -38,7 +39,7 @@ updates the control in the touch bar. Possible values: #### `touchBarScrubber.overlayStyle` -A `String` representing the style that selected items in the scrubber should have. This style is overlayed on top +A `string` representing the style that selected items in the scrubber should have. This style is overlaid on top of the scrubber item instead of being placed behind it. Updating this value immediately updates the control in the touch bar. Possible values: @@ -48,12 +49,12 @@ touch bar. Possible values: #### `touchBarScrubber.showArrowButtons` -A `Boolean` representing whether to show the left / right selection arrows in this scrubber. Updating this value +A `boolean` representing whether to show the left / right selection arrows in this scrubber. Updating this value immediately updates the control in the touch bar. #### `touchBarScrubber.mode` -A `String` representing the mode of this scrubber. Updating this value immediately +A `string` representing the mode of this scrubber. Updating this value immediately updates the control in the touch bar. Possible values: * `fixed` - Maps to `NSScrubberModeFixed`. @@ -61,5 +62,5 @@ updates the control in the touch bar. Possible values: #### `touchBarScrubber.continuous` -A `Boolean` representing whether this scrubber is continuous or not. Updating this value immediately +A `boolean` representing whether this scrubber is continuous or not. Updating this value immediately updates the control in the touch bar. diff --git a/docs/api/touch-bar-segmented-control.md b/docs/api/touch-bar-segmented-control.md index f25604592e17b..53d60622480d3 100644 --- a/docs/api/touch-bar-segmented-control.md +++ b/docs/api/touch-bar-segmented-control.md @@ -2,12 +2,13 @@ > Create a segmented control (a button group) where one button has a selected state -Process: [Main](../glossary.md#main-process) +Process: [Main](../glossary.md#main-process)<br /> +_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ ### `new TouchBarSegmentedControl(options)` * `options` Object - * `segmentStyle` String (optional) - Style of the segments: + * `segmentStyle` string (optional) - Style of the segments: * `automatic` - Default. The appearance of the segmented control is automatically determined based on the type of window in which the control is displayed and the position within the window. Maps to `NSSegmentStyleAutomatic`. @@ -21,7 +22,7 @@ Process: [Main](../glossary.md#main-process) * `small-square` - The control is displayed using the small square style. Maps to `NSSegmentStyleSmallSquare`. * `separated` - The segments in the control are displayed very close to each other but not touching. Maps to `NSSegmentStyleSeparated`. - * `mode` String (optional) - The selection mode of the control: + * `mode` string (optional) - The selection mode of the control: * `single` - Default. One item selected at a time, selecting one deselects the previously selected item. Maps to `NSSegmentSwitchTrackingSelectOne`. * `multiple` - Multiple items can be selected at a time. Maps to `NSSegmentSwitchTrackingSelectAny`. * `buttons` - Make the segments act as buttons, each segment can be pressed and released but never marked as active. Maps to `NSSegmentSwitchTrackingMomentary`. @@ -29,7 +30,7 @@ Process: [Main](../glossary.md#main-process) * `selectedIndex` Integer (optional) - The index of the currently selected segment, will update automatically with user interaction. When the mode is `multiple` it will be the last selected item. * `change` Function (optional) - Called when the user selects a new segment. * `selectedIndex` Integer - The index of the segment the user selected. - * `isSelected` Boolean - Whether as a result of user selection the segment is selected or not. + * `isSelected` boolean - Whether as a result of user selection the segment is selected or not. ### Instance Properties @@ -37,7 +38,7 @@ The following properties are available on instances of `TouchBarSegmentedControl #### `touchBarSegmentedControl.segmentStyle` -A `String` representing the controls current segment style. Updating this value immediately updates the control +A `string` representing the controls current segment style. Updating this value immediately updates the control in the touch bar. #### `touchBarSegmentedControl.segments` @@ -52,4 +53,4 @@ in the touch bar. User interaction with the touch bar will update this value aut #### `touchBarSegmentedControl.mode` -A `String` representing the current selection mode of the control. Can be `single`, `multiple` or `buttons`. +A `string` representing the current selection mode of the control. Can be `single`, `multiple` or `buttons`. diff --git a/docs/api/touch-bar-slider.md b/docs/api/touch-bar-slider.md index 8bfdb5fc9643e..16036ffcf5b56 100644 --- a/docs/api/touch-bar-slider.md +++ b/docs/api/touch-bar-slider.md @@ -2,17 +2,18 @@ > Create a slider in the touch bar for native macOS applications -Process: [Main](../glossary.md#main-process) +Process: [Main](../glossary.md#main-process)<br /> +_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ ### `new TouchBarSlider(options)` * `options` Object - * `label` String (optional) - Label text. + * `label` string (optional) - Label text. * `value` Integer (optional) - Selected value. * `minValue` Integer (optional) - Minimum value. * `maxValue` Integer (optional) - Maximum value. * `change` Function (optional) - Function to call when the slider is changed. - * `newValue` Number - The value that the user selected on the Slider. + * `newValue` number - The value that the user selected on the Slider. ### Instance Properties @@ -20,20 +21,20 @@ The following properties are available on instances of `TouchBarSlider`: #### `touchBarSlider.label` -A `String` representing the slider's current text. Changing this value immediately updates the slider +A `string` representing the slider's current text. Changing this value immediately updates the slider in the touch bar. #### `touchBarSlider.value` -A `Number` representing the slider's current value. Changing this value immediately updates the slider +A `number` representing the slider's current value. Changing this value immediately updates the slider in the touch bar. #### `touchBarSlider.minValue` -A `Number` representing the slider's current minimum value. Changing this value immediately updates the +A `number` representing the slider's current minimum value. Changing this value immediately updates the slider in the touch bar. #### `touchBarSlider.maxValue` -A `Number` representing the slider's current maximum value. Changing this value immediately updates the +A `number` representing the slider's current maximum value. Changing this value immediately updates the slider in the touch bar. diff --git a/docs/api/touch-bar-spacer.md b/docs/api/touch-bar-spacer.md index de13c8d4e94be..79f4a7bd5ecb4 100644 --- a/docs/api/touch-bar-spacer.md +++ b/docs/api/touch-bar-spacer.md @@ -2,12 +2,13 @@ > Create a spacer between two items in the touch bar for native macOS applications -Process: [Main](../glossary.md#main-process) +Process: [Main](../glossary.md#main-process)<br /> +_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ ### `new TouchBarSpacer(options)` * `options` Object - * `size` String (optional) - Size of spacer, possible values are: + * `size` string (optional) - Size of spacer, possible values are: * `small` - Small space between items. Maps to `NSTouchBarItemIdentifierFixedSpaceSmall`. This is the default. * `large` - Large space between items. Maps to `NSTouchBarItemIdentifierFixedSpaceLarge`. * `flexible` - Take up all available space. Maps to `NSTouchBarItemIdentifierFlexibleSpace`. @@ -18,4 +19,4 @@ The following properties are available on instances of `TouchBarSpacer`: #### `touchBarSpacer.size` -A `String` representing the size of the spacer. Can be `small`, `large` or `flexible`. +A `string` representing the size of the spacer. Can be `small`, `large` or `flexible`. diff --git a/docs/api/touch-bar.md b/docs/api/touch-bar.md index 62afc0e251067..6ff301dbe53b9 100644 --- a/docs/api/touch-bar.md +++ b/docs/api/touch-bar.md @@ -1,3 +1,9 @@ +# TouchBar + +> [!WARNING] +> Electron's built-in classes cannot be subclassed in user code. +> For more information, see [the FAQ](../faq.md#class-inheritance-does-not-work-with-electron-built-in-modules). + ## Class: TouchBar > Create TouchBar layouts for native macOS applications @@ -13,12 +19,9 @@ Process: [Main](../glossary.md#main-process) Creates a new touch bar with the specified items. Use `BrowserWindow.setTouchBar` to add the `TouchBar` to a window. -**Note:** The TouchBar API is currently experimental and may change or be -removed in future Electron releases. - -**Tip:** If you don't have a MacBook with Touch Bar, you can use -[Touch Bar Simulator](https://github.com/sindresorhus/touch-bar-simulator) -to test Touch Bar usage in your app. +> [!NOTE] +> The TouchBar API is currently experimental and may change or be +> removed in future Electron releases. ### Static Properties @@ -77,7 +80,7 @@ immediately updates the escape item in the touch bar. Below is an example of a simple slot machine touch bar game with a button and some labels. -```javascript +```js const { app, BrowserWindow, TouchBar } = require('electron') const { TouchBarLabel, TouchBarButton, TouchBarSpacer } = TouchBar @@ -85,12 +88,12 @@ const { TouchBarLabel, TouchBarButton, TouchBarSpacer } = TouchBar let spinning = false // Reel labels -const reel1 = new TouchBarLabel() -const reel2 = new TouchBarLabel() -const reel3 = new TouchBarLabel() +const reel1 = new TouchBarLabel({ label: '' }) +const reel2 = new TouchBarLabel({ label: '' }) +const reel3 = new TouchBarLabel({ label: '' }) // Spin result label -const result = new TouchBarLabel() +const result = new TouchBarLabel({ label: '' }) // Spin button const spin = new TouchBarButton({ diff --git a/docs/api/tray.md b/docs/api/tray.md index 1a6b9cf9a5942..0c7c2e95ac0b8 100644 --- a/docs/api/tray.md +++ b/docs/api/tray.md @@ -1,3 +1,5 @@ +# Tray + ## Class: Tray > Add icons and context menus to the system's notification area. @@ -6,7 +8,7 @@ Process: [Main](../glossary.md#main-process) `Tray` is an [EventEmitter][event-emitter]. -```javascript +```js title='Creating a basic tray menu' const { app, Menu, Tray } = require('electron') let tray = null @@ -23,18 +25,28 @@ app.whenReady().then(() => { }) ``` -__Platform limitations:__ +> [!TIP] +> See also: [A detailed guide about how to implement Tray menus](../tutorial/tray.md). + +> [!WARNING] +> Electron's built-in classes cannot be subclassed in user code. +> For more information, see [the FAQ](../faq.md#class-inheritance-does-not-work-with-electron-built-in-modules). + +**Platform Considerations** -* On Linux the app indicator will be used if it is supported, otherwise +**Linux** + +* Tray icon uses [StatusNotifierItem](https://www.freedesktop.org/wiki/Specifications/StatusNotifierItem/) + by default, when it is not available in user's desktop environment the `GtkStatusIcon` will be used instead. -* On Linux distributions that only have app indicator support, you have to - install `libappindicator1` to make the tray icon work. -* App indicator will only be shown when it has a context menu. -* When app indicator is used on Linux, the `click` event is ignored. -* On Linux in order for changes made to individual `MenuItem`s to take effect, +* The `click` event is emitted when the tray icon receives activation from + user, however the StatusNotifierItem spec does not specify which action would + cause an activation, for some environments it is left mouse click, but for + some it might be double left mouse click. +* In order for changes made to individual `MenuItem`s to take effect, you have to call `setContextMenu` again. For example: -```javascript +```js const { app, Menu, Tray } = require('electron') let appIcon = null @@ -53,15 +65,29 @@ app.whenReady().then(() => { }) ``` -* On Windows it is recommended to use `ICO` icons to get best visual effects. +**MacOS** + +* Icons passed to the Tray constructor should be [Template Images](native-image.md#template-image-macos). +* To make sure your icon isn't grainy on retina monitors, be sure your `@2x` image is 144dpi. +* If you are bundling your application (e.g., with webpack for development), be sure that the file names are not being mangled or hashed. The filename needs to end in Template, and the `@2x` image needs to have the same filename as the standard image, or MacOS will not magically invert your image's colors or use the high density image. +* 16x16 (72dpi) and 32x32@2x (144dpi) work well for most icons. + +**Windows** -If you want to keep exact same behaviors on all platforms, you should not -rely on the `click` event and always attach a context menu to the tray icon. +* It is recommended to use `ICO` icons to get best visual effects. ### `new Tray(image, [guid])` -* `image` ([NativeImage](native-image.md) | String) -* `guid` String (optional) _Windows_ - Assigns a GUID to the tray icon. If the executable is signed and the signature contains an organization in the subject line then the GUID is permanently associated with that signature. OS level settings like the position of the tray icon in the system tray will persist even if the path to the executable changes. If the executable is not code-signed then the GUID is permanently associated with the path to the executable. Changing the path to the executable will break the creation of the tray icon and a new GUID must be used. However, it is highly recommended to use the GUID parameter only in conjunction with code-signed executable. If an App defines multiple tray icons then each icon must use a separate GUID. +* `image` ([NativeImage](native-image.md) | string) +* `guid` string (optional) _Windows_ _macOS_ - A unique string used to identify the tray icon. Must adhere to [UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier) format. + +**Windows** + +On Windows, if the executable is signed and the signature contains an organization in the subject line then the GUID is permanently associated with that signature. OS level settings like the position of the tray icon in the system tray will persist even if the path to the executable changes. If the executable is not code-signed then the GUID is permanently associated with the path to the executable. Changing the path to the executable will break the creation of the tray icon and a new GUID must be used. However, it is highly recommended to use the GUID parameter only in conjunction with code-signed executable. If an App defines multiple tray icons then each icon must use a separate GUID. + +**MacOS** + +On macOS, the `guid` is a string used to uniquely identify the tray icon and allow it to retain its position between relaunches. Using the same string for a new tray item will create it in the same position as the previous tray item to use the string. Creates a new tray icon associated with the `image`. @@ -79,6 +105,9 @@ Returns: Emitted when the tray icon is clicked. +Note that on Linux this event is emitted when the tray icon receives an +activation, which might not necessarily be left mouse click. + #### Event: 'right-click' _macOS_ _Windows_ Returns: @@ -97,6 +126,15 @@ Returns: Emitted when the tray icon is double clicked. +#### Event: 'middle-click' _Windows_ + +Returns: + +* `event` [KeyboardEvent](structures/keyboard-event.md) +* `bounds` [Rectangle](structures/rectangle.md) - The bounds of tray icon. + +Emitted when the tray icon is middle clicked. + #### Event: 'balloon-show' _Windows_ Emitted when the tray balloon shows. @@ -119,7 +157,7 @@ Emitted when any dragged items are dropped on the tray icon. Returns: * `event` Event -* `files` String[] - The paths of the dropped files. +* `files` string[] - The paths of the dropped files. Emitted when dragged files are dropped in the tray icon. @@ -128,7 +166,7 @@ Emitted when dragged files are dropped in the tray icon. Returns: * `event` Event -* `text` String - the dropped text string. +* `text` string - the dropped text string. Emitted when dragged text is dropped in the tray icon. @@ -153,7 +191,8 @@ Returns: Emitted when the mouse is released from clicking the tray icon. -Note: This will not be emitted if you have set a context menu for your Tray using `tray.setContextMenu`, as a result of macOS-level constraints. +> [!NOTE] +> This will not be emitted if you have set a context menu for your Tray using `tray.setContextMenu`, as a result of macOS-level constraints. #### Event: 'mouse-down' _macOS_ @@ -164,7 +203,7 @@ Returns: Emitted when the mouse clicks the tray icon. -#### Event: 'mouse-enter' _macOS_ +#### Event: 'mouse-enter' _macOS_ _Windows_ Returns: @@ -173,7 +212,7 @@ Returns: Emitted when the mouse enters the tray icon. -#### Event: 'mouse-leave' _macOS_ +#### Event: 'mouse-leave' _macOS_ _Windows_ Returns: @@ -201,37 +240,37 @@ Destroys the tray icon immediately. #### `tray.setImage(image)` -* `image` ([NativeImage](native-image.md) | String) +* `image` ([NativeImage](native-image.md) | string) Sets the `image` associated with this tray icon. #### `tray.setPressedImage(image)` _macOS_ -* `image` ([NativeImage](native-image.md) | String) +* `image` ([NativeImage](native-image.md) | string) Sets the `image` associated with this tray icon when pressed on macOS. #### `tray.setToolTip(toolTip)` -* `toolTip` String +* `toolTip` string -Sets the hover text for this tray icon. +Sets the hover text for this tray icon. Setting the text to an empty string will remove the tooltip. #### `tray.setTitle(title[, options])` _macOS_ -* `title` String +* `title` string * `options` Object (optional) - * `fontType` String (optional) - The font family variant to display, can be `monospaced` or `monospacedDigit`. `monospaced` is available in macOS 10.15+ and `monospacedDigit` is available in macOS 10.11+. When left blank, the title uses the default system font. + * `fontType` string (optional) - The font family variant to display, can be `monospaced` or `monospacedDigit`. `monospaced` is available in macOS 10.15+ When left blank, the title uses the default system font. Sets the title displayed next to the tray icon in the status bar (Support ANSI colors). #### `tray.getTitle()` _macOS_ -Returns `String` - the title displayed next to the tray icon in the status bar +Returns `string` - the title displayed next to the tray icon in the status bar #### `tray.setIgnoreDoubleClickEvents(ignore)` _macOS_ -* `ignore` Boolean +* `ignore` boolean Sets the option to ignore double click events. Ignoring these events allows you to detect every individual click of the tray icon. @@ -240,24 +279,24 @@ This value is set to false by default. #### `tray.getIgnoreDoubleClickEvents()` _macOS_ -Returns `Boolean` - Whether double click events will be ignored. +Returns `boolean` - Whether double click events will be ignored. #### `tray.displayBalloon(options)` _Windows_ * `options` Object - * `icon` ([NativeImage](native-image.md) | String) (optional) - Icon to use when `iconType` is `custom`. - * `iconType` String (optional) - Can be `none`, `info`, `warning`, `error` or `custom`. Default is `custom`. - * `title` String - * `content` String - * `largeIcon` Boolean (optional) - The large version of the icon should be used. Default is `true`. Maps to [`NIIF_LARGE_ICON`][NIIF_LARGE_ICON]. - * `noSound` Boolean (optional) - Do not play the associated sound. Default is `false`. Maps to [`NIIF_NOSOUND`][NIIF_NOSOUND]. - * `respectQuietTime` Boolean (optional) - Do not display the balloon notification if the current user is in "quiet time". Default is `false`. Maps to [`NIIF_RESPECT_QUIET_TIME`][NIIF_RESPECT_QUIET_TIME]. + * `icon` ([NativeImage](native-image.md) | string) (optional) - Icon to use when `iconType` is `custom`. + * `iconType` string (optional) - Can be `none`, `info`, `warning`, `error` or `custom`. Default is `custom`. + * `title` string + * `content` string + * `largeIcon` boolean (optional) - The large version of the icon should be used. Default is `true`. Maps to [`NIIF_LARGE_ICON`][NIIF_LARGE_ICON]. + * `noSound` boolean (optional) - Do not play the associated sound. Default is `false`. Maps to [`NIIF_NOSOUND`][NIIF_NOSOUND]. + * `respectQuietTime` boolean (optional) - Do not display the balloon notification if the current user is in "quiet time". Default is `false`. Maps to [`NIIF_RESPECT_QUIET_TIME`][NIIF_RESPECT_QUIET_TIME]. Displays a tray balloon. -[NIIF_NOSOUND]: https://docs.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-notifyicondataa#niif_nosound-0x00000010 -[NIIF_LARGE_ICON]: https://docs.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-notifyicondataa#niif_large_icon-0x00000020 -[NIIF_RESPECT_QUIET_TIME]: https://docs.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-notifyicondataa#niif_respect_quiet_time-0x00000080 +[NIIF_NOSOUND]: https://learn.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-notifyicondataa#niif_nosound-0x00000010 +[NIIF_LARGE_ICON]: https://learn.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-notifyicondataa#niif_large_icon-0x00000020 +[NIIF_RESPECT_QUIET_TIME]: https://learn.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-notifyicondataa#niif_respect_quiet_time-0x00000080 #### `tray.removeBalloon()` _Windows_ @@ -296,8 +335,56 @@ Returns [`Rectangle`](structures/rectangle.md) The `bounds` of this tray icon as `Object`. +#### `tray.getGUID()` _macOS_ _Windows_ + +Returns `string | null` - The GUID used to uniquely identify the tray icon and allow it to retain its position between relaunches, or null if none is set. + #### `tray.isDestroyed()` -Returns `Boolean` - Whether the tray icon is destroyed. +Returns `boolean` - Whether the tray icon is destroyed. [event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter + +## Platform considerations + +### Linux + +* Tray icon uses [StatusNotifierItem](https://www.freedesktop.org/wiki/Specifications/StatusNotifierItem/) + by default, when it is not available in user's desktop environment the + `GtkStatusIcon` will be used instead. +* The `click` event is emitted when the tray icon receives activation from + user, however the StatusNotifierItem spec does not specify which action would + cause an activation, for some environments it is left mouse click, but for + some it might be double left mouse click. +* In order for changes made to individual `MenuItem`s to take effect, + you have to call `setContextMenu` again. For example: + +```js +const { app, Menu, Tray } = require('electron') + +let appIcon = null +app.whenReady().then(() => { + appIcon = new Tray('/path/to/my/icon') + const contextMenu = Menu.buildFromTemplate([ + { label: 'Item1', type: 'radio' }, + { label: 'Item2', type: 'radio' } + ]) + + // Make a change to the context menu + contextMenu.items[1].checked = false + + // Call this again for Linux because we modified the context menu + appIcon.setContextMenu(contextMenu) +}) +``` + +### macOS + +* Icons passed to the Tray constructor should be [Template Images](native-image.md#template-image-macos). +* To make sure your icon isn't grainy on retina monitors, be sure your `@2x` image is 144dpi. +* If you are bundling your application (e.g., with webpack for development), be sure that the file names are not being mangled or hashed. The filename needs to end in Template, and the `@2x` image needs to have the same filename as the standard image, or MacOS will not magically invert your image's colors or use the high density image. +* 16x16 (72dpi) and 32x32@2x (144dpi) work well for most icons. + +### Windows + +* It is recommended to use `ICO` icons to get best visual effects. diff --git a/docs/api/utility-process.md b/docs/api/utility-process.md new file mode 100644 index 0000000000000..bac030bbfaeee --- /dev/null +++ b/docs/api/utility-process.md @@ -0,0 +1,184 @@ +# utilityProcess + +`utilityProcess` creates a child process with +Node.js and Message ports enabled. It provides the equivalent of [`child_process.fork`][] API from Node.js +but instead uses [Services API][] from Chromium to launch the child process. + +Process: [Main](../glossary.md#main-process)<br /> + +## Methods + +### `utilityProcess.fork(modulePath[, args][, options])` + +* `modulePath` string - Path to the script that should run as entrypoint in the child process. +* `args` string[] (optional) - List of string arguments that will be available as `process.argv` + in the child process. +* `options` Object (optional) + * `env` Object (optional) - Environment key-value pairs. Default is `process.env`. + * `execArgv` string[] (optional) - List of string arguments passed to the executable. + * `cwd` string (optional) - Current working directory of the child process. + * `stdio` (string[] | string) (optional) - Allows configuring the mode for `stdout` and `stderr` + of the child process. Default is `inherit`. + String value can be one of `pipe`, `ignore`, `inherit`, for more details on these values you can refer to + [stdio][] documentation from Node.js. Currently this option only supports configuring `stdout` and + `stderr` to either `pipe`, `inherit` or `ignore`. Configuring `stdin` to any property other than `ignore` is not supported and will result in an error. + For example, the supported values will be processed as following: + * `pipe`: equivalent to \['ignore', 'pipe', 'pipe'] + * `ignore`: equivalent to \['ignore', 'ignore', 'ignore'] + * `inherit`: equivalent to \['ignore', 'inherit', 'inherit'] (the default) + * `serviceName` string (optional) - Name of the process that will appear in `name` property of + [`ProcessMetric`](structures/process-metric.md) returned by [`app.getAppMetrics`](app.md#appgetappmetrics) + and [`child-process-gone` event of `app`](app.md#event-child-process-gone). + Default is `Node Utility Process`. + * `allowLoadingUnsignedLibraries` boolean (optional) _macOS_ - With this flag, the utility process will be + launched via the `Electron Helper (Plugin).app` helper executable on macOS, which can be + codesigned with `com.apple.security.cs.disable-library-validation` and + `com.apple.security.cs.allow-unsigned-executable-memory` entitlements. This will allow the utility process + to load unsigned libraries. Unless you specifically need this capability, it is best to leave this disabled. + Default is `false`. + * `disclaim` boolean (optional) _macOS_ - With this flag, the utility process will disclaim + responsibility for the child process. This causes the operating system to consider the child + process as a separate entity for purposes of security policies like Transparency, Consent, and + Control (TCC). When responsibility is disclaimed, the parent process will not be attributed + for any TCC requests initiated by the child process. This is useful when launching processes + that run third-party or otherwise untrusted code. Default is `false`. + * `respondToAuthRequestsFromMainProcess` boolean (optional) - With this flag, all HTTP 401 and 407 network + requests created via the [net module](net.md) will allow responding to them via the + [`app#login`](app.md#event-login) event in the main process instead of the default + [`login`](client-request.md#event-login) event on the [`ClientRequest`](client-request.md) object. Default is + `false`. + +Returns [`UtilityProcess`](utility-process.md#class-utilityprocess) + +> [!NOTE] +> `utilityProcess.fork` can only be called after the `ready` event has been emitted on `App`. + +## Class: UtilityProcess + +> Instances of the `UtilityProcess` represent the Chromium spawned child process +> with Node.js integration. + +`UtilityProcess` is an [EventEmitter][event-emitter]. + +### Instance Methods + +#### `child.postMessage(message, [transfer])` + +* `message` any +* `transfer` MessagePortMain[] (optional) + +Send a message to the child process, optionally transferring ownership of +zero or more [`MessagePortMain`][] objects. + +For example: + +```js +// Main process +const { port1, port2 } = new MessageChannelMain() +const child = utilityProcess.fork(path.join(__dirname, 'test.js')) +child.postMessage({ message: 'hello' }, [port1]) + +// Child process +process.parentPort.once('message', (e) => { + const [port] = e.ports + // ... +}) +``` + +#### `child.kill()` + +Returns `boolean` + +Terminates the process gracefully. On POSIX, it uses SIGTERM +but will ensure the process is reaped on exit. This function returns +true if the kill is successful, and false otherwise. + +### Instance Properties + +#### `child.pid` + +A `Integer | undefined` representing the process identifier (PID) of the child process. +Until the child process has spawned successfully, the value is `undefined`. When +the child process exits, then the value is `undefined` after the `exit` event is emitted. + +```js +const child = utilityProcess.fork(path.join(__dirname, 'test.js')) + +console.log(child.pid) // undefined + +child.on('spawn', () => { + console.log(child.pid) // Integer +}) + +child.on('exit', () => { + console.log(child.pid) // undefined +}) +``` + +> [!NOTE] +> You can use the `pid` to determine if the process is currently running. + +#### `child.stdout` + +A `NodeJS.ReadableStream | null` that represents the child process's stdout. +If the child was spawned with options.stdio\[1] set to anything other than 'pipe', then this will be `null`. +When the child process exits, then the value is `null` after the `exit` event is emitted. + +```js +// Main process +const { port1, port2 } = new MessageChannelMain() +const child = utilityProcess.fork(path.join(__dirname, 'test.js')) +child.stdout.on('data', (data) => { + console.log(`Received chunk ${data}`) +}) +``` + +#### `child.stderr` + +A `NodeJS.ReadableStream | null` that represents the child process's stderr. +If the child was spawned with options.stdio\[2] set to anything other than 'pipe', then this will be `null`. +When the child process exits, then the value is `null` after the `exit` event is emitted. + +### Instance Events + +#### Event: 'spawn' + +Emitted once the child process has spawned successfully. + +#### Event: 'error' _Experimental_ + +Returns: + +* `type` string - Type of error. One of the following values: + * `FatalError` +* `location` string - Source location from where the error originated. +* `report` string - [`Node.js diagnostic report`][]. + +Emitted when the child process needs to terminate due to non continuable error from V8. + +No matter if you listen to the `error` event, the `exit` event will be emitted after the +child process terminates. + +#### Event: 'exit' + +Returns: + +* `code` number - Contains the exit code for +the process obtained from waitpid on POSIX, or GetExitCodeProcess on Windows. + +Emitted after the child process ends. + +#### Event: 'message' + +Returns: + +* `message` any + +Emitted when the child process sends a message using [`process.parentPort.postMessage()`](process.md#processparentport). + +[`child_process.fork`]: https://nodejs.org/dist/latest-v16.x/docs/api/child_process.html#child_processforkmodulepath-args-options +[Services API]: https://chromium.googlesource.com/chromium/src/+/main/docs/mojo_and_services.md +[stdio]: https://nodejs.org/dist/latest/docs/api/child_process.html#optionsstdio +[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter +[`MessagePortMain`]: message-port-main.md +[`Node.js diagnostic report`]: https://nodejs.org/docs/latest/api/report.html#diagnostic-report diff --git a/docs/api/view.md b/docs/api/view.md new file mode 100644 index 0000000000000..6dddd43c892d5 --- /dev/null +++ b/docs/api/view.md @@ -0,0 +1,138 @@ +# View + +> Create and layout native views. + +Process: [Main](../glossary.md#main-process) + +This module cannot be used until the `ready` event of the `app` +module is emitted. + +```js +const { BaseWindow, View } = require('electron') + +const win = new BaseWindow() +const view = new View() + +view.setBackgroundColor('red') +view.setBounds({ x: 0, y: 0, width: 100, height: 100 }) +win.contentView.addChildView(view) +``` + +## Class: View + +> A basic native view. + +Process: [Main](../glossary.md#main-process) + +`View` is an [EventEmitter][event-emitter]. + +> [!WARNING] +> Electron's built-in classes cannot be subclassed in user code. +> For more information, see [the FAQ](../faq.md#class-inheritance-does-not-work-with-electron-built-in-modules). + +### `new View()` + +Creates a new `View`. + +### Instance Events + +Objects created with `new View` emit the following events: + +#### Event: 'bounds-changed' + +Emitted when the view's bounds have changed in response to being laid out. The +new bounds can be retrieved with [`view.getBounds()`](#viewgetbounds). + +### Instance Methods + +Objects created with `new View` have the following instance methods: + +#### `view.addChildView(view[, index])` + +* `view` View - Child view to add. +* `index` Integer (optional) - Index at which to insert the child view. + Defaults to adding the child at the end of the child list. + +If the same View is added to a parent which already contains it, it will be reordered such that +it becomes the topmost view. + +#### `view.removeChildView(view)` + +* `view` View - Child view to remove. + +If the view passed as a parameter is not a child of this view, this method is a no-op. + +#### `view.setBounds(bounds[, options])` + +* `bounds` [Rectangle](structures/rectangle.md) - New bounds of the View. +* `options` Object (optional) - Options for setting the bounds. + * `animate` boolean | Object (optional) - If true, the bounds change will be animated. If an object is passed, it can contain the following properties: + * `duration` Integer (optional) - Duration of the animation in milliseconds. Default is `250`. + * `easing` string (optional) - Easing function for the animation. Default is `linear`. + * `linear` + * `ease-in` + * `ease-out` + * `ease-in-out` + +#### `view.getBounds()` + +Returns [`Rectangle`](structures/rectangle.md) - The bounds of this View, relative to its parent. + +#### `view.setBackgroundColor(color)` + +* `color` string - Color in Hex, RGB, ARGB, HSL, HSLA or named CSS color format. The alpha channel is + optional for the hex type. + +Examples of valid `color` values: + +* Hex + * `#fff` (RGB) + * `#ffff` (ARGB) + * `#ffffff` (RRGGBB) + * `#ffffffff` (AARRGGBB) +* RGB + * `rgb\(([\d]+),\s*([\d]+),\s*([\d]+)\)` + * e.g. `rgb(255, 255, 255)` +* RGBA + * `rgba\(([\d]+),\s*([\d]+),\s*([\d]+),\s*([\d.]+)\)` + * e.g. `rgba(255, 255, 255, 1.0)` +* HSL + * `hsl\((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%\)` + * e.g. `hsl(200, 20%, 50%)` +* HSLA + * `hsla\((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)\)` + * e.g. `hsla(200, 20%, 50%, 0.5)` +* Color name + * Options are listed in [SkParseColor.cpp](https://source.chromium.org/chromium/chromium/src/+/main:third_party/skia/src/utils/SkParseColor.cpp;l=11-152;drc=eea4bf52cb0d55e2a39c828b017c80a5ee054148) + * Similar to CSS Color Module Level 3 keywords, but case-sensitive. + * e.g. `blueviolet` or `red` + +> [!NOTE] +> Hex format with alpha takes `AARRGGBB` or `ARGB`, _not_ `RRGGBBAA` or `RGB`. + +#### `view.setBorderRadius(radius)` + +* `radius` Integer - Border radius size in pixels. + +> [!NOTE] +> The area cutout of the view's border still captures clicks. + +#### `view.setVisible(visible)` + +* `visible` boolean - If false, the view will be hidden from display. + +#### `view.getVisible()` + +Returns `boolean` - Whether the view should be drawn. Note that this is +different from whether the view is visible on screen—it may still be obscured +or out of view. + +### Instance Properties + +Objects created with `new View` have the following properties: + +#### `view.children` _Readonly_ + +A `View[]` property representing the child views of this view. + +[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter diff --git a/docs/api/web-contents-view.md b/docs/api/web-contents-view.md new file mode 100644 index 0000000000000..cae7dabfc563f --- /dev/null +++ b/docs/api/web-contents-view.md @@ -0,0 +1,65 @@ +# WebContentsView + +> A View that displays a WebContents. + +Process: [Main](../glossary.md#main-process) + +This module cannot be used until the `ready` event of the `app` +module is emitted. + +```js +const { BaseWindow, WebContentsView } = require('electron') + +const win = new BaseWindow({ width: 800, height: 400 }) + +const view1 = new WebContentsView() +win.contentView.addChildView(view1) +view1.webContents.loadURL('https://electronjs.org') +view1.setBounds({ x: 0, y: 0, width: 400, height: 400 }) + +const view2 = new WebContentsView() +win.contentView.addChildView(view2) +view2.webContents.loadURL('https://github.com/electron/electron') +view2.setBounds({ x: 400, y: 0, width: 400, height: 400 }) +``` + +## Class: WebContentsView extends `View` + +> A View that displays a WebContents. + +Process: [Main](../glossary.md#main-process) + +`WebContentsView` inherits from [`View`](view.md). + +`WebContentsView` is an [EventEmitter][event-emitter]. + +> [!WARNING] +> Electron's built-in classes cannot be subclassed in user code. +> For more information, see [the FAQ](../faq.md#class-inheritance-does-not-work-with-electron-built-in-modules). + +### `new WebContentsView([options])` + +* `options` Object (optional) + * `webPreferences` [WebPreferences](structures/web-preferences.md) (optional) - Settings of web page's features. + * `webContents` [WebContents](web-contents.md) (optional) - If present, the given WebContents will be adopted by the WebContentsView. A WebContents may only be presented in one WebContentsView at a time. + +Creates a WebContentsView. + +### Instance Properties + +Objects created with `new WebContentsView` have the following properties, in +addition to those inherited from [View](view.md): + +#### `view.webContents` _Readonly_ + +A `WebContents` property containing a reference to the displayed `WebContents`. +Use this to interact with the `WebContents`, for instance to load a URL. + +```js +const { WebContentsView } = require('electron') + +const view = new WebContentsView() +view.webContents.loadURL('https://electronjs.org/') +``` + +[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter diff --git a/docs/api/web-contents.md b/docs/api/web-contents.md index 599a46b1e6c08..a2d4808e6f2d8 100644 --- a/docs/api/web-contents.md +++ b/docs/api/web-contents.md @@ -9,46 +9,106 @@ It is responsible for rendering and controlling a web page and is a property of the [`BrowserWindow`](browser-window.md) object. An example of accessing the `webContents` object: -```javascript +```js const { BrowserWindow } = require('electron') const win = new BrowserWindow({ width: 800, height: 1500 }) -win.loadURL('http://github.com') +win.loadURL('https://github.com') const contents = win.webContents console.log(contents) ``` +## Navigation Events + +Several events can be used to monitor navigations as they occur within a `webContents`. + +### Document Navigations + +When a `webContents` navigates to another page (as opposed to an [in-page navigation](web-contents.md#in-page-navigation)), the following events will be fired. + +* [`did-start-navigation`](web-contents.md#event-did-start-navigation) +* [`will-frame-navigate`](web-contents.md#event-will-frame-navigate) +* [`will-navigate`](web-contents.md#event-will-navigate) (only fired when main frame navigates) +* [`will-redirect`](web-contents.md#event-will-redirect) (only fired when a redirect happens during navigation) +* [`did-redirect-navigation`](web-contents.md#event-did-redirect-navigation) (only fired when a redirect happens during navigation) +* [`did-frame-navigate`](web-contents.md#event-did-frame-navigate) +* [`did-navigate`](web-contents.md#event-did-navigate) (only fired when main frame navigates) + +Subsequent events will not fire if `event.preventDefault()` is called on any of the cancellable events. + +### In-page Navigation + +In-page navigations don't cause the page to reload, but instead navigate to a location within the current page. These events are not cancellable. For an in-page navigations, the following events will fire in this order: + +* [`did-start-navigation`](web-contents.md#event-did-start-navigation) +* [`did-navigate-in-page`](web-contents.md#event-did-navigate-in-page) + +### Frame Navigation + +The [`will-navigate`](web-contents.md#event-will-navigate) and [`did-navigate`](web-contents.md#event-did-navigate) events only fire when the [mainFrame](web-contents.md#contentsmainframe-readonly) navigates. +If you want to also observe navigations in `<iframe>`s, use [`will-frame-navigate`](web-contents.md#event-will-frame-navigate) and [`did-frame-navigate`](web-contents.md#event-did-frame-navigate) events. + ## Methods These methods can be accessed from the `webContents` module: -```javascript +```js const { webContents } = require('electron') + console.log(webContents) ``` ### `webContents.getAllWebContents()` Returns `WebContents[]` - An array of all `WebContents` instances. This will contain web contents -for all windows, webviews, opened devtools, and devtools extension background pages. +for all windows, webviews, opened DevTools, and DevTools extension background pages. ### `webContents.getFocusedWebContents()` -Returns `WebContents` - The web contents that is focused in this application, otherwise +Returns `WebContents | null` - The web contents that is focused in this application, otherwise returns `null`. ### `webContents.fromId(id)` * `id` Integer -Returns `WebContents` - A WebContents instance with the given ID. +Returns `WebContents | undefined` - A WebContents instance with the given ID, or +`undefined` if there is no WebContents associated with the given ID. + +### `webContents.fromFrame(frame)` + +* `frame` WebFrameMain + +Returns `WebContents | undefined` - A WebContents instance with the given WebFrameMain, or +`undefined` if there is no WebContents associated with the given WebFrameMain. + +### `webContents.fromDevToolsTargetId(targetId)` + +* `targetId` string - The Chrome DevTools Protocol [TargetID](https://chromedevtools.github.io/devtools-protocol/tot/Target/#type-TargetID) associated with the WebContents instance. + +Returns `WebContents | undefined` - A WebContents instance with the given TargetID, or +`undefined` if there is no WebContents associated with the given TargetID. + +When communicating with the [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/), +it can be useful to lookup a WebContents instance based on its assigned TargetID. + +```js +async function lookupTargetId (browserWindow) { + const wc = browserWindow.webContents + await wc.debugger.attach('1.3') + const { targetInfo } = await wc.debugger.sendCommand('Target.getTargetInfo') + const { targetId } = targetInfo + const targetWebContents = await wc.fromDevToolsTargetId(targetId) +} +``` ## Class: WebContents > Render and control the contents of a BrowserWindow instance. -Process: [Main](../glossary.md#main-process) +Process: [Main](../glossary.md#main-process)<br /> +_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ ### Instance Events @@ -63,14 +123,14 @@ Returns: * `event` Event * `errorCode` Integer -* `errorDescription` String -* `validatedURL` String -* `isMainFrame` Boolean +* `errorDescription` string +* `validatedURL` string +* `isMainFrame` boolean * `frameProcessId` Integer * `frameRoutingId` Integer This event is like `did-finish-load` but emitted when the load failed. -The full list of error codes and their meaning is available [here](https://source.chromium.org/chromium/chromium/src/+/master:net/base/net_error_list.h). +The full list of error codes and their meaning is available [here](https://source.chromium.org/chromium/chromium/src/+/main:net/base/net_error_list.h). #### Event: 'did-fail-provisional-load' @@ -78,9 +138,9 @@ Returns: * `event` Event * `errorCode` Integer -* `errorDescription` String -* `validatedURL` String -* `isMainFrame` Boolean +* `errorDescription` string +* `validatedURL` string +* `isMainFrame` boolean * `frameProcessId` Integer * `frameRoutingId` Integer @@ -92,7 +152,7 @@ This event is like `did-fail-load` but emitted when the load was cancelled Returns: * `event` Event -* `isMainFrame` Boolean +* `isMainFrame` boolean * `frameProcessId` Integer * `frameRoutingId` Integer @@ -108,19 +168,15 @@ Corresponds to the points in time when the spinner of the tab stopped spinning. #### Event: 'dom-ready' -Returns: - -* `event` Event - -Emitted when the document in the given frame is loaded. +Emitted when the document in the top-level frame is loaded. #### Event: 'page-title-updated' Returns: * `event` Event -* `title` String -* `explicitSet` Boolean +* `title` string +* `explicitSet` boolean Fired when page title is set during navigation. `explicitSet` is false when title is synthesized from file url. @@ -130,93 +186,47 @@ title is synthesized from file url. Returns: * `event` Event -* `favicons` String[] - Array of URLs. +* `favicons` string[] - Array of URLs. Emitted when page receives favicon urls. -#### Event: 'new-window' _Deprecated_ +#### Event: 'content-bounds-updated' Returns: -* `event` NewWindowWebContentsEvent -* `url` String -* `frameName` String -* `disposition` String - Can be `default`, `foreground-tab`, `background-tab`, - `new-window`, `save-to-disk` and `other`. -* `options` BrowserWindowConstructorOptions - The options which will be used for creating the new - [`BrowserWindow`](browser-window.md). -* `additionalFeatures` String[] - The non-standard features (features not handled - by Chromium or Electron) given to `window.open()`. -* `referrer` [Referrer](structures/referrer.md) - The referrer that will be - passed to the new window. May or may not result in the `Referer` header being - sent, depending on the referrer policy. -* `postBody` [PostBody](structures/post-body.md) (optional) - The post data that - will be sent to the new window, along with the appropriate headers that will - be set. If no post data is to be sent, the value will be `null`. Only defined - when the window is being created by a form that set `target=_blank`. - -Deprecated in favor of [`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandlerhandler). - -Emitted when the page requests to open a new window for a `url`. It could be -requested by `window.open` or an external link like `<a target='_blank'>`. - -By default a new `BrowserWindow` will be created for the `url`. - -Calling `event.preventDefault()` will prevent Electron from automatically creating a -new [`BrowserWindow`](browser-window.md). If you call `event.preventDefault()` and manually create a new -[`BrowserWindow`](browser-window.md) then you must set `event.newGuest` to reference the new [`BrowserWindow`](browser-window.md) -instance, failing to do so may result in unexpected behavior. For example: - -```javascript -myBrowserWindow.webContents.on('new-window', (event, url, frameName, disposition, options, additionalFeatures, referrer, postBody) => { - event.preventDefault() - const win = new BrowserWindow({ - webContents: options.webContents, // use existing webContents if provided - show: false - }) - win.once('ready-to-show', () => win.show()) - if (!options.webContents) { - const loadOptions = { - httpReferrer: referrer - } - if (postBody != null) { - const { data, contentType, boundary } = postBody - loadOptions.postData = postBody.data - loadOptions.extraHeaders = `content-type: ${contentType}; boundary=${boundary}` - } +* `event` Event +* `bounds` [Rectangle](structures/rectangle.md) - requested new content bounds - win.loadURL(url, loadOptions) // existing webContents will be navigated automatically - } - event.newGuest = win -}) -``` +Emitted when the page calls `window.moveTo`, `window.resizeTo` or related APIs. + +By default, this will move the window. To prevent that behavior, call +`event.preventDefault()`. #### Event: 'did-create-window' Returns: + * `window` BrowserWindow * `details` Object - * `url` String - URL for the created window. - * `frameName` String - Name given to the created window in the - `window.open()` call. - * `options` BrowserWindowConstructorOptions - The options used to create the - BrowserWindow. They are merged in increasing precedence: options inherited - from the parent, parsed options from the `features` string from - `window.open()`, and options given by - [`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandlerhandler). - Unrecognized options are not filtered out. - * `additionalFeatures` String[] - The non-standard features (features not - handled Chromium or Electron) _Deprecated_ - * `referrer` [Referrer](structures/referrer.md) - The referrer that will be - passed to the new window. May or may not result in the `Referer` header - being sent, depending on the referrer policy. - * `postBody` [PostBody](structures/post-body.md) (optional) - The post data - that will be sent to the new window, along with the appropriate headers - that will be set. If no post data is to be sent, the value will be `null`. - Only defined when the window is being created by a form that set - `target=_blank`. - * `disposition` String - Can be `default`, `foreground-tab`, - `background-tab`, `new-window`, `save-to-disk` and `other`. + * `url` string - URL for the created window. + * `frameName` string - Name given to the created window in the + `window.open()` call. + * `options` [BrowserWindowConstructorOptions](structures/browser-window-options.md) - The options used to create the + BrowserWindow. They are merged in increasing precedence: parsed options + from the `features` string from `window.open()`, security-related + webPreferences inherited from the parent, and options given by + [`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandlerhandler). + Unrecognized options are not filtered out. + * `referrer` [Referrer](structures/referrer.md) - The referrer that will be + passed to the new window. May or may not result in the `Referer` header + being sent, depending on the referrer policy. + * `postBody` [PostBody](structures/post-body.md) (optional) - The post data + that will be sent to the new window, along with the appropriate headers + that will be set. If no post data is to be sent, the value will be `null`. + Only defined when the window is being created by a form that set + `target=_blank`. + * `disposition` string - Can be `default`, `foreground-tab`, + `background-tab`, `new-window` or `other`. Emitted _after_ successful creation of a window via `window.open` in the renderer. Not emitted if the creation of the window is canceled from @@ -228,12 +238,58 @@ See [`window.open()`](window-open.md) for more details and how to use this in co Returns: -* `event` Event -* `url` String +* `details` Event\<\> + * `url` string - The URL the frame is navigating to. + * `isSameDocument` boolean - This event does not fire for same document navigations using window.history api and reference fragment navigations. + This property is always set to `false` for this event. + * `isMainFrame` boolean - True if the navigation is taking place in a main frame. + * `frame` WebFrameMain | null - The frame to be navigated. + May be `null` if accessed after the frame has either navigated or been destroyed. + * `initiator` WebFrameMain | null (optional) - The frame which initiated the + navigation, which can be a parent frame (e.g. via `window.open` with a + frame's name), or null if the navigation was not initiated by a frame. This + can also be null if the initiating frame was deleted before the event was + emitted. +* `url` string _Deprecated_ +* `isInPlace` boolean _Deprecated_ +* `isMainFrame` boolean _Deprecated_ +* `frameProcessId` Integer _Deprecated_ +* `frameRoutingId` Integer _Deprecated_ + +Emitted when a user or the page wants to start navigation on the main frame. It can happen when +the `window.location` object is changed or a user clicks a link in the page. + +This event will not emit when the navigation is started programmatically with +APIs like `webContents.loadURL` and `webContents.back`. + +It is also not emitted for in-page navigations, such as clicking anchor links +or updating the `window.location.hash`. Use `did-navigate-in-page` event for +this purpose. -Emitted when a user or the page wants to start navigation. It can happen when +Calling `event.preventDefault()` will prevent the navigation. + +#### Event: 'will-frame-navigate' + +Returns: + +* `details` Event\<\> + * `url` string - The URL the frame is navigating to. + * `isSameDocument` boolean - This event does not fire for same document navigations using window.history api and reference fragment navigations. + This property is always set to `false` for this event. + * `isMainFrame` boolean - True if the navigation is taking place in a main frame. + * `frame` WebFrameMain | null - The frame to be navigated. + May be `null` if accessed after the frame has either navigated or been destroyed. + * `initiator` WebFrameMain | null (optional) - The frame which initiated the + navigation, which can be a parent frame (e.g. via `window.open` with a + frame's name), or null if the navigation was not initiated by a frame. This + can also be null if the initiating frame was deleted before the event was + emitted. + +Emitted when a user or the page wants to start navigation in any frame. It can happen when the `window.location` object is changed or a user clicks a link in the page. +Unlike `will-navigate`, `will-frame-navigate` is fired when the main frame or any of its subframes attempts to navigate. When the navigation event comes from the main frame, `isMainFrame` will be `true`. + This event will not emit when the navigation is started programmatically with APIs like `webContents.loadURL` and `webContents.back`. @@ -247,28 +303,51 @@ Calling `event.preventDefault()` will prevent the navigation. Returns: -* `event` Event -* `url` String -* `isInPlace` Boolean -* `isMainFrame` Boolean -* `frameProcessId` Integer -* `frameRoutingId` Integer - -Emitted when any frame (including main) starts navigating. `isInPlace` will be -`true` for in-page navigations. +* `details` Event\<\> + * `url` string - The URL the frame is navigating to. + * `isSameDocument` boolean - Whether the navigation happened without changing + document. Examples of same document navigations are reference fragment + navigations, pushState/replaceState, and same page history navigation. + * `isMainFrame` boolean - True if the navigation is taking place in a main frame. + * `frame` WebFrameMain | null - The frame to be navigated. + May be `null` if accessed after the frame has either navigated or been destroyed. + * `initiator` WebFrameMain | null (optional) - The frame which initiated the + navigation, which can be a parent frame (e.g. via `window.open` with a + frame's name), or null if the navigation was not initiated by a frame. This + can also be null if the initiating frame was deleted before the event was + emitted. +* `url` string _Deprecated_ +* `isInPlace` boolean _Deprecated_ +* `isMainFrame` boolean _Deprecated_ +* `frameProcessId` Integer _Deprecated_ +* `frameRoutingId` Integer _Deprecated_ + +Emitted when any frame (including main) starts navigating. #### Event: 'will-redirect' Returns: -* `event` Event -* `url` String -* `isInPlace` Boolean -* `isMainFrame` Boolean -* `frameProcessId` Integer -* `frameRoutingId` Integer - -Emitted as a server side redirect occurs during navigation. For example a 302 +* `details` Event\<\> + * `url` string - The URL the frame is navigating to. + * `isSameDocument` boolean - Whether the navigation happened without changing + document. Examples of same document navigations are reference fragment + navigations, pushState/replaceState, and same page history navigation. + * `isMainFrame` boolean - True if the navigation is taking place in a main frame. + * `frame` WebFrameMain | null - The frame to be navigated. + May be `null` if accessed after the frame has either navigated or been destroyed. + * `initiator` WebFrameMain | null (optional) - The frame which initiated the + navigation, which can be a parent frame (e.g. via `window.open` with a + frame's name), or null if the navigation was not initiated by a frame. This + can also be null if the initiating frame was deleted before the event was + emitted. +* `url` string _Deprecated_ +* `isInPlace` boolean _Deprecated_ +* `isMainFrame` boolean _Deprecated_ +* `frameProcessId` Integer _Deprecated_ +* `frameRoutingId` Integer _Deprecated_ + +Emitted when a server side redirect occurs during navigation. For example a 302 redirect. This event will be emitted after `did-start-navigation` and always before the @@ -281,27 +360,39 @@ redirect). Returns: -* `event` Event -* `url` String -* `isInPlace` Boolean -* `isMainFrame` Boolean -* `frameProcessId` Integer -* `frameRoutingId` Integer +* `details` Event\<\> + * `url` string - The URL the frame is navigating to. + * `isSameDocument` boolean - Whether the navigation happened without changing + document. Examples of same document navigations are reference fragment + navigations, pushState/replaceState, and same page history navigation. + * `isMainFrame` boolean - True if the navigation is taking place in a main frame. + * `frame` WebFrameMain | null - The frame to be navigated. + May be `null` if accessed after the frame has either navigated or been destroyed. + * `initiator` WebFrameMain | null (optional) - The frame which initiated the + navigation, which can be a parent frame (e.g. via `window.open` with a + frame's name), or null if the navigation was not initiated by a frame. This + can also be null if the initiating frame was deleted before the event was + emitted. +* `url` string _Deprecated_ +* `isInPlace` boolean _Deprecated_ +* `isMainFrame` boolean _Deprecated_ +* `frameProcessId` Integer _Deprecated_ +* `frameRoutingId` Integer _Deprecated_ Emitted after a server side redirect occurs during navigation. For example a 302 redirect. This event cannot be prevented, if you want to prevent redirects you should -checkout out the `will-redirect` event above. +check out the `will-redirect` event above. #### Event: 'did-navigate' Returns: * `event` Event -* `url` String +* `url` string * `httpResponseCode` Integer - -1 for non HTTP navigations -* `httpStatusText` String - empty for non HTTP navigations +* `httpStatusText` string - empty for non HTTP navigations Emitted when a main frame navigation is done. @@ -314,10 +405,10 @@ this purpose. Returns: * `event` Event -* `url` String +* `url` string * `httpResponseCode` Integer - -1 for non HTTP navigations -* `httpStatusText` String - empty for non HTTP navigations, -* `isMainFrame` Boolean +* `httpStatusText` string - empty for non HTTP navigations, +* `isMainFrame` boolean * `frameProcessId` Integer * `frameRoutingId` Integer @@ -332,8 +423,8 @@ this purpose. Returns: * `event` Event -* `url` String -* `isMainFrame` Boolean +* `url` string +* `isMainFrame` boolean * `frameProcessId` Integer * `frameRoutingId` Integer @@ -354,8 +445,9 @@ Emitted when a `beforeunload` event handler is attempting to cancel a page unloa Calling `event.preventDefault()` will ignore the `beforeunload` event handler and allow the page to be unloaded. -```javascript +```js const { BrowserWindow, dialog } = require('electron') + const win = new BrowserWindow({ width: 800, height: 600 }) win.webContents.on('will-prevent-unload', (event) => { const choice = dialog.showMessageBoxSync(win, { @@ -373,34 +465,15 @@ win.webContents.on('will-prevent-unload', (event) => { }) ``` -#### Event: 'crashed' _Deprecated_ - -Returns: - -* `event` Event -* `killed` Boolean - -Emitted when the renderer process crashes or is killed. - -**Deprecated:** This event is superceded by the `render-process-gone` event -which contains more information about why the render process disappeared. It -isn't always because it crashed. The `killed` boolean can be replaced by -checking `reason === 'killed'` when you switch to that event. +> [!NOTE] +> This will be emitted for `BrowserViews` but will _not_ be respected - this is because we have chosen not to tie the `BrowserView` lifecycle to its owning BrowserWindow should one exist per the [specification](https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event). #### Event: 'render-process-gone' Returns: * `event` Event -* `details` Object - * `reason` String - The reason the render process is gone. Possible values: - * `clean-exit` - Process exited with an exit code of zero - * `abnormal-exit` - Process exited with a non-zero exit code - * `killed` - Process was sent a SIGTERM or otherwise killed externally - * `crashed` - Process crashed - * `oom` - Process ran out of memory - * `launch-failed` - Process never successfully launched - * `integrity-failure` - Windows code integrity checks failed +* `details` [RenderProcessGoneDetails](structures/render-process-gone-details.md) Emitted when the renderer process unexpectedly disappears. This is normally because it was crashed or killed. @@ -413,19 +486,19 @@ Emitted when the web page becomes unresponsive. Emitted when the unresponsive web page becomes responsive again. -#### Event: 'plugin-crashed' +#### Event: 'destroyed' -Returns: +Emitted when `webContents` is destroyed. -* `event` Event -* `name` String -* `version` String +#### Event: 'input-event' -Emitted when a plugin process has crashed. +Returns: -#### Event: 'destroyed' +* `event` Event +* `inputEvent` [InputEvent](structures/input-event.md) -Emitted when `webContents` is destroyed. +Emitted when an input event is sent to the WebContents. See +[InputEvent](structures/input-event.md) for details. #### Event: 'before-input-event' @@ -433,15 +506,17 @@ Returns: * `event` Event * `input` Object - Input properties. - * `type` String - Either `keyUp` or `keyDown`. - * `key` String - Equivalent to [KeyboardEvent.key][keyboardevent]. - * `code` String - Equivalent to [KeyboardEvent.code][keyboardevent]. - * `isAutoRepeat` Boolean - Equivalent to [KeyboardEvent.repeat][keyboardevent]. - * `isComposing` Boolean - Equivalent to [KeyboardEvent.isComposing][keyboardevent]. - * `shift` Boolean - Equivalent to [KeyboardEvent.shiftKey][keyboardevent]. - * `control` Boolean - Equivalent to [KeyboardEvent.controlKey][keyboardevent]. - * `alt` Boolean - Equivalent to [KeyboardEvent.altKey][keyboardevent]. - * `meta` Boolean - Equivalent to [KeyboardEvent.metaKey][keyboardevent]. + * `type` string - Either `keyUp` or `keyDown`. + * `key` string - Equivalent to [KeyboardEvent.key][keyboardevent]. + * `code` string - Equivalent to [KeyboardEvent.code][keyboardevent]. + * `isAutoRepeat` boolean - Equivalent to [KeyboardEvent.repeat][keyboardevent]. + * `isComposing` boolean - Equivalent to [KeyboardEvent.isComposing][keyboardevent]. + * `shift` boolean - Equivalent to [KeyboardEvent.shiftKey][keyboardevent]. + * `control` boolean - Equivalent to [KeyboardEvent.controlKey][keyboardevent]. + * `alt` boolean - Equivalent to [KeyboardEvent.altKey][keyboardevent]. + * `meta` boolean - Equivalent to [KeyboardEvent.metaKey][keyboardevent]. + * `location` number - Equivalent to [KeyboardEvent.location][keyboardevent]. + * `modifiers` string[] - See [InputEvent.modifiers](structures/input-event.md). Emitted before dispatching the `keydown` and `keyup` events in the page. Calling `event.preventDefault` will prevent the page `keydown`/`keyup` events @@ -450,15 +525,56 @@ and the menu shortcuts. To only prevent the menu shortcuts, use [`setIgnoreMenuShortcuts`](#contentssetignoremenushortcutsignore): -```javascript -const { BrowserWindow } = require('electron') +```js +const { app, BrowserWindow } = require('electron') -const win = new BrowserWindow({ width: 800, height: 600 }) +app.whenReady().then(() => { + const win = new BrowserWindow({ width: 800, height: 600 }) -win.webContents.on('before-input-event', (event, input) => { - // For example, only enable application menu keyboard shortcuts when - // Ctrl/Cmd are down. - win.webContents.setIgnoreMenuShortcuts(!input.control && !input.meta) + win.webContents.on('before-input-event', (event, input) => { + // Enable application menu keyboard shortcuts when Ctrl/Cmd are down. + win.webContents.setIgnoreMenuShortcuts(!input.control && !input.meta) + }) +}) +``` + +#### Event: 'before-mouse-event' + +Returns: + +* `event` Event +* `mouse` [MouseInputEvent](structures/mouse-input-event.md) + +Emitted before dispatching mouse events in the page. + +Calling `event.preventDefault` will prevent the page mouse events. + +```js +const { app, BrowserWindow } = require('electron') + +app.whenReady().then(() => { + const win = new BrowserWindow({ width: 800, height: 600 }) + + win.webContents.on('before-mouse-event', (event, mouse) => { + // Prevent mouseDown events. + if (mouse.type === 'mouseDown') { + console.log(mouse) + /* + { + type: 'mouseDown', + clickCount: 1, + movementX: 0, + movementY: 0, + button: 'left', + x: 632.359375, + y: 480.6875, + globalX: 168.359375, + globalY: 193.6875 + } + */ + event.preventDefault() + } + }) }) ``` @@ -475,10 +591,45 @@ Emitted when the window leaves a full-screen state triggered by HTML API. Returns: * `event` Event -* `zoomDirection` String - Can be `in` or `out`. +* `zoomDirection` string - Can be `in` or `out`. Emitted when the user is requesting to change the zoom level using the mouse wheel. +#### Event: 'blur' + +Emitted when the `WebContents` loses focus. + +#### Event: 'focus' + +Emitted when the `WebContents` gains focus. + +Note that on macOS, having focus means the `WebContents` is the first responder +of window, so switching focus between windows would not trigger the `focus` and +`blur` events of `WebContents`, as the first responder of each window is not +changed. + +The `focus` and `blur` events of `WebContents` should only be used to detect +focus change between different `WebContents` and `BrowserView` in the same +window. + +#### Event: 'devtools-open-url' + +Returns: + +* `event` Event +* `url` string - URL of the link that was clicked or selected. + +Emitted when a link is clicked in DevTools or 'Open in new tab' is selected for a link in its context menu. + +#### Event: 'devtools-search-query' + +Returns: + +* `event` Event +* `query` string - text to query for. + +Emitted when 'Search' is selected for text in its context menu. + #### Event: 'devtools-opened' Emitted when DevTools is opened. @@ -496,16 +647,16 @@ Emitted when DevTools is focused / opened. Returns: * `event` Event -* `url` String -* `error` String - The error code. +* `url` string +* `error` string - The error code. * `certificate` [Certificate](structures/certificate.md) * `callback` Function - * `isTrusted` Boolean - Indicates whether the certificate can be considered trusted. + * `isTrusted` boolean - Indicates whether the certificate can be considered trusted. +* `isMainFrame` boolean Emitted when failed to verify the `certificate` for `url`. -The usage is the same with [the `certificate-error` event of -`app`](app.md#event-certificate-error). +The usage is the same with [the `certificate-error` event of `app`](app.md#event-certificate-error). #### Event: 'select-client-certificate' @@ -519,8 +670,7 @@ Returns: Emitted when a client certificate is requested. -The usage is the same with [the `select-client-certificate` event of -`app`](app.md#event-select-client-certificate). +The usage is the same with [the `select-client-certificate` event of `app`](app.md#event-select-client-certificate). #### Event: 'login' @@ -530,14 +680,14 @@ Returns: * `authenticationResponseDetails` Object * `url` URL * `authInfo` Object - * `isProxy` Boolean - * `scheme` String - * `host` String + * `isProxy` boolean + * `scheme` string + * `host` string * `port` Integer - * `realm` String + * `realm` string * `callback` Function - * `username` String (optional) - * `password` String (optional) + * `username` string (optional) + * `password` string (optional) Emitted when `webContents` wants to do basic auth. @@ -553,10 +703,10 @@ Returns: * `activeMatchOrdinal` Integer - Position of the active match. * `matches` Integer - Number of Matches. * `selectionArea` Rectangle - Coordinates of first match region. - * `finalUpdate` Boolean + * `finalUpdate` boolean Emitted when a result is available for -[`webContents.findInPage`] request. +[`webContents.findInPage`](#contentsfindinpagetext-options) request. #### Event: 'media-started-playing' @@ -566,12 +716,21 @@ Emitted when media starts playing. Emitted when media is paused or done playing. +#### Event: 'audio-state-changed' + +Returns: + +* `event` Event\<\> + * `audible` boolean - True if one or more frames or child `webContents` are emitting audio. + +Emitted when media becomes audible or inaudible. + #### Event: 'did-change-theme-color' Returns: * `event` Event -* `color` (String | null) - Theme color is in format of '#rrggbb'. It is `null` when no theme color is set. +* `color` (string | null) - Theme color is in format of '#rrggbb'. It is `null` when no theme color is set. Emitted when a page's theme color changes. This is usually due to encountering a meta tag: @@ -585,7 +744,7 @@ a meta tag: Returns: * `event` Event -* `url` String +* `url` string Emitted when mouse moves over a link or the keyboard moves the focus to a link. @@ -594,20 +753,22 @@ Emitted when mouse moves over a link or the keyboard moves the focus to a link. Returns: * `event` Event -* `type` String +* `type` string * `image` [NativeImage](native-image.md) (optional) * `scale` Float (optional) - scaling factor for the custom cursor. * `size` [Size](structures/size.md) (optional) - the size of the `image`. * `hotspot` [Point](structures/point.md) (optional) - coordinates of the custom cursor's hotspot. -Emitted when the cursor's type changes. The `type` parameter can be `default`, -`crosshair`, `pointer`, `text`, `wait`, `help`, `e-resize`, `n-resize`, -`ne-resize`, `nw-resize`, `s-resize`, `se-resize`, `sw-resize`, `w-resize`, -`ns-resize`, `ew-resize`, `nesw-resize`, `nwse-resize`, `col-resize`, -`row-resize`, `m-panning`, `e-panning`, `n-panning`, `ne-panning`, `nw-panning`, -`s-panning`, `se-panning`, `sw-panning`, `w-panning`, `move`, `vertical-text`, -`cell`, `context-menu`, `alias`, `progress`, `nodrop`, `copy`, `none`, -`not-allowed`, `zoom-in`, `zoom-out`, `grab`, `grabbing` or `custom`. +Emitted when the cursor's type changes. The `type` parameter can be `pointer`, +`crosshair`, `hand`, `text`, `wait`, `help`, `e-resize`, `n-resize`, `ne-resize`, +`nw-resize`, `s-resize`, `se-resize`, `sw-resize`, `w-resize`, `ns-resize`, `ew-resize`, +`nesw-resize`, `nwse-resize`, `col-resize`, `row-resize`, `m-panning`, `m-panning-vertical`, +`m-panning-horizontal`, `e-panning`, `n-panning`, `ne-panning`, `nw-panning`, `s-panning`, +`se-panning`, `sw-panning`, `w-panning`, `move`, `vertical-text`, `cell`, `context-menu`, +`alias`, `progress`, `nodrop`, `copy`, `none`, `not-allowed`, `zoom-in`, `zoom-out`, `grab`, +`grabbing`, `custom`, `null`, `drag-drop-none`, `drag-drop-move`, `drag-drop-copy`, +`drag-drop-link`, `ns-no-resize`, `ew-no-resize`, `nesw-no-resize`, `nwse-no-resize`, +or `default`. If the `type` parameter is `custom`, the `image` parameter will hold the custom cursor image in a [`NativeImage`](native-image.md), and `scale`, `size` and `hotspot` will hold @@ -621,57 +782,79 @@ Returns: * `params` Object * `x` Integer - x coordinate. * `y` Integer - y coordinate. - * `linkURL` String - URL of the link that encloses the node the context menu + * `frame` WebFrameMain | null - Frame from which the context menu was invoked. + May be `null` if accessed after the frame has either navigated or been destroyed. + * `linkURL` string - URL of the link that encloses the node the context menu was invoked on. - * `linkText` String - Text associated with the link. May be an empty + * `linkText` string - Text associated with the link. May be an empty string if the contents of the link are an image. - * `pageURL` String - URL of the top level page that the context menu was + * `pageURL` string - URL of the top level page that the context menu was invoked on. - * `frameURL` String - URL of the subframe that the context menu was invoked + * `frameURL` string - URL of the subframe that the context menu was invoked on. - * `srcURL` String - Source URL for the element that the context menu + * `srcURL` string - Source URL for the element that the context menu was invoked on. Elements with source URLs are images, audio and video. - * `mediaType` String - Type of the node the context menu was invoked on. Can + * `mediaType` string - Type of the node the context menu was invoked on. Can be `none`, `image`, `audio`, `video`, `canvas`, `file` or `plugin`. - * `hasImageContents` Boolean - Whether the context menu was invoked on an image + * `hasImageContents` boolean - Whether the context menu was invoked on an image which has non-empty contents. - * `isEditable` Boolean - Whether the context is editable. - * `selectionText` String - Text of the selection that the context menu was + * `isEditable` boolean - Whether the context is editable. + * `selectionText` string - Text of the selection that the context menu was invoked on. - * `titleText` String - Title or alt text of the selection that the context - was invoked on. - * `misspelledWord` String - The misspelled word under the cursor, if any. - * `dictionarySuggestions` String[] - An array of suggested words to show the + * `titleText` string - Title text of the selection that the context menu was + invoked on. + * `altText` string - Alt text of the selection that the context menu was + invoked on. + * `suggestedFilename` string - Suggested filename to be used when saving file through 'Save + Link As' option of context menu. + * `selectionRect` [Rectangle](structures/rectangle.md) - Rect representing the coordinates in the document space of the selection. + * `selectionStartOffset` number - Start position of the selection text. + * `referrerPolicy` [Referrer](structures/referrer.md) - The referrer policy of the frame on which the menu is invoked. + * `misspelledWord` string - The misspelled word under the cursor, if any. + * `dictionarySuggestions` string[] - An array of suggested words to show the user to replace the `misspelledWord`. Only available if there is a misspelled word and spellchecker is enabled. - * `frameCharset` String - The character encoding of the frame on which the + * `frameCharset` string - The character encoding of the frame on which the menu was invoked. - * `inputFieldType` String - If the context menu was invoked on an input - field, the type of that field. Possible values are `none`, `plainText`, - `password`, `other`. - * `menuSourceType` String - Input source that invoked the context menu. - Can be `none`, `mouse`, `keyboard`, `touch` or `touchMenu`. + * `formControlType` string - The source that the context menu was invoked on. + Possible values include `none`, `button-button`, `field-set`, + `input-button`, `input-checkbox`, `input-color`, `input-date`, + `input-datetime-local`, `input-email`, `input-file`, `input-hidden`, + `input-image`, `input-month`, `input-number`, `input-password`, `input-radio`, + `input-range`, `input-reset`, `input-search`, `input-submit`, `input-telephone`, + `input-text`, `input-time`, `input-url`, `input-week`, `output`, `reset-button`, + `select-list`, `select-list`, `select-multiple`, `select-one`, `submit-button`, + and `text-area`, + * `spellcheckEnabled` boolean - If the context is editable, whether or not spellchecking is enabled. + * `menuSourceType` string - Input source that invoked the context menu. + Can be `none`, `mouse`, `keyboard`, `touch`, `touchMenu`, `longPress`, `longTap`, `touchHandle`, `stylus`, `adjustSelection`, or `adjustSelectionReset`. * `mediaFlags` Object - The flags for the media element the context menu was invoked on. - * `inError` Boolean - Whether the media element has crashed. - * `isPaused` Boolean - Whether the media element is paused. - * `isMuted` Boolean - Whether the media element is muted. - * `hasAudio` Boolean - Whether the media element has audio. - * `isLooping` Boolean - Whether the media element is looping. - * `isControlsVisible` Boolean - Whether the media element's controls are + * `inError` boolean - Whether the media element has crashed. + * `isPaused` boolean - Whether the media element is paused. + * `isMuted` boolean - Whether the media element is muted. + * `hasAudio` boolean - Whether the media element has audio. + * `isLooping` boolean - Whether the media element is looping. + * `isControlsVisible` boolean - Whether the media element's controls are visible. - * `canToggleControls` Boolean - Whether the media element's controls are + * `canToggleControls` boolean - Whether the media element's controls are toggleable. - * `canRotate` Boolean - Whether the media element can be rotated. + * `canPrint` boolean - Whether the media element can be printed. + * `canSave` boolean - Whether or not the media element can be downloaded. + * `canShowPictureInPicture` boolean - Whether the media element can show picture-in-picture. + * `isShowingPictureInPicture` boolean - Whether the media element is currently showing picture-in-picture. + * `canRotate` boolean - Whether the media element can be rotated. + * `canLoop` boolean - Whether the media element can be looped. * `editFlags` Object - These flags indicate whether the renderer believes it is able to perform the corresponding action. - * `canUndo` Boolean - Whether the renderer believes it can undo. - * `canRedo` Boolean - Whether the renderer believes it can redo. - * `canCut` Boolean - Whether the renderer believes it can cut. - * `canCopy` Boolean - Whether the renderer believes it can copy - * `canPaste` Boolean - Whether the renderer believes it can paste. - * `canDelete` Boolean - Whether the renderer believes it can delete. - * `canSelectAll` Boolean - Whether the renderer believes it can select all. + * `canUndo` boolean - Whether the renderer believes it can undo. + * `canRedo` boolean - Whether the renderer believes it can redo. + * `canCut` boolean - Whether the renderer believes it can cut. + * `canCopy` boolean - Whether the renderer believes it can copy. + * `canPaste` boolean - Whether the renderer believes it can paste. + * `canDelete` boolean - Whether the renderer believes it can delete. + * `canSelectAll` boolean - Whether the renderer believes it can select all. + * `canEditRichly` boolean - Whether the renderer believes it can edit text richly. Emitted when there is a new context menu that needs to be handled. @@ -682,20 +865,27 @@ Returns: * `event` Event * `devices` [BluetoothDevice[]](structures/bluetooth-device.md) * `callback` Function - * `deviceId` String + * `deviceId` string -Emitted when bluetooth device needs to be selected on call to -`navigator.bluetooth.requestDevice`. To use `navigator.bluetooth` api -`webBluetooth` should be enabled. If `event.preventDefault` is not called, -first available device will be selected. `callback` should be called with -`deviceId` to be selected, passing empty string to `callback` will -cancel the request. +Emitted when a bluetooth device needs to be selected when a call to +`navigator.bluetooth.requestDevice` is made. `callback` should be called with +the `deviceId` of the device to be selected. Passing an empty string to +`callback` will cancel the request. -```javascript +If no event listener is added for this event, all bluetooth requests will be cancelled. + +If `event.preventDefault` is not called when handling this event, the first available +device will be automatically selected. + +Due to the nature of bluetooth, scanning for devices when +`navigator.bluetooth.requestDevice` is called may take time and will cause +`select-bluetooth-device` to fire multiple times until `callback` is called +with either a device id or an empty string to cancel the request. + +```js title='main.js' const { app, BrowserWindow } = require('electron') let win = null -app.commandLine.appendSwitch('enable-experimental-web-platform-features') app.whenReady().then(() => { win = new BrowserWindow({ width: 800, height: 600 }) @@ -705,6 +895,9 @@ app.whenReady().then(() => { return device.deviceName === 'test' }) if (!result) { + // The device wasn't found so we need to either wait longer (eg until the + // device is turned on) or cancel the request by calling the callback + // with an empty string. callback('') } else { callback(result.deviceId) @@ -717,36 +910,65 @@ app.whenReady().then(() => { Returns: -* `event` Event +* `details` Event\<\> + * `texture` [OffscreenSharedTexture](structures/offscreen-shared-texture.md) (optional) _Experimental_ - The GPU shared texture of the frame, when `webPreferences.offscreen.useSharedTexture` is `true`. * `dirtyRect` [Rectangle](structures/rectangle.md) * `image` [NativeImage](native-image.md) - The image data of the whole frame. -Emitted when a new frame is generated. Only the dirty area is passed in the -buffer. +Emitted when a new frame is generated. Only the dirty area is passed in the buffer. -```javascript +```js const { BrowserWindow } = require('electron') const win = new BrowserWindow({ webPreferences: { offscreen: true } }) win.webContents.on('paint', (event, dirty, image) => { - // updateBitmap(dirty, image.getBitmap()) + // updateBitmap(dirty, image.toBitmap()) }) -win.loadURL('http://github.com') +win.loadURL('https://github.com') +``` + +When using shared texture (set `webPreferences.offscreen.useSharedTexture` to `true`) feature, you can pass the texture handle to external rendering pipeline without the overhead of +copying data between CPU and GPU memory, with Chromium's hardware acceleration support. This feature is helpful for high-performance rendering scenarios. + +Only a limited number of textures can exist at the same time, so it's important that you call `texture.release()` as soon as you're done with the texture. +By managing the texture lifecycle by yourself, you can safely pass the `texture.textureInfo` to other processes through IPC. + +More details can be found in the [offscreen rendering tutorial](../tutorial/offscreen-rendering.md). To learn about how to handle the texture in native code, refer to [offscreen rendering's code documentation.](../../shell/browser/osr/README.md). + +```js +const { BrowserWindow } = require('electron') + +const win = new BrowserWindow({ webPreferences: { offscreen: { useSharedTexture: true } } }) +win.webContents.on('paint', async (e, dirty, image) => { + if (e.texture) { + // By managing lifecycle yourself, you can handle the event in async handler or pass the `e.texture.textureInfo` + // to other processes (not `e.texture`, the `e.texture.release` function is not passable through IPC). + await new Promise(resolve => setTimeout(resolve, 50)) + + // You can send the native texture handle to native code for importing into your rendering pipeline. + // Read more at https://github.com/electron/electron/blob/main/shell/browser/osr/README.md + // importTextureHandle(dirty, e.texture.textureInfo) + + // You must call `e.texture.release()` as soon as possible, before the underlying frame pool is drained. + e.texture.release() + } +}) +win.loadURL('https://github.com') ``` #### Event: 'devtools-reload-page' -Emitted when the devtools window instructs the webContents to reload +Emitted when the DevTools window instructs the webContents to reload #### Event: 'will-attach-webview' Returns: * `event` Event -* `webPreferences` WebPreferences - The web preferences that will be used by the guest +* `webPreferences` [WebPreferences](structures/web-preferences.md) - The web preferences that will be used by the guest page. This object can be modified to adjust the preferences for the guest page. -* `params` Record<string, string> - The other `<webview>` parameters such as the `src` URL. +* `params` Record\<string, string\> - The other `<webview>` parameters such as the `src` URL. This object can be modified to adjust the parameters of the guest page. Emitted when a `<webview>`'s web contents is being attached to this web @@ -756,9 +978,6 @@ This event can be used to configure `webPreferences` for the `webContents` of a `<webview>` before it's loaded, and provides the ability to set settings that can't be set via `<webview>` attributes. -**Note:** The specified `preload` script option will appear as `preloadURL` -(not `preload`) in the `webPreferences` object emitted with this event. - #### Event: 'did-attach-webview' Returns: @@ -773,11 +992,17 @@ Emitted when a `<webview>` has been attached to this web contents. Returns: -* `event` Event -* `level` Integer - The log level, from 0 to 3. In order it matches `verbose`, `info`, `warning` and `error`. -* `message` String - The actual console message -* `line` Integer - The line number of the source that triggered this console message -* `sourceId` String +* `details` Event\<\> + * `message` string - Message text + * `level` string - Message severity + Possible values include `info`, `warning`, `error`, and `debug`. + * `lineNumber` Integer - Line number in the log source + * `sourceId` string - URL of the log source + * `frame` WebFrameMain - Frame that logged the message +* `level` Integer _Deprecated_ - The log level, from 0 to 3. In order it matches `verbose`, `info`, `warning` and `error`. +* `message` string _Deprecated_ - The actual console message +* `line` Integer _Deprecated_ - The line number of the source that triggered this console message +* `sourceId` string _Deprecated_ Emitted when the associated window logs a console message. @@ -786,7 +1011,7 @@ Emitted when the associated window logs a console message. Returns: * `event` Event -* `preloadPath` String +* `preloadPath` string * `error` Error Emitted when the preload script `preloadPath` throws an unhandled exception `error`. @@ -795,83 +1020,25 @@ Emitted when the preload script `preloadPath` throws an unhandled exception `err Returns: -* `event` Event -* `channel` String +* `event` [IpcMainEvent](structures/ipc-main-event.md) +* `channel` string * `...args` any[] Emitted when the renderer process sends an asynchronous message via `ipcRenderer.send()`. +See also [`webContents.ipc`](#contentsipc-readonly), which provides an [`IpcMain`](ipc-main.md)-like interface for responding to IPC messages specifically from this WebContents. + #### Event: 'ipc-message-sync' Returns: -* `event` Event -* `channel` String +* `event` [IpcMainEvent](structures/ipc-main-event.md) +* `channel` string * `...args` any[] Emitted when the renderer process sends a synchronous message via `ipcRenderer.sendSync()`. -#### Event: 'desktop-capturer-get-sources' - -Returns: - -* `event` Event - -Emitted when `desktopCapturer.getSources()` is called in the renderer process. -Calling `event.preventDefault()` will make it return empty sources. - -#### Event: 'remote-require' _Deprecated_ - -Returns: - -* `event` IpcMainEvent -* `moduleName` String - -Emitted when `remote.require()` is called in the renderer process. -Calling `event.preventDefault()` will prevent the module from being returned. -Custom value can be returned by setting `event.returnValue`. - -#### Event: 'remote-get-global' _Deprecated_ - -Returns: - -* `event` IpcMainEvent -* `globalName` String - -Emitted when `remote.getGlobal()` is called in the renderer process. -Calling `event.preventDefault()` will prevent the global from being returned. -Custom value can be returned by setting `event.returnValue`. - -#### Event: 'remote-get-builtin' _Deprecated_ - -Returns: - -* `event` IpcMainEvent -* `moduleName` String - -Emitted when `remote.getBuiltin()` is called in the renderer process. -Calling `event.preventDefault()` will prevent the module from being returned. -Custom value can be returned by setting `event.returnValue`. - -#### Event: 'remote-get-current-window' _Deprecated_ - -Returns: - -* `event` IpcMainEvent - -Emitted when `remote.getCurrentWindow()` is called in the renderer process. -Calling `event.preventDefault()` will prevent the object from being returned. -Custom value can be returned by setting `event.returnValue`. - -#### Event: 'remote-get-current-web-contents' _Deprecated_ - -Returns: - -* `event` IpcMainEvent - -Emitted when `remote.getCurrentWebContents()` is called in the renderer process. -Calling `event.preventDefault()` will prevent the object from being returned. -Custom value can be returned by setting `event.returnValue`. +See also [`webContents.ipc`](#contentsipc-readonly), which provides an [`IpcMain`](ipc-main.md)-like interface for responding to IPC messages specifically from this WebContents. #### Event: 'preferred-size-changed' @@ -886,40 +1053,51 @@ Emitted when the `WebContents` preferred size has changed. This event will only be emitted when `enablePreferredSizeMode` is set to `true` in `webPreferences`. +#### Event: 'frame-created' + +Returns: + +* `event` Event +* `details` Object + * `frame` WebFrameMain | null - The created frame. + May be `null` if accessed after the frame has either navigated or been destroyed. + +Emitted when the [mainFrame](web-contents.md#contentsmainframe-readonly), an `<iframe>`, or a nested `<iframe>` is loaded within the page. + ### Instance Methods #### `contents.loadURL(url[, options])` -* `url` String +* `url` string * `options` Object (optional) - * `httpReferrer` (String | [Referrer](structures/referrer.md)) (optional) - An HTTP Referrer url. - * `userAgent` String (optional) - A user agent originating the request. - * `extraHeaders` String (optional) - Extra headers separated by "\n". - * `postData` ([UploadRawData[]](structures/upload-raw-data.md) | [UploadFile[]](structures/upload-file.md)) (optional) - * `baseURLForDataURL` String (optional) - Base url (with trailing path separator) for files to be loaded by the data url. This is needed only if the specified `url` is a data url and needs to load other files. + * `httpReferrer` (string | [Referrer](structures/referrer.md)) (optional) - An HTTP Referrer url. + * `userAgent` string (optional) - A user agent originating the request. + * `extraHeaders` string (optional) - Extra headers separated by "\n". + * `postData` ([UploadRawData](structures/upload-raw-data.md) | [UploadFile](structures/upload-file.md))[] (optional) + * `baseURLForDataURL` string (optional) - Base url (with trailing path separator) for files to be loaded by the data url. This is needed only if the specified `url` is a data url and needs to load other files. Returns `Promise<void>` - the promise will resolve when the page has finished loading (see [`did-finish-load`](web-contents.md#event-did-finish-load)), and rejects if the page fails to load (see -[`did-fail-load`](web-contents.md#event-did-fail-load)). A noop rejection handler is already attached, which avoids unhandled rejection errors. +[`did-fail-load`](web-contents.md#event-did-fail-load)). A noop rejection handler is already attached, which avoids unhandled rejection errors. If the existing page has a beforeUnload handler, [`did-fail-load`](web-contents.md#event-did-fail-load) will be called unless [`will-prevent-unload`](web-contents.md#event-did-fail-load) is handled. Loads the `url` in the window. The `url` must contain the protocol prefix, e.g. the `http://` or `file://`. If the load should bypass http cache then use the `pragma` header to achieve it. -```javascript -const { webContents } = require('electron') +```js +const win = new BrowserWindow() const options = { extraHeaders: 'pragma: no-cache\n' } -webContents.loadURL('https://github.com', options) +win.webContents.loadURL('https://github.com', options) ``` #### `contents.loadFile(filePath[, options])` -* `filePath` String +* `filePath` string * `options` Object (optional) - * `query` Record<String, String> (optional) - Passed to `url.format()`. - * `search` String (optional) - Passed to `url.format()`. - * `hash` String (optional) - Passed to `url.format()`. + * `query` Record\<string, string\> (optional) - Passed to `url.format()`. + * `search` string (optional) - Passed to `url.format()`. + * `hash` string (optional) - Passed to `url.format()`. Returns `Promise<void>` - the promise will resolve when the page has finished loading (see [`did-finish-load`](web-contents.md#event-did-finish-load)), and rejects @@ -940,24 +1118,28 @@ an app structure like this: Would require code like this ```js +const win = new BrowserWindow() win.loadFile('src/index.html') ``` -#### `contents.downloadURL(url)` +#### `contents.downloadURL(url[, options])` -* `url` String +* `url` string +* `options` Object (optional) + * `headers` Record\<string, string\> (optional) - HTTP request headers. Initiates a download of the resource at `url` without navigating. The `will-download` event of `session` will be triggered. #### `contents.getURL()` -Returns `String` - The URL of the current web page. +Returns `string` - The URL of the current web page. -```javascript +```js const { BrowserWindow } = require('electron') + const win = new BrowserWindow({ width: 800, height: 600 }) -win.loadURL('http://github.com').then(() => { +win.loadURL('https://github.com').then(() => { const currentURL = win.webContents.getURL() console.log(currentURL) }) @@ -965,11 +1147,26 @@ win.loadURL('http://github.com').then(() => { #### `contents.getTitle()` -Returns `String` - The title of the current web page. +Returns `string` - The title of the current web page. #### `contents.isDestroyed()` -Returns `Boolean` - Whether the web page is destroyed. +Returns `boolean` - Whether the web page is destroyed. + +#### `contents.close([opts])` + +* `opts` Object (optional) + * `waitForBeforeUnload` boolean - if true, fire the `beforeunload` event + before closing the page. If the page prevents the unload, the WebContents + will not be closed. The [`will-prevent-unload`](#event-will-prevent-unload) + will be fired if the page requests prevention of unload. + +Closes the page, as if the web content had called `window.close()`. + +If the page is successfully closed (i.e. the unload is not prevented by the +page, or `waitForBeforeUnload` is false or unspecified), the WebContents will +be destroyed and no longer usable. The [`destroyed`](#event-destroyed) event +will be emitted. #### `contents.focus()` @@ -977,20 +1174,20 @@ Focuses the web page. #### `contents.isFocused()` -Returns `Boolean` - Whether the web page is focused. +Returns `boolean` - Whether the web page is focused. #### `contents.isLoading()` -Returns `Boolean` - Whether web page is still loading resources. +Returns `boolean` - Whether web page is still loading resources. #### `contents.isLoadingMainFrame()` -Returns `Boolean` - Whether the main frame (and not just iframes or frames within it) is +Returns `boolean` - Whether the main frame (and not just iframes or frames within it) is still loading. #### `contents.isWaitingForResponse()` -Returns `Boolean` - Whether the web page is waiting for a first-response from the main +Returns `boolean` - Whether the web page is waiting for a first-response from the main resource of the page. #### `contents.stop()` @@ -1005,47 +1202,127 @@ Reloads the current web page. Reloads current page and ignores cache. -#### `contents.canGoBack()` +#### `contents.canGoBack()` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/41752 + breaking-changes-header: deprecated-clearhistory-cangoback-goback-cangoforward-goforward-gotoindex-cangotooffset-gotooffset-on-webcontents +``` +--> -Returns `Boolean` - Whether the browser can go back to previous web page. +Returns `boolean` - Whether the browser can go back to previous web page. -#### `contents.canGoForward()` +**Deprecated:** Should use the new [`contents.navigationHistory.canGoBack`](navigation-history.md#navigationhistorycangoback) API. -Returns `Boolean` - Whether the browser can go forward to next web page. +#### `contents.canGoForward()` _Deprecated_ -#### `contents.canGoToOffset(offset)` +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/41752 + breaking-changes-header: deprecated-clearhistory-cangoback-goback-cangoforward-goforward-gotoindex-cangotooffset-gotooffset-on-webcontents +``` +--> + +Returns `boolean` - Whether the browser can go forward to next web page. + +**Deprecated:** Should use the new [`contents.navigationHistory.canGoForward`](navigation-history.md#navigationhistorycangoforward) API. + +#### `contents.canGoToOffset(offset)` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/41752 + breaking-changes-header: deprecated-clearhistory-cangoback-goback-cangoforward-goforward-gotoindex-cangotooffset-gotooffset-on-webcontents +``` +--> * `offset` Integer -Returns `Boolean` - Whether the web page can go to `offset`. +Returns `boolean` - Whether the web page can go to `offset`. -#### `contents.clearHistory()` +**Deprecated:** Should use the new [`contents.navigationHistory.canGoToOffset`](navigation-history.md#navigationhistorycangotooffsetoffset) API. + +#### `contents.clearHistory()` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/41752 + breaking-changes-header: deprecated-clearhistory-cangoback-goback-cangoforward-goforward-gotoindex-cangotooffset-gotooffset-on-webcontents +``` +--> Clears the navigation history. -#### `contents.goBack()` +**Deprecated:** Should use the new [`contents.navigationHistory.clear`](navigation-history.md#navigationhistoryclear) API. + +#### `contents.goBack()` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/41752 + breaking-changes-header: deprecated-clearhistory-cangoback-goback-cangoforward-goforward-gotoindex-cangotooffset-gotooffset-on-webcontents +``` +--> Makes the browser go back a web page. -#### `contents.goForward()` +**Deprecated:** Should use the new [`contents.navigationHistory.goBack`](navigation-history.md#navigationhistorygoback) API. + +#### `contents.goForward()` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/41752 + breaking-changes-header: deprecated-clearhistory-cangoback-goback-cangoforward-goforward-gotoindex-cangotooffset-gotooffset-on-webcontents +``` +--> Makes the browser go forward a web page. -#### `contents.goToIndex(index)` +**Deprecated:** Should use the new [`contents.navigationHistory.goForward`](navigation-history.md#navigationhistorygoforward) API. + +#### `contents.goToIndex(index)` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/41752 + breaking-changes-header: deprecated-clearhistory-cangoback-goback-cangoforward-goforward-gotoindex-cangotooffset-gotooffset-on-webcontents +``` +--> * `index` Integer Navigates browser to the specified absolute web page index. -#### `contents.goToOffset(offset)` +**Deprecated:** Should use the new [`contents.navigationHistory.goToIndex`](navigation-history.md#navigationhistorygotoindexindex) API. + +#### `contents.goToOffset(offset)` _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/41752 + breaking-changes-header: deprecated-clearhistory-cangoback-goback-cangoforward-goforward-gotoindex-cangotooffset-gotooffset-on-webcontents +``` +--> * `offset` Integer Navigates to the specified offset from the "current entry". +**Deprecated:** Should use the new [`contents.navigationHistory.goToOffset`](navigation-history.md#navigationhistorygotooffsetoffset) API. + #### `contents.isCrashed()` -Returns `Boolean` - Whether the renderer process has crashed. +Returns `boolean` - Whether the renderer process has crashed. #### `contents.forcefullyCrashRenderer()` @@ -1061,7 +1338,9 @@ when this process is unstable or unusable, for instance in order to recover from the `unresponsive` event. ```js -contents.on('unresponsive', async () => { +const win = new BrowserWindow() + +win.webContents.on('unresponsive', async () => { const { response } = await dialog.showMessageBox({ message: 'App X has become unresponsive', title: 'Do you want to try forcefully reloading the app?', @@ -1069,42 +1348,43 @@ contents.on('unresponsive', async () => { cancelId: 1 }) if (response === 0) { - contents.forcefullyCrashRenderer() - contents.reload() + win.webContents.forcefullyCrashRenderer() + win.webContents.reload() } }) ``` #### `contents.setUserAgent(userAgent)` -* `userAgent` String +* `userAgent` string Overrides the user agent for this web page. #### `contents.getUserAgent()` -Returns `String` - The user agent for this web page. +Returns `string` - The user agent for this web page. #### `contents.insertCSS(css[, options])` -* `css` String +* `css` string * `options` Object (optional) - * `cssOrigin` String (optional) - Can be either 'user' or 'author'; Specifying 'user' enables you to prevent websites from overriding the CSS you insert. Default is 'author'. + * `cssOrigin` string (optional) - Can be 'user' or 'author'. Sets the [cascade origin](https://www.w3.org/TR/css3-cascade/#cascade-origin) of the inserted stylesheet. Default is 'author'. -Returns `Promise<String>` - A promise that resolves with a key for the inserted CSS that can later be used to remove the CSS via `contents.removeInsertedCSS(key)`. +Returns `Promise<string>` - A promise that resolves with a key for the inserted CSS that can later be used to remove the CSS via `contents.removeInsertedCSS(key)`. Injects CSS into the current web page and returns a unique key for the inserted stylesheet. ```js -contents.on('did-finish-load', () => { - contents.insertCSS('html, body { background-color: #f00; }') +const win = new BrowserWindow() +win.webContents.on('did-finish-load', () => { + win.webContents.insertCSS('html, body { background-color: #f00; }') }) ``` #### `contents.removeInsertedCSS(key)` -* `key` String +* `key` string Returns `Promise<void>` - Resolves if the removal was successful. @@ -1112,16 +1392,18 @@ Removes the inserted CSS from the current web page. The stylesheet is identified by its key, which is returned from `contents.insertCSS(css)`. ```js -contents.on('did-finish-load', async () => { - const key = await contents.insertCSS('html, body { background-color: #f00; }') - contents.removeInsertedCSS(key) +const win = new BrowserWindow() + +win.webContents.on('did-finish-load', async () => { + const key = await win.webContents.insertCSS('html, body { background-color: #f00; }') + win.webContents.removeInsertedCSS(key) }) ``` #### `contents.executeJavaScript(code[, userGesture])` -* `code` String -* `userGesture` Boolean (optional) - Default is `false`. +* `code` string +* `userGesture` boolean (optional) - Default is `false`. Returns `Promise<any>` - A promise that resolves with the result of the executed code or is rejected if the result of the code is a rejected promise. @@ -1135,7 +1417,9 @@ this limitation. Code execution will be suspended until web page stop loading. ```js -contents.executeJavaScript('fetch("https://jsonplaceholder.typicode.com/users/1").then(resp => resp.json())', true) +const win = new BrowserWindow() + +win.webContents.executeJavaScript('fetch("https://jsonplaceholder.typicode.com/users/1").then(resp => resp.json())', true) .then((result) => { console.log(result) // Will be the JSON object from the fetch call }) @@ -1145,7 +1429,7 @@ contents.executeJavaScript('fetch("https://jsonplaceholder.typicode.com/users/1" * `worldId` Integer - The ID of the world to run the javascript in, `0` is the default world, `999` is the world used by Electron's `contextIsolation` feature. You can provide any integer here. * `scripts` [WebSource[]](structures/web-source.md) -* `userGesture` Boolean (optional) - Default is `false`. +* `userGesture` boolean (optional) - Default is `false`. Returns `Promise<any>` - A promise that resolves with the result of the executed code or is rejected if the result of the code is a rejected promise. @@ -1154,39 +1438,77 @@ Works like `executeJavaScript` but evaluates `scripts` in an isolated context. #### `contents.setIgnoreMenuShortcuts(ignore)` -* `ignore` Boolean +* `ignore` boolean Ignore application menu shortcuts while this web contents is focused. #### `contents.setWindowOpenHandler(handler)` -* `handler` Function<{action: 'deny'} | {action: 'allow', overrideBrowserWindowOptions?: BrowserWindowConstructorOptions}> +* `handler` Function\<[WindowOpenHandlerResponse](structures/window-open-handler-response.md)\> * `details` Object - * `url` String - The _resolved_ version of the URL passed to `window.open()`. e.g. opening a window with `window.open('foo')` will yield something like `https://the-origin/the/current/path/foo`. - * `frameName` String - Name of the window provided in `window.open()` - * `features` String - Comma separated list of window features provided to `window.open()`. - Returns `{action: 'deny'} | {action: 'allow', overrideBrowserWindowOptions?: BrowserWindowConstructorOptions}` - `deny` cancels the creation of the new - window. `allow` will allow the new window to be created. Specifying `overrideBrowserWindowOptions` allows customization of the created window. + * `url` string - The _resolved_ version of the URL passed to `window.open()`. e.g. opening a window with `window.open('foo')` will yield something like `https://the-origin/the/current/path/foo`. + * `frameName` string - Name of the window provided in `window.open()` + * `features` string - Comma separated list of window features provided to `window.open()`. + * `disposition` string - Can be `default`, `foreground-tab`, `background-tab`, + `new-window` or `other`. + * `referrer` [Referrer](structures/referrer.md) - The referrer that will be + passed to the new window. May or may not result in the `Referer` header being + sent, depending on the referrer policy. + * `postBody` [PostBody](structures/post-body.md) (optional) - The post data that + will be sent to the new window, along with the appropriate headers that will + be set. If no post data is to be sent, the value will be `null`. Only defined + when the window is being created by a form that set `target=_blank`. + + Returns `WindowOpenHandlerResponse` - When set to `{ action: 'deny' }` cancels the creation of the new + window. `{ action: 'allow' }` will allow the new window to be created. Returning an unrecognized value such as a null, undefined, or an object without a recognized 'action' value will result in a console error and have the same effect as returning `{action: 'deny'}`. -Called before creating a window when `window.open()` is called from the -renderer. See [`window.open()`](window-open.md) for more details and how to use this in conjunction with `did-create-window`. +Called before creating a window when a new window is requested by the renderer, e.g. +by `window.open()`, a link with `target="_blank"`, shift+clicking on a link, or +submitting a form with `<form target="_blank">`. See +[`window.open()`](window-open.md) for more details and how to use this in +conjunction with `did-create-window`. + +An example showing how to customize the process of new `BrowserWindow` creation to be `BrowserView` attached to main window instead: + +```js +const { BrowserView, BrowserWindow } = require('electron') + +const mainWindow = new BrowserWindow() + +mainWindow.webContents.setWindowOpenHandler((details) => { + return { + action: 'allow', + createWindow: (options) => { + const browserView = new BrowserView(options) + mainWindow.addBrowserView(browserView) + browserView.setBounds({ x: 0, y: 0, width: 640, height: 480 }) + // For `background-tab` disposition (e.g., when middle-clicking or ctrl/cmd-clicking a link), + // `options.webContents` is undefined because its creation can be deferred. So load the URL manually. + if (details.disposition === 'background-tab') { + browserView.webContents.loadURL(details.url) + } + return browserView.webContents + } + } +}) +``` #### `contents.setAudioMuted(muted)` -* `muted` Boolean +* `muted` boolean Mute the audio on the current web page. #### `contents.isAudioMuted()` -Returns `Boolean` - Whether this page has been muted. +Returns `boolean` - Whether this page has been muted. #### `contents.isCurrentlyAudible()` -Returns `Boolean` - Whether audio is currently playing. +Returns `boolean` - Whether audio is currently playing. #### `contents.setZoomFactor(factor)` @@ -1199,38 +1521,41 @@ The factor must be greater than 0.0. #### `contents.getZoomFactor()` -Returns `Number` - the current zoom factor. +Returns `number` - the current zoom factor. #### `contents.setZoomLevel(level)` -* `level` Number - Zoom level. +* `level` number - Zoom level. Changes the zoom level to the specified level. The original size is 0 and each increment above or below represents zooming 20% larger or smaller to default limits of 300% and 50% of original size, respectively. The formula for this is `scale := 1.2 ^ level`. -> **NOTE**: The zoom policy at the Chromium level is same-origin, meaning that the +> [!NOTE] +> The zoom policy at the Chromium level is same-origin, meaning that the > zoom level for a specific domain propagates across all instances of windows with > the same domain. Differentiating the window URLs will make zoom work per-window. #### `contents.getZoomLevel()` -Returns `Number` - the current zoom level. +Returns `number` - the current zoom level. #### `contents.setVisualZoomLevelLimits(minimumLevel, maximumLevel)` -* `minimumLevel` Number -* `maximumLevel` Number +* `minimumLevel` number +* `maximumLevel` number Returns `Promise<void>` Sets the maximum and minimum pinch-to-zoom level. -> **NOTE**: Visual zoom is disabled by default in Electron. To re-enable it, call: +> [!NOTE] +> Visual zoom is disabled by default in Electron. To re-enable it, call: > > ```js -> contents.setVisualZoomLevelLimits(1, 3) +> const win = new BrowserWindow() +> win.webContents.setVisualZoomLevelLimits(1, 3) > ``` #### `contents.undo()` @@ -1249,6 +1574,10 @@ Executes the editing command `cut` in web page. Executes the editing command `copy` in web page. +#### `contents.centerSelection()` + +Centers the current text selection in web page. + #### `contents.copyImageAt(x, y)` * `x` Integer @@ -1256,6 +1585,20 @@ Executes the editing command `copy` in web page. Copy the image at the given position to the clipboard. +#### `contents.copyVideoFrameAt(x, y)` + +* `x` Integer +* `y` Integer + +When executed on a video media element, copies the frame at (x, y) to the clipboard. + +#### `contents.saveVideoFrameAs(x, y)` + +* `x` Integer +* `y` Integer + +When executed on a video media element, shows a save dialog and saves the frame at (x, y) to disk. + #### `contents.paste()` Executes the editing command `paste` in web page. @@ -1276,21 +1619,61 @@ Executes the editing command `selectAll` in web page. Executes the editing command `unselect` in web page. +#### `contents.scrollToTop()` + +Scrolls to the top of the current `webContents`. + +#### `contents.scrollToBottom()` + +Scrolls to the bottom of the current `webContents`. + +#### `contents.adjustSelection(options)` + +* `options` Object + * `start` Number (optional) - Amount to shift the start index of the current selection. + * `end` Number (optional) - Amount to shift the end index of the current selection. + +Adjusts the current text selection starting and ending points in the focused frame by the given amounts. A negative amount moves the selection towards the beginning of the document, and a positive amount moves the selection towards the end of the document. + +Example: + +```js +const win = new BrowserWindow() + +// Adjusts the beginning of the selection 1 letter forward, +// and the end of the selection 5 letters forward. +win.webContents.adjustSelection({ start: 1, end: 5 }) + +// Adjusts the beginning of the selection 2 letters forward, +// and the end of the selection 3 letters backward. +win.webContents.adjustSelection({ start: 2, end: -3 }) +``` + +For a call of `win.webContents.adjustSelection({ start: 1, end: 5 })` + +Before: + +<img width="487" alt="Image Before Text Selection Adjustment" src="../images/web-contents-text-selection-before.png"/> + +After: + +<img width="487" alt="Image After Text Selection Adjustment" src="../images/web-contents-text-selection-after.png"/> + #### `contents.replace(text)` -* `text` String +* `text` string Executes the editing command `replace` in web page. #### `contents.replaceMisspelling(text)` -* `text` String +* `text` string Executes the editing command `replaceMisspelling` in web page. #### `contents.insertText(text)` -* `text` String +* `text` string Returns `Promise<void>` @@ -1298,12 +1681,11 @@ Inserts `text` to the focused element. #### `contents.findInPage(text[, options])` -* `text` String - Content to be searched, must not be empty. +* `text` string - Content to be searched, must not be empty. * `options` Object (optional) - * `forward` Boolean (optional) - Whether to search forward or backward, defaults to `true`. - * `findNext` Boolean (optional) - Whether the operation is first request or a follow up, - defaults to `false`. - * `matchCase` Boolean (optional) - Whether search should be case-sensitive, + * `forward` boolean (optional) - Whether to search forward or backward, defaults to `true`. + * `findNext` boolean (optional) - Whether to begin a new text finding session with this request. Should be `true` for initial requests, and `false` for follow-up requests. Defaults to `false`. + * `matchCase` boolean (optional) - Whether search should be case-sensitive, defaults to `false`. Returns `Integer` - The request id used for the request. @@ -1313,105 +1695,100 @@ can be obtained by subscribing to [`found-in-page`](web-contents.md#event-found- #### `contents.stopFindInPage(action)` -* `action` String - Specifies the action to take place when ending - [`webContents.findInPage`] request. +* `action` string - Specifies the action to take place when ending + [`webContents.findInPage`](#contentsfindinpagetext-options) request. * `clearSelection` - Clear the selection. * `keepSelection` - Translate the selection into a normal selection. * `activateSelection` - Focus and click the selection node. Stops any `findInPage` request for the `webContents` with the provided `action`. -```javascript -const { webContents } = require('electron') -webContents.on('found-in-page', (event, result) => { - if (result.finalUpdate) webContents.stopFindInPage('clearSelection') +```js +const win = new BrowserWindow() +win.webContents.on('found-in-page', (event, result) => { + if (result.finalUpdate) win.webContents.stopFindInPage('clearSelection') }) -const requestId = webContents.findInPage('api') +const requestId = win.webContents.findInPage('api') console.log(requestId) ``` -#### `contents.capturePage([rect])` +#### `contents.capturePage([rect, opts])` * `rect` [Rectangle](structures/rectangle.md) (optional) - The area of the page to be captured. +* `opts` Object (optional) + * `stayHidden` boolean (optional) - Keep the page hidden instead of visible. Default is `false`. + * `stayAwake` boolean (optional) - Keep the system awake instead of allowing it to sleep. Default is `false`. Returns `Promise<NativeImage>` - Resolves with a [NativeImage](native-image.md) Captures a snapshot of the page within `rect`. Omitting `rect` will capture the whole visible page. +The page is considered visible when its browser window is hidden and the capturer count is non-zero. +If you would like the page to stay hidden, you should ensure that `stayHidden` is set to true. #### `contents.isBeingCaptured()` -Returns `Boolean` - Whether this page is being captured. It returns true when the capturer count -is large then 0. - -#### `contents.incrementCapturerCount([size, stayHidden])` - -* `size` [Size](structures/size.md) (optional) - The preferred size for the capturer. -* `stayHidden` Boolean (optional) - Keep the page hidden instead of visible. - -Increase the capturer count by one. The page is considered visible when its browser window is -hidden and the capturer count is non-zero. If you would like the page to stay hidden, you should ensure that `stayHidden` is set to true. - -This also affects the Page Visibility API. - -#### `contents.decrementCapturerCount([stayHidden])` - -* `stayHidden` Boolean (optional) - Keep the page in hidden state instead of visible. +Returns `boolean` - Whether this page is being captured. It returns true when the capturer count +is greater than 0. -Decrease the capturer count by one. The page will be set to hidden or occluded state when its -browser window is hidden or occluded and the capturer count reaches zero. If you want to -decrease the hidden capturer count instead you should set `stayHidden` to true. - -#### `contents.getPrinters()` +#### `contents.getPrintersAsync()` Get the system printer list. -Returns [`PrinterInfo[]`](structures/printer-info.md) +Returns `Promise<PrinterInfo[]>` - Resolves with a [`PrinterInfo[]`](structures/printer-info.md) #### `contents.print([options], [callback])` * `options` Object (optional) - * `silent` Boolean (optional) - Don't ask user for print settings. Default is `false`. - * `printBackground` Boolean (optional) - Prints the background color and image of + * `silent` boolean (optional) - Don't ask user for print settings. Default is `false`. + * `printBackground` boolean (optional) - Prints the background color and image of the web page. Default is `false`. - * `deviceName` String (optional) - Set the printer device name to use. Must be the system-defined name and not the 'friendly' name, e.g 'Brother_QL_820NWB' and not 'Brother QL-820NWB'. - * `color` Boolean (optional) - Set whether the printed web page will be in color or grayscale. Default is `true`. + * `deviceName` string (optional) - Set the printer device name to use. Must be the system-defined name and not the 'friendly' name, e.g 'Brother_QL_820NWB' and not 'Brother QL-820NWB'. + * `color` boolean (optional) - Set whether the printed web page will be in color or grayscale. Default is `true`. * `margins` Object (optional) - * `marginType` String (optional) - Can be `default`, `none`, `printableArea`, or `custom`. If `custom` is chosen, you will also need to specify `top`, `bottom`, `left`, and `right`. - * `top` Number (optional) - The top margin of the printed web page, in pixels. - * `bottom` Number (optional) - The bottom margin of the printed web page, in pixels. - * `left` Number (optional) - The left margin of the printed web page, in pixels. - * `right` Number (optional) - The right margin of the printed web page, in pixels. - * `landscape` Boolean (optional) - Whether the web page should be printed in landscape mode. Default is `false`. - * `scaleFactor` Number (optional) - The scale factor of the web page. - * `pagesPerSheet` Number (optional) - The number of pages to print per page sheet. - * `collate` Boolean (optional) - Whether the web page should be collated. - * `copies` Number (optional) - The number of copies of the web page to print. + * `marginType` string (optional) - Can be `default`, `none`, `printableArea`, or `custom`. If `custom` is chosen, you will also need to specify `top`, `bottom`, `left`, and `right`. + * `top` number (optional) - The top margin of the printed web page, in pixels. + * `bottom` number (optional) - The bottom margin of the printed web page, in pixels. + * `left` number (optional) - The left margin of the printed web page, in pixels. + * `right` number (optional) - The right margin of the printed web page, in pixels. + * `landscape` boolean (optional) - Whether the web page should be printed in landscape mode. Default is `false`. + * `scaleFactor` number (optional) - The scale factor of the web page. + * `pagesPerSheet` number (optional) - The number of pages to print per page sheet. + * `collate` boolean (optional) - Whether the web page should be collated. + * `copies` number (optional) - The number of copies of the web page to print. * `pageRanges` Object[] (optional) - The page range to print. On macOS, only one range is honored. - * `from` Number - Index of the first page to print (0-based). - * `to` Number - Index of the last page to print (inclusive) (0-based). - * `duplexMode` String (optional) - Set the duplex mode of the printed web page. Can be `simplex`, `shortEdge`, or `longEdge`. - * `dpi` Record<string, number> (optional) - * `horizontal` Number (optional) - The horizontal dpi. - * `vertical` Number (optional) - The vertical dpi. - * `header` String (optional) - String to be printed as page header. - * `footer` String (optional) - String to be printed as page footer. - * `pageSize` String | Size (optional) - Specify page size of the printed document. Can be `A3`, - `A4`, `A5`, `Legal`, `Letter`, `Tabloid` or an Object containing `height`. + * `from` number - Index of the first page to print (0-based). + * `to` number - Index of the last page to print (inclusive) (0-based). + * `duplexMode` string (optional) - Set the duplex mode of the printed web page. Can be `simplex`, `shortEdge`, or `longEdge`. + * `dpi` Record\<string, number\> (optional) + * `horizontal` number (optional) - The horizontal dpi. + * `vertical` number (optional) - The vertical dpi. + * `header` string (optional) - string to be printed as page header. + * `footer` string (optional) - string to be printed as page footer. + * `pageSize` string | Size (optional) - Specify page size of the printed document. Can be `A0`, `A1`, `A2`, `A3`, + `A4`, `A5`, `A6`, `Legal`, `Letter`, `Tabloid` or an Object containing `height` and `width`. + * `usePrinterDefaultPageSize` boolean (optional) - Whether to use a given printer's default page size. Default is `false`. Cannot be combined with `pageSize`. When `deviceName` is provided, uses the default page size of that specific printer. When `deviceName` is not provided, uses the default page size of the system's default printer. If the printer's default page size cannot be retrieved, falls back to A4 (210mm x 297mm). * `callback` Function (optional) - * `success` Boolean - Indicates success of the print call. - * `failureReason` String - Error description called back if the print fails. + * `success` boolean - Indicates success of the print call. + * `failureReason` string - Error description called back if the print fails. -When a custom `pageSize` is passed, Chromium attempts to validate platform specific minimum values for `width_microns` and `height_microns`. Width and height must both be minimum 353 microns but may be higher on some operating systems. +When a custom `pageSize` is passed, Chromium attempts to validate platform specific minimum values for `width_microns` and `height_microns`. Width and height must both be minimum 353 microns but may be higher on some operating systems. If a valid `pageSize` is not passed and `usePrinterDefaultPageSize` is `false`, an error will be thrown. Prints window's web page. When `silent` is set to `true`, Electron will pick the system's default printer if `deviceName` is empty and the default settings for printing. +Some possible `failureReason`s for print failure include: + +* "Invalid printer settings" +* "Print job canceled" +* "Print job failed" + Use `page-break-before: always;` CSS style to force to print to a new page. Example usage: ```js +const win = new BrowserWindow() const options = { silent: true, deviceName: 'My-Printer', @@ -1428,77 +1805,70 @@ win.webContents.print(options, (success, errorType) => { #### `contents.printToPDF(options)` * `options` Object - * `headerFooter` Record<string, string> (optional) - the header and footer for the PDF. - * `title` String - The title for the PDF header. - * `url` String - the url for the PDF footer. - * `landscape` Boolean (optional) - `true` for landscape, `false` for portrait. - * `marginsType` Integer (optional) - Specifies the type of margins to use. Uses 0 for - default margin, 1 for no margin, and 2 for minimum margin. - * `scaleFactor` Number (optional) - The scale factor of the web page. Can range from 0 to 100. - * `pageRanges` Record<string, number> (optional) - The page range to print. - * `from` Number - Index of the first page to print (0-based). - * `to` Number - Index of the last page to print (inclusive) (0-based). - * `pageSize` String | Size (optional) - Specify page size of the generated PDF. Can be `A3`, - `A4`, `A5`, `Legal`, `Letter`, `Tabloid` or an Object containing `height` and `width` in microns. - * `printBackground` Boolean (optional) - Whether to print CSS backgrounds. - * `printSelectionOnly` Boolean (optional) - Whether to print selection only. + * `landscape` boolean (optional) - Paper orientation.`true` for landscape, `false` for portrait. Defaults to false. + * `displayHeaderFooter` boolean (optional) - Whether to display header and footer. Defaults to false. + * `printBackground` boolean (optional) - Whether to print background graphics. Defaults to false. + * `scale` number(optional) - Scale of the webpage rendering. Defaults to 1. + * `pageSize` string | Size (optional) - Specify page size of the generated PDF. Can be `A0`, `A1`, `A2`, `A3`, + `A4`, `A5`, `A6`, `Legal`, `Letter`, `Tabloid`, `Ledger`, or an Object containing `height` and `width` in inches. Defaults to `Letter`. + * `margins` Object (optional) + * `top` number (optional) - Top margin in inches. Defaults to 1cm (~0.4 inches). + * `bottom` number (optional) - Bottom margin in inches. Defaults to 1cm (~0.4 inches). + * `left` number (optional) - Left margin in inches. Defaults to 1cm (~0.4 inches). + * `right` number (optional) - Right margin in inches. Defaults to 1cm (~0.4 inches). + * `pageRanges` string (optional) - Page ranges to print, e.g., '1-5, 8, 11-13'. Defaults to the empty string, which means print all pages. + * `headerTemplate` string (optional) - HTML template for the print header. Should be valid HTML markup with following classes used to inject printing values into them: `date` (formatted print date), `title` (document title), `url` (document location), `pageNumber` (current page number) and `totalPages` (total pages in the document). For example, `<span class=title></span>` would generate span containing the title. + * `footerTemplate` string (optional) - HTML template for the print footer. Should use the same format as the `headerTemplate`. + * `preferCSSPageSize` boolean (optional) - Whether or not to prefer page size as defined by css. Defaults to false, in which case the content will be scaled to fit the paper size. + * `generateTaggedPDF` boolean (optional) _Experimental_ - Whether or not to generate a tagged (accessible) PDF. Defaults to false. As this property is experimental, the generated PDF may not adhere fully to PDF/UA and WCAG standards. + * `generateDocumentOutline` boolean (optional) _Experimental_ - Whether or not to generate a PDF document outline from content headers. Defaults to false. Returns `Promise<Buffer>` - Resolves with the generated PDF data. -Prints window's web page as PDF with Chromium's preview printing custom -settings. +Prints the window's web page as PDF. The `landscape` will be ignored if `@page` CSS at-rule is used in the web page. -By default, an empty `options` will be regarded as: - -```javascript -{ - marginsType: 0, - printBackground: false, - printSelectionOnly: false, - landscape: false, - pageSize: 'A4', - scaleFactor: 100 -} -``` - -Use `page-break-before: always;` CSS style to force to print to a new page. - An example of `webContents.printToPDF`: -```javascript -const { BrowserWindow } = require('electron') -const fs = require('fs') -const path = require('path') -const os = require('os') +```js +const { app, BrowserWindow } = require('electron') -const win = new BrowserWindow({ width: 800, height: 600 }) -win.loadURL('http://github.com') +const fs = require('node:fs') +const os = require('node:os') +const path = require('node:path') -win.webContents.on('did-finish-load', () => { - // Use default printing options - win.webContents.printToPDF({}).then(data => { +app.whenReady().then(() => { + const win = new BrowserWindow() + win.loadURL('https://github.com') + + win.webContents.on('did-finish-load', () => { + // Use default printing options const pdfPath = path.join(os.homedir(), 'Desktop', 'temp.pdf') - fs.writeFile(pdfPath, data, (error) => { - if (error) throw error - console.log(`Wrote PDF successfully to ${pdfPath}`) + win.webContents.printToPDF({}).then(data => { + fs.writeFile(pdfPath, data, (error) => { + if (error) throw error + console.log(`Wrote PDF successfully to ${pdfPath}`) + }) + }).catch(error => { + console.log(`Failed to write PDF to ${pdfPath}: `, error) }) - }).catch(error => { - console.log(`Failed to write PDF to ${pdfPath}: `, error) }) }) ``` +See [Page.printToPdf](https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-printToPDF) for more information. + #### `contents.addWorkSpace(path)` -* `path` String +* `path` string Adds the specified path to DevTools workspace. Must be used after DevTools creation: -```javascript +```js const { BrowserWindow } = require('electron') + const win = new BrowserWindow() win.webContents.on('devtools-opened', () => { win.webContents.addWorkSpace(__dirname) @@ -1507,7 +1877,7 @@ win.webContents.on('devtools-opened', () => { #### `contents.removeWorkSpace(path)` -* `path` String +* `path` string Removes the specified path from DevTools workspace. @@ -1515,67 +1885,22 @@ Removes the specified path from DevTools workspace. * `devToolsWebContents` WebContents -Uses the `devToolsWebContents` as the target `WebContents` to show devtools. +Uses the `devToolsWebContents` as the target `WebContents` to show DevTools. The `devToolsWebContents` must not have done any navigation, and it should not be used for other purposes after the call. -By default Electron manages the devtools by creating an internal `WebContents` +By default, Electron manages the DevTools by creating an internal `WebContents` with native view, which developers have very limited control of. With the `setDevToolsWebContents` method, developers can use any `WebContents` to show -the devtools in it, including `BrowserWindow`, `BrowserView` and `<webview>` -tag. +the DevTools in it, such as [`BrowserWindow`](./browser-window.md) or [`WebContentsView`](./web-contents-view.md). -Note that closing the devtools does not destroy the `devToolsWebContents`, it -is caller's responsibility to destroy `devToolsWebContents`. +Note that closing the DevTools does not destroy the `devToolsWebContents`, it +is the caller's responsibility to destroy `devToolsWebContents` manually. -An example of showing devtools in a `<webview>` tag: +An example of showing DevTools in a `BrowserWindow`: -```html -<html> -<head> - <style type="text/css"> - * { margin: 0; } - #browser { height: 70%; } - #devtools { height: 30%; } - </style> -</head> -<body> - <webview id="browser" src="https://github.com"></webview> - <webview id="devtools" src="about:blank"></webview> - <script> - const { ipcRenderer } = require('electron') - const emittedOnce = (element, eventName) => new Promise(resolve => { - element.addEventListener(eventName, event => resolve(event), { once: true }) - }) - const browserView = document.getElementById('browser') - const devtoolsView = document.getElementById('devtools') - const browserReady = emittedOnce(browserView, 'dom-ready') - const devtoolsReady = emittedOnce(devtoolsView, 'dom-ready') - Promise.all([browserReady, devtoolsReady]).then(() => { - const targetId = browserView.getWebContentsId() - const devtoolsId = devtoolsView.getWebContentsId() - ipcRenderer.send('open-devtools', targetId, devtoolsId) - }) - </script> -</body> -</html> -``` - -```js -// Main process -const { ipcMain, webContents } = require('electron') -ipcMain.on('open-devtools', (event, targetContentsId, devtoolsContentsId) => { - const target = webContents.fromId(targetContentsId) - const devtools = webContents.fromId(devtoolsContentsId) - target.setDevToolsWebContents(devtools) - target.openDevTools() -}) -``` - -An example of showing devtools in a `BrowserWindow`: - -```js +```js title='main.js' const { app, BrowserWindow } = require('electron') let win = null @@ -1593,28 +1918,43 @@ app.whenReady().then(() => { #### `contents.openDevTools([options])` * `options` Object (optional) - * `mode` String - Opens the devtools with specified dock state, can be - `right`, `bottom`, `undocked`, `detach`. Defaults to last used dock state. + * `mode` string - Opens the DevTools with specified dock state, can be + `left`, `right`, `bottom`, `undocked`, `detach`. Defaults to last used dock state. In `undocked` mode it's possible to dock back. In `detach` mode it's not. - * `activate` Boolean (optional) - Whether to bring the opened devtools window + * `activate` boolean (optional) - Whether to bring the opened DevTools window to the foreground. The default is `true`. + * `title` string (optional) - A title for the DevTools window (only in `undocked` or `detach` mode). -Opens the devtools. +Opens the DevTools. When `contents` is a `<webview>` tag, the `mode` would be `detach` by default, explicitly passing an empty `mode` can force using last used dock state. +On Windows, if Windows Control Overlay is enabled, DevTools will be opened with `mode: 'detach'`. + #### `contents.closeDevTools()` -Closes the devtools. +Closes the DevTools view. #### `contents.isDevToolsOpened()` -Returns `Boolean` - Whether the devtools is opened. +Returns `boolean` - Whether the DevTools view is opened. #### `contents.isDevToolsFocused()` -Returns `Boolean` - Whether the devtools view is focused . +Returns `boolean` - Whether the DevTools view is focused . + +#### `contents.getDevToolsTitle()` + +Returns `string` - the current title of the DevTools window. This will only be visible +if DevTools is opened in `undocked` or `detach` mode. + +#### `contents.setDevToolsTitle(title)` + +* `title` string + +Changes the title of the DevTools window to `title`. This will only be visible if DevTools is +opened in `undocked` or `detach` mode. #### `contents.toggleDevTools()` @@ -1633,7 +1973,7 @@ Opens the developer tools for the shared worker context. #### `contents.inspectSharedWorkerById(workerId)` -* `workerId` String +* `workerId` string Inspects the shared worker based on its ID. @@ -1647,55 +1987,30 @@ Opens the developer tools for the service worker context. #### `contents.send(channel, ...args)` -* `channel` String +* `channel` string * `...args` any[] Send an asynchronous message to the renderer process via `channel`, along with -arguments. Arguments will be serialized with the [Structured Clone -Algorithm][SCA], just like [`postMessage`][], so prototype chains will not be +arguments. Arguments will be serialized with the [Structured Clone Algorithm][SCA], +just like [`postMessage`][], so prototype chains will not be included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an exception. -> **NOTE**: Sending non-standard JavaScript types such as DOM objects or -> special Electron objects is deprecated, and will begin throwing an exception -> starting with Electron 9. +:::warning -The renderer process can handle the message by listening to `channel` with the -[`ipcRenderer`](ipc-renderer.md) module. +Sending non-standard JavaScript types such as DOM objects or +special Electron objects will throw an exception. -An example of sending messages from the main process to the renderer process: +::: -```javascript -// In the main process. -const { app, BrowserWindow } = require('electron') -let win = null - -app.whenReady().then(() => { - win = new BrowserWindow({ width: 800, height: 600 }) - win.loadURL(`file://${__dirname}/index.html`) - win.webContents.on('did-finish-load', () => { - win.webContents.send('ping', 'whoooooooh!') - }) -}) -``` - -```html -<!-- index.html --> -<html> -<body> - <script> - require('electron').ipcRenderer.on('ping', (event, message) => { - console.log(message) // Prints 'whoooooooh!' - }) - </script> -</body> -</html> -``` +For additional reading, refer to [Electron's IPC guide](../tutorial/ipc.md). #### `contents.sendToFrame(frameId, channel, ...args)` -* `frameId` Integer -* `channel` String +* `frameId` Integer | \[number, number] - the ID of the frame to send to, or a + pair of `[processId, frameId]` if the frame is in a different process to the + main frame. +* `channel` string * `...args` any[] Send an asynchronous message to a specific frame in a renderer process via @@ -1704,9 +2019,8 @@ Send an asynchronous message to a specific frame in a renderer process via chains will not be included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an exception. -> **NOTE**: Sending non-standard JavaScript types such as DOM objects or -> special Electron objects is deprecated, and will begin throwing an exception -> starting with Electron 9. +> **NOTE:** Sending non-standard JavaScript types such as DOM objects or +> special Electron objects will throw an exception. The renderer process can handle the message by listening to `channel` with the [`ipcRenderer`](ipc-renderer.md) module. @@ -1730,7 +2044,7 @@ ipcMain.on('ping', (event) => { #### `contents.postMessage(channel, message, [transfer])` -* `channel` String +* `channel` string * `message` any * `transfer` MessagePortMain[] (optional) @@ -1745,8 +2059,9 @@ For example: ```js // Main process +const win = new BrowserWindow() const { port1, port2 } = new MessageChannelMain() -webContents.postMessage('port', { message: 'hello' }, [port1]) +win.webContents.postMessage('port', { message: 'hello' }, [port1]) // Renderer process ipcRenderer.on('port', (e, msg) => { @@ -1758,7 +2073,7 @@ ipcRenderer.on('port', (e, msg) => { #### `contents.enableDeviceEmulation(parameters)` * `parameters` Object - * `screenPosition` String - Specify the screen type to emulate + * `screenPosition` string - Specify the screen type to emulate (default: `desktop`): * `desktop` - Desktop screen type. * `mobile` - Mobile screen type. @@ -1782,12 +2097,14 @@ Disable device emulation enabled by `webContents.enableDeviceEmulation`. * `inputEvent` [MouseInputEvent](structures/mouse-input-event.md) | [MouseWheelInputEvent](structures/mouse-wheel-input-event.md) | [KeyboardInputEvent](structures/keyboard-input-event.md) Sends an input `event` to the page. -**Note:** The [`BrowserWindow`](browser-window.md) containing the contents needs to be focused for + +> [!NOTE] +> The [`BrowserWindow`](browser-window.md) containing the contents needs to be focused for `sendInputEvent()` to work. #### `contents.beginFrameSubscription([onlyDirty ,]callback)` -* `onlyDirty` Boolean (optional) - Defaults to `false`. +* `onlyDirty` boolean (optional) - Defaults to `false`. * `callback` Function * `image` [NativeImage](native-image.md) * `dirtyRect` [Rectangle](structures/rectangle.md) @@ -1811,8 +2128,9 @@ End subscribing for frame presentation events. #### `contents.startDrag(item)` * `item` Object - * `file` String[] | String - The path(s) to the file(s) being dragged. - * `icon` [NativeImage](native-image.md) | String - The image must be + * `file` string - The path to the file being dragged. + * `files` string[] (optional) - The paths to the files being dragged. (`files` will override `file` field) + * `icon` [NativeImage](native-image.md) | string - The image must be non-empty on macOS. Sets the `item` as dragging item for current drag-drop operation, `file` is the @@ -1821,16 +2139,17 @@ the cursor when dragging. #### `contents.savePage(fullPath, saveType)` -* `fullPath` String - The full file path. -* `saveType` String - Specify the save type. +* `fullPath` string - The absolute file path. +* `saveType` string - Specify the save type. * `HTMLOnly` - Save only the HTML of the page. * `HTMLComplete` - Save complete-html page. * `MHTML` - Save complete-html page as MHTML. Returns `Promise<void>` - resolves if the page is saved. -```javascript +```js const { BrowserWindow } = require('electron') + const win = new BrowserWindow() win.loadURL('https://github.com') @@ -1850,45 +2169,45 @@ Shows pop-up dictionary that searches the selected word on the page. #### `contents.isOffscreen()` -Returns `Boolean` - Indicates whether *offscreen rendering* is enabled. +Returns `boolean` - Indicates whether _offscreen rendering_ is enabled. #### `contents.startPainting()` -If *offscreen rendering* is enabled and not painting, start painting. +If _offscreen rendering_ is enabled and not painting, start painting. #### `contents.stopPainting()` -If *offscreen rendering* is enabled and painting, stop painting. +If _offscreen rendering_ is enabled and painting, stop painting. #### `contents.isPainting()` -Returns `Boolean` - If *offscreen rendering* is enabled returns whether it is currently painting. +Returns `boolean` - If _offscreen rendering_ is enabled returns whether it is currently painting. #### `contents.setFrameRate(fps)` * `fps` Integer -If *offscreen rendering* is enabled sets the frame rate to the specified number. -Only values between 1 and 60 are accepted. +If _offscreen rendering_ is enabled sets the frame rate to the specified number. +When `webPreferences.offscreen.useSharedTexture` is `false` only values between 1 and 240 are accepted. #### `contents.getFrameRate()` -Returns `Integer` - If *offscreen rendering* is enabled returns the current frame rate. +Returns `Integer` - If _offscreen rendering_ is enabled returns the current frame rate. #### `contents.invalidate()` Schedules a full repaint of the window this web contents is in. -If *offscreen rendering* is enabled invalidates the frame and generates a new +If _offscreen rendering_ is enabled invalidates the frame and generates a new one through the `'paint'` event. #### `contents.getWebRTCIPHandlingPolicy()` -Returns `String` - Returns the WebRTC IP Handling Policy. +Returns `string` - Returns the WebRTC IP Handling Policy. #### `contents.setWebRTCIPHandlingPolicy(policy)` -* `policy` String - Specify the WebRTC IP Handling Policy. +* `policy` string - Specify the WebRTC IP Handling Policy. * `default` - Exposes user's public and local IPs. This is the default behavior. When this policy is used, WebRTC has the right to enumerate all interfaces and bind them to discover public interfaces. @@ -1907,6 +2226,44 @@ Setting the WebRTC IP handling policy allows you to control which IPs are exposed via WebRTC. See [BrowserLeaks](https://browserleaks.com/webrtc) for more details. +#### `contents.getWebRTCUDPPortRange()` + +Returns `Object`: + +* `min` Integer - The minimum UDP port number that WebRTC should use. +* `max` Integer - The maximum UDP port number that WebRTC should use. + +By default this value is `{ min: 0, max: 0 }` , which would apply no restriction on the udp port range. + +#### `contents.setWebRTCUDPPortRange(udpPortRange)` + +* `udpPortRange` Object + * `min` Integer - The minimum UDP port number that WebRTC should use. + * `max` Integer - The maximum UDP port number that WebRTC should use. + +Setting the WebRTC UDP Port Range allows you to restrict the udp port range used by WebRTC. By default the port range is unrestricted. + +> [!NOTE] +> To reset to an unrestricted port range this value should be set to `{ min: 0, max: 0 }`. + +#### `contents.getMediaSourceId(requestWebContents)` + +* `requestWebContents` WebContents - Web contents that the id will be registered to. + +Returns `string` - The identifier of a WebContents stream. This identifier can be used +with `navigator.mediaDevices.getUserMedia` using a `chromeMediaSource` of `tab`. +The identifier is restricted to the web contents that it is registered to and is only valid for 10 seconds. + +#### `contents.getOrCreateDevToolsTargetId()` + +Returns `string` - The Chrome DevTools Protocol +[TargetID](https://chromedevtools.github.io/devtools-protocol/tot/Target/#type-TargetID) +associated with this WebContents. This is the reverse of +[`webContents.fromDevToolsTargetId()`](#webcontentsfromdevtoolstargetidtargetid). + +> [!NOTE] +> This method creates a new DevTools agent for this WebContents if one does not already exist. + #### `contents.getOSProcessId()` Returns `Integer` - The operating system `pid` of the associated renderer @@ -1918,9 +2275,23 @@ Returns `Integer` - The Chromium internal `pid` of the associated renderer. Can be compared to the `frameProcessId` passed by frame specific navigation events (e.g. `did-frame-navigate`) +#### `contents.clone()` + +Returns `WebContents` - A cloned WebContents instance. This method creates a copy +of the WebContents with the following attributes: + +* **WebPreferences** - All preferences from the original WebContents are copied +* **SiteInstance** - Uses the same SiteInstance as the original. This means the cloned WebContents will reuse the same render process as the original when loading same-origin pages, and only spawn a new render process for cross-origin navigations. This process allocation behavior is consistent with window.open and tab duplication in Chromium. For more details, see [Chromium's Site Isolation](https://www.chromium.org/developers/design-documents/site-isolation/) design document. +* **Opener relationship** - Inherits the opener (window.opener) relationship +* **Navigation state** - Copies the navigation history and controller state + +The cloned WebContents is an independent instance with its own lifecycle that can be destroyed separately and will not contain any open web pages. + +This API is useful for use cases where you want to create a new WebContents that shares the same render process with the original for same-origin content, while maintaining full lifecycle independence. Additionally, reusing the existing render process can help optimize memory usage and page load speed to a certain extent, as it eliminates the overhead of spawning and initializing a new render process from scratch. + #### `contents.takeHeapSnapshot(filePath)` -* `filePath` String - Path to the output file. +* `filePath` string - Path to the output file. Returns `Promise<void>` - Indicates whether the snapshot has been created successfully. @@ -1928,48 +2299,100 @@ Takes a V8 heap snapshot and saves it to `filePath`. #### `contents.getBackgroundThrottling()` -Returns `Boolean` - whether or not this WebContents will throttle animations and timers +Returns `boolean` - whether or not this WebContents will throttle animations and timers when the page becomes backgrounded. This also affects the Page Visibility API. #### `contents.setBackgroundThrottling(allowed)` -* `allowed` Boolean +<!-- +```YAML history +changes: + - pr-url: https://github.com/electron/electron/pull/38924 + description: "`WebContents.backgroundThrottling` set to false affects all `WebContents` in the host `BrowserWindow`" + breaking-changes-header: behavior-changed-webcontentsbackgroundthrottling-set-to-false-affects-all-webcontents-in-the-host-browserwindow +``` +--> + +* `allowed` boolean Controls whether or not this WebContents will throttle animations and timers when the page becomes backgrounded. This also affects the Page Visibility API. #### `contents.getType()` -Returns `String` - the type of the webContent. Can be `backgroundPage`, `window`, `browserView`, `remote`, `webview` or `offscreen`. +Returns `string` - the type of the webContent. Can be `backgroundPage`, `window`, `browserView`, `remote`, `webview` or `offscreen`. + +#### `contents.setImageAnimationPolicy(policy)` + +* `policy` string - Can be `animate`, `animateOnce` or `noAnimation`. + +Sets the image animation policy for this webContents. The policy only affects +_new_ images, existing images that are currently being animated are unaffected. +This is a known limitation in Chromium, you can force image animation to be +recalculated with `img.src = img.src` which will result in no network traffic +but will update the animation policy. + +This corresponds to the [animationPolicy][] accessibility feature in Chromium. + +[animationPolicy]: https://developer.chrome.com/docs/extensions/reference/accessibilityFeatures/#property-animationPolicy ### Instance Properties +#### `contents.ipc` _Readonly_ + +An [`IpcMain`](ipc-main.md) scoped to just IPC messages sent from this +WebContents. + +IPC messages sent with `ipcRenderer.send`, `ipcRenderer.sendSync` or +`ipcRenderer.postMessage` will be delivered in the following order: + +1. `contents.on('ipc-message')` +2. `contents.mainFrame.on(channel)` +3. `contents.ipc.on(channel)` +4. `ipcMain.on(channel)` + +Handlers registered with `invoke` will be checked in the following order. The +first one that is defined will be called, the rest will be ignored. + +1. `contents.mainFrame.handle(channel)` +2. `contents.handle(channel)` +3. `ipcMain.handle(channel)` + +A handler or event listener registered on the WebContents will receive IPC +messages sent from any frame, including child frames. In most cases, only the +main frame can send IPC messages. However, if the `nodeIntegrationInSubFrames` +option is enabled, it is possible for child frames to send IPC messages also. +In that case, handlers should check the `senderFrame` property of the IPC event +to ensure that the message is coming from the expected frame. Alternatively, +register handlers on the appropriate frame directly using the +[`WebFrameMain.ipc`](web-frame-main.md#frameipc-readonly) interface. + #### `contents.audioMuted` -A `Boolean` property that determines whether this page is muted. +A `boolean` property that determines whether this page is muted. #### `contents.userAgent` -A `String` property that determines the user agent for this web page. +A `string` property that determines the user agent for this web page. #### `contents.zoomLevel` -A `Number` property that determines the zoom level for this web contents. +A `number` property that determines the zoom level for this web contents. The original size is 0 and each increment above or below represents zooming 20% larger or smaller to default limits of 300% and 50% of original size, respectively. The formula for this is `scale := 1.2 ^ level`. #### `contents.zoomFactor` -A `Number` property that determines the zoom factor for this web contents. +A `number` property that determines the zoom factor for this web contents. The zoom factor is the zoom percent divided by 100, so 300% = 3.0. #### `contents.frameRate` An `Integer` property that sets the frame rate of the web contents to the specified number. -Only values between 1 and 60 are accepted. +Only values between 1 and 240 are accepted. -Only applicable if *offscreen rendering* is enabled. +Only applicable if _offscreen rendering_ is enabled. #### `contents.id` _Readonly_ @@ -1979,31 +2402,57 @@ A `Integer` representing the unique ID of this WebContents. Each ID is unique am A [`Session`](session.md) used by this webContents. +#### `contents.navigationHistory` _Readonly_ + +A [`NavigationHistory`](navigation-history.md) used by this webContents. + #### `contents.hostWebContents` _Readonly_ -A [`WebContents`](web-contents.md) instance that might own this `WebContents`. +A `WebContents | null` property that represents a [`WebContents`](web-contents.md) +instance that might own this `WebContents`. #### `contents.devToolsWebContents` _Readonly_ -A `WebContents | null` property that represents the of DevTools `WebContents` associated with a given `WebContents`. +A `WebContents | null` property that represents the DevTools `WebContents` associated with a given `WebContents`. -**Note:** Users should never store this object because it may become `null` -when the DevTools has been closed. +> [!NOTE] +> Users should never store this object because it may become `null` +> when the DevTools has been closed. #### `contents.debugger` _Readonly_ A [`Debugger`](debugger.md) instance for this webContents. -[keyboardevent]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent -[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter -[SCA]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm -[`postMessage`]: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage - #### `contents.backgroundThrottling` -A `Boolean` property that determines whether or not this WebContents will throttle animations and timers +<!-- +```YAML history +changes: + - pr-url: https://github.com/electron/electron/pull/38924 + description: "`WebContents.backgroundThrottling` set to false affects all `WebContents` in the host `BrowserWindow`" + breaking-changes-header: behavior-changed-webcontentsbackgroundthrottling-set-to-false-affects-all-webcontents-in-the-host-browserwindow +``` +--> + +A `boolean` property that determines whether or not this WebContents will throttle animations and timers when the page becomes backgrounded. This also affects the Page Visibility API. #### `contents.mainFrame` _Readonly_ A [`WebFrameMain`](web-frame-main.md) property that represents the top frame of the page's frame hierarchy. + +#### `contents.opener` _Readonly_ + +A [`WebFrameMain | null`](web-frame-main.md) property that represents the frame that opened this WebContents, either +with open(), or by navigating a link with a target attribute. + +#### `contents.focusedFrame` _Readonly_ + +A [`WebFrameMain | null`](web-frame-main.md) property that represents the currently focused frame in this WebContents. +Can be the top frame, an inner `<iframe>`, or `null` if nothing is focused. + +[keyboardevent]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent +[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter +[SCA]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm +[`postMessage`]: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage +[`MessagePortMain`]: message-port-main.md diff --git a/docs/api/web-frame-main.md b/docs/api/web-frame-main.md index fa3c00a28ac3e..b0f9a00d1ebb0 100644 --- a/docs/api/web-frame-main.md +++ b/docs/api/web-frame-main.md @@ -8,7 +8,7 @@ The `webFrameMain` module can be used to lookup frames across existing [`WebContents`](web-contents.md) instances. Navigation events are the common use case. -```javascript +```js const { BrowserWindow, webFrameMain } = require('electron') const win = new BrowserWindow({ width: 800, height: 1500 }) @@ -16,7 +16,7 @@ win.loadURL('https://twitter.com') win.webContents.on( 'did-frame-navigate', - (event, url, isMainFrame, frameProcessId, frameRoutingId) => { + (event, url, httpResponseCode, httpStatusText, isMainFrame, frameProcessId, frameRoutingId) => { const frame = webFrameMain.fromId(frameProcessId, frameRoutingId) if (frame) { const code = 'document.body.innerHTML = document.body.innerHTML.replaceAll("heck", "h*ck")' @@ -26,10 +26,10 @@ win.webContents.on( ) ``` -You can also access frames of existing pages by using the `webFrame` property +You can also access frames of existing pages by using the `mainFrame` property of [`WebContents`](web-contents.md). -```javascript +```js const { BrowserWindow } = require('electron') async function main () { @@ -57,24 +57,42 @@ These methods can be accessed from the `webFrameMain` module: ### `webFrameMain.fromId(processId, routingId)` -* `processId` Integer - An `Integer` representing the id of the process which owns the frame. -* `routingId` Integer - An `Integer` representing the unique frame id in the +* `processId` Integer - An `Integer` representing the internal ID of the process which owns the frame. +* `routingId` Integer - An `Integer` representing the unique frame ID in the current renderer process. Routing IDs can be retrieved from `WebFrameMain` instances (`frame.routingId`) and are also passed by frame specific `WebContents` navigation events (e.g. `did-frame-navigate`). -Returns `WebFrameMain` - A frame with the given process and routing IDs. +Returns `WebFrameMain | undefined` - A frame with the given process and routing IDs, +or `undefined` if there is no WebFrameMain associated with the given IDs. + +### `webFrameMain.fromFrameToken(processId, frameToken)` + +* `processId` Integer - An `Integer` representing the internal ID of the process which owns the frame. +* `frameToken` string - A `string` token identifying the unique frame. Can also + be retrieved in the renderer process via + [`webFrame.frameToken`](web-frame.md#webframeframetoken-readonly). + +Returns `WebFrameMain | null` - A frame with the given process and frame token, +or `null` if there is no WebFrameMain associated with the given IDs. ## Class: WebFrameMain -Process: [Main](../glossary.md#main-process) +Process: [Main](../glossary.md#main-process)<br /> +_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ + +### Instance Events + +#### Event: 'dom-ready' + +Emitted when the document is loaded. ### Instance Methods #### `frame.executeJavaScript(code[, userGesture])` -* `code` String -* `userGesture` Boolean (optional) - Default is `false`. +* `code` string +* `userGesture` boolean (optional) - Default is `false`. Returns `Promise<unknown>` - A promise that resolves with the result of the executed code or is rejected if execution throws or results in a rejected promise. @@ -89,12 +107,129 @@ this limitation. Returns `boolean` - Whether the reload was initiated successfully. Only results in `false` when the frame has no history. +#### `frame.isDestroyed()` + +Returns `boolean` - Whether the frame is destroyed. + +#### `frame.send(channel, ...args)` + +* `channel` string +* `...args` any[] + +Send an asynchronous message to the renderer process via `channel`, along with +arguments. Arguments will be serialized with the [Structured Clone Algorithm][SCA], +just like [`postMessage`][], so prototype chains will not be included. +Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an exception. + +The renderer process can handle the message by listening to `channel` with the +[`ipcRenderer`](ipc-renderer.md) module. + +#### `frame.postMessage(channel, message, [transfer])` + +* `channel` string +* `message` any +* `transfer` MessagePortMain[] (optional) + +Send a message to the renderer process, optionally transferring ownership of +zero or more [`MessagePortMain`][] objects. + +The transferred `MessagePortMain` objects will be available in the renderer +process by accessing the `ports` property of the emitted event. When they +arrive in the renderer, they will be native DOM `MessagePort` objects. + +For example: + +```js +// Main process +const win = new BrowserWindow() +const { port1, port2 } = new MessageChannelMain() +win.webContents.mainFrame.postMessage('port', { message: 'hello' }, [port1]) + +// Renderer process +ipcRenderer.on('port', (e, msg) => { + const [port] = e.ports + // ... +}) +``` + +#### `frame.collectJavaScriptCallStack()` _Experimental_ + +Returns `Promise<string> | Promise<void>` - A promise that resolves with the currently running JavaScript call +stack. If no JavaScript runs in the frame, the promise will never resolve. In cases where the call stack is +otherwise unable to be collected, it will return `undefined`. + +This can be useful to determine why the frame is unresponsive in cases where there's long-running JavaScript. +For more information, see the [proposed Crash Reporting API.](https://wicg.github.io/crash-reporting/) + +```js +const { app } = require('electron') + +app.commandLine.appendSwitch('enable-features', 'DocumentPolicyIncludeJSCallStacksInCrashReports') + +app.on('web-contents-created', (_, webContents) => { + webContents.on('unresponsive', async () => { + // Interrupt execution and collect call stack from unresponsive renderer + const callStack = await webContents.mainFrame.collectJavaScriptCallStack() + console.log('Renderer unresponsive\n', callStack) + }) +}) +``` + +#### `frame.copyVideoFrameAt(x, y)` + +* `x` Integer +* `y` Integer + +When executed on a video media element, copies the frame at (x, y) to the clipboard. + +#### `frame.saveVideoFrameAs(x, y)` + +* `x` Integer +* `y` Integer + +When executed on a video media element, shows a save dialog and saves the frame at (x, y) to disk. + ### Instance Properties +#### `frame.ipc` _Readonly_ + +An [`IpcMain`](ipc-main.md) instance scoped to the frame. + +IPC messages sent with `ipcRenderer.send`, `ipcRenderer.sendSync` or +`ipcRenderer.postMessage` will be delivered in the following order: + +1. `contents.on('ipc-message')` +2. `contents.mainFrame.on(channel)` +3. `contents.ipc.on(channel)` +4. `ipcMain.on(channel)` + +Handlers registered with `invoke` will be checked in the following order. The +first one that is defined will be called, the rest will be ignored. + +1. `contents.mainFrame.handle(channel)` +2. `contents.handle(channel)` +3. `ipcMain.handle(channel)` + +In most cases, only the main frame of a WebContents can send or receive IPC +messages. However, if the `nodeIntegrationInSubFrames` option is enabled, it is +possible for child frames to send and receive IPC messages also. The +[`WebContents.ipc`](web-contents.md#contentsipc-readonly) interface may be more +convenient when `nodeIntegrationInSubFrames` is not enabled. + #### `frame.url` _Readonly_ A `string` representing the current URL of the frame. +#### `frame.origin` _Readonly_ + +A `string` representing the current origin of the frame, serialized according +to [RFC 6454](https://www.rfc-editor.org/rfc/rfc6454). This may be different +from the URL. For instance, if the frame is a child window opened to +`about:blank`, then `frame.origin` will return the parent frame's origin, while +`frame.url` will return the empty string. Pages without a scheme/host/port +triple origin will have the serialized origin of `"null"` (that is, the string +containing the letters n, u, l, l). + #### `frame.top` _Readonly_ A `WebFrameMain | null` representing top frame in the frame hierarchy to which `frame` @@ -124,7 +259,12 @@ not used again. #### `frame.name` _Readonly_ -A `String` representing the frame name. +A `string` representing the frame name. + +#### `frame.frameToken` _Readonly_ + +A `string` which uniquely identifies the frame within its associated renderer +process. This is equivalent to [`webFrame.frameToken`](web-frame.md#webframeframetoken-readonly). #### `frame.osProcessId` _Readonly_ @@ -140,3 +280,20 @@ This is not the same as the OS process ID; to read that use `frame.osProcessId`. An `Integer` representing the unique frame id in the current renderer process. Distinct `WebFrameMain` instances that refer to the same underlying frame will have the same `routingId`. + +#### `frame.visibilityState` _Readonly_ + +A `string` representing the [visibility state](https://developer.mozilla.org/en-US/docs/Web/API/Document/visibilityState) of the frame. + +See also how the [Page Visibility API](browser-window.md#page-visibility) is affected by other Electron APIs. + +#### `frame.detached` _Readonly_ + +A `Boolean` representing whether the frame is detached from the frame tree. If a frame is accessed +while the corresponding page is running any [unload][] listeners, it may become detached as the +newly navigated page replaced it in the frame tree. + +[SCA]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm +[`postMessage`]: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage +[`MessagePortMain`]: message-port-main.md +[unload]: https://developer.mozilla.org/en-US/docs/Web/API/Window/unload_event diff --git a/docs/api/web-frame.md b/docs/api/web-frame.md index 9891c5d09ab0c..5ff93495b3543 100644 --- a/docs/api/web-frame.md +++ b/docs/api/web-frame.md @@ -4,13 +4,19 @@ Process: [Renderer](../glossary.md#renderer-process) +> [!IMPORTANT] +> If you want to call this API from a renderer process with context isolation enabled, +> place the API call in your preload script and +> [expose](../tutorial/context-isolation.md#after-context-isolation-enabled) it using the +> [`contextBridge`](context-bridge.md) API. + `webFrame` export of the Electron module is an instance of the `WebFrame` -class representing the top frame of the current `BrowserWindow`. Sub-frames can -be retrieved by certain properties and methods (e.g. `webFrame.firstChild`). +class representing the current frame. Sub-frames can be retrieved by +certain properties and methods (e.g. `webFrame.firstChild`). An example of zooming current page to 200%. -```javascript +```js const { webFrame } = require('electron') webFrame.setZoomFactor(2) @@ -31,45 +37,53 @@ The factor must be greater than 0.0. ### `webFrame.getZoomFactor()` -Returns `Number` - The current zoom factor. +Returns `number` - The current zoom factor. ### `webFrame.setZoomLevel(level)` -* `level` Number - Zoom level. +* `level` number - Zoom level. Changes the zoom level to the specified level. The original size is 0 and each increment above or below represents zooming 20% larger or smaller to default limits of 300% and 50% of original size, respectively. -> **NOTE**: The zoom policy at the Chromium level is same-origin, meaning that the +> [!NOTE] +> The zoom policy at the Chromium level is same-origin, meaning that the > zoom level for a specific domain propagates across all instances of windows with > the same domain. Differentiating the window URLs will make zoom work per-window. ### `webFrame.getZoomLevel()` -Returns `Number` - The current zoom level. +Returns `number` - The current zoom level. ### `webFrame.setVisualZoomLevelLimits(minimumLevel, maximumLevel)` -* `minimumLevel` Number -* `maximumLevel` Number +* `minimumLevel` number +* `maximumLevel` number Sets the maximum and minimum pinch-to-zoom level. -> **NOTE**: Visual zoom is disabled by default in Electron. To re-enable it, call: +> [!NOTE] +> Visual zoom is disabled by default in Electron. To re-enable it, call: > > ```js > webFrame.setVisualZoomLevelLimits(1, 3) > ``` +> [!NOTE] +> Visual zoom only applies to pinch-to-zoom behavior. Cmd+/-/0 zoom shortcuts are +> controlled by the 'zoomIn', 'zoomOut', and 'resetZoom' MenuItem roles in the application +> Menu. To disable shortcuts, manually [define the Menu](../tutorial/menus.md) and omit zoom roles +> from the definition. + ### `webFrame.setSpellCheckProvider(language, provider)` -* `language` String +* `language` string * `provider` Object * `spellCheck` Function - * `words` String[] + * `words` string[] * `callback` Function - * `misspeltWords` String[] + * `misspeltWords` string[] Sets a provider for spell checking in input fields and text areas. @@ -91,13 +105,14 @@ with an array of misspelt words when complete. An example of using [node-spellchecker][spellchecker] as provider: -```javascript +```js @ts-expect-error=[3,8] const { webFrame } = require('electron') + const spellChecker = require('spellchecker') + webFrame.setSpellCheckProvider('en-US', { spellCheck (words, callback) { setTimeout(() => { - const spellchecker = require('spellchecker') const misspelled = words.filter(x => spellchecker.isMisspelled(x)) callback(misspelled) }, 0) @@ -105,11 +120,13 @@ webFrame.setSpellCheckProvider('en-US', { }) ``` -### `webFrame.insertCSS(css)` +### `webFrame.insertCSS(css[, options])` -* `css` String - CSS source code. +* `css` string +* `options` Object (optional) + * `cssOrigin` string (optional) - Can be 'user' or 'author'. Sets the [cascade origin](https://www.w3.org/TR/css3-cascade/#cascade-origin) of the inserted stylesheet. Default is 'author'. -Returns `String` - A key for the inserted CSS that can later be used to remove +Returns `string` - A key for the inserted CSS that can later be used to remove the CSS via `webFrame.removeInsertedCSS(key)`. Injects CSS into the current web page and returns a unique key for the inserted @@ -117,21 +134,21 @@ stylesheet. ### `webFrame.removeInsertedCSS(key)` -* `key` String +* `key` string Removes the inserted CSS from the current web page. The stylesheet is identified by its key, which is returned from `webFrame.insertCSS(css)`. ### `webFrame.insertText(text)` -* `text` String +* `text` string Inserts `text` to the focused element. -### `webFrame.executeJavaScript(code[, userGesture, callback])` +### `webFrame.executeJavaScript(code[, userGesture][, callback])` -* `code` String -* `userGesture` Boolean (optional) - Default is `false`. +* `code` string +* `userGesture` boolean (optional) - Default is `false`. * `callback` Function (optional) - Called after script has been executed. Unless the frame is suspended (e.g. showing a modal alert), execution will be synchronous and the callback will be invoked before the method returns. For @@ -149,14 +166,14 @@ In the browser window some HTML APIs like `requestFullScreen` can only be invoked by a gesture from the user. Setting `userGesture` to `true` will remove this limitation. -### `webFrame.executeJavaScriptInIsolatedWorld(worldId, scripts[, userGesture, callback])` +### `webFrame.executeJavaScriptInIsolatedWorld(worldId, scripts[, userGesture][, callback])` * `worldId` Integer - The ID of the world to run the javascript in, `0` is the default main world (where content runs), `999` is the world used by Electron's `contextIsolation` feature. Accepts values in the range 1..536870911. * `scripts` [WebSource[]](structures/web-source.md) -* `userGesture` Boolean (optional) - Default is `false`. +* `userGesture` boolean (optional) - Default is `false`. * `callback` Function (optional) - Called after script has been executed. Unless the frame is suspended (e.g. showing a modal alert), execution will be synchronous and the callback will be invoked before the method returns. For @@ -176,14 +193,16 @@ dispatch errors of isolated worlds to foreign worlds. ### `webFrame.setIsolatedWorldInfo(worldId, info)` -* `worldId` Integer - The ID of the world to run the javascript in, `0` is the default world, `999` is the world used by Electrons `contextIsolation` feature. Chrome extensions reserve the range of IDs in `[1 << 20, 1 << 29)`. You can provide any integer here. +* `worldId` Integer - The ID of the world to run the javascript in, `0` is the default world, `999` is the world used by Electron's `contextIsolation` feature. Chrome extensions reserve the range of IDs in `[1 << 20, 1 << 29)`. You can provide any integer here. * `info` Object - * `securityOrigin` String (optional) - Security origin for the isolated world. - * `csp` String (optional) - Content Security Policy for the isolated world. - * `name` String (optional) - Name for isolated world. Useful in devtools. + * `securityOrigin` string (optional) - Security origin for the isolated world. + * `csp` string (optional) - Content Security Policy for the isolated world. + * `name` string (optional) - Name for isolated world. Useful in DevTools. Set the security origin, content security policy and name of the isolated world. -Note: If the `csp` is specified, then the `securityOrigin` also has to be specified. + +> [!NOTE] +> If the `csp` is specified, then the `securityOrigin` also has to be specified. ### `webFrame.getResourceUsage()` @@ -199,14 +218,17 @@ Returns `Object`: Returns an object describing usage information of Blink's internal memory caches. -```javascript +```js const { webFrame } = require('electron') + console.log(webFrame.getResourceUsage()) ``` This will generate: -```javascript +<!-- eslint-skip --> + +```js { images: { count: 22, @@ -235,41 +257,52 @@ and intend to stay there). ### `webFrame.getFrameForSelector(selector)` -* `selector` String - CSS selector for a frame element. +* `selector` string - CSS selector for a frame element. -Returns `WebFrame` - The frame element in `webFrame's` document selected by +Returns `WebFrame | null` - The frame element in `webFrame's` document selected by `selector`, `null` would be returned if `selector` does not select a frame or if the frame is not in the current renderer process. ### `webFrame.findFrameByName(name)` -* `name` String +* `name` string -Returns `WebFrame` - A child of `webFrame` with the supplied `name`, `null` +Returns `WebFrame | null` - A child of `webFrame` with the supplied `name`, `null` would be returned if there's no such frame or if the frame is not in the current renderer process. -### `webFrame.findFrameByRoutingId(routingId)` +### `webFrame.findFrameByRoutingId(routingId)` _Deprecated_ * `routingId` Integer - An `Integer` representing the unique frame id in the current renderer process. Routing IDs can be retrieved from `WebFrame` instances (`webFrame.routingId`) and are also passed by frame specific `WebContents` navigation events (e.g. `did-frame-navigate`) -Returns `WebFrame` - that has the supplied `routingId`, `null` if not found. +Returns `WebFrame | null` - that has the supplied `routingId`, `null` if not found. + +**Deprecated:** Use the new `webFrame.findFrameByToken` API. + +### `webFrame.findFrameByToken(frameToken)` + +* `frameToken` string - A `string` representing the unique frame id in the + current renderer process. Frame tokens can be retrieved from `WebFrame` + instances (`webFrame.frameToken`) and can also be retrieved from + `WebFrameMain` instances using `webFrameMain.frameToken`. + +Returns `WebFrame | null` - that has the supplied `frameToken`, `null` if not found. ### `webFrame.isWordMisspelled(word)` -* `word` String - The word to be spellchecked. +* `word` string - The word to be spellchecked. -Returns `Boolean` - True if the word is misspelled according to the built in +Returns `boolean` - True if the word is misspelled according to the built in spellchecker, false otherwise. If no dictionary is loaded, always return false. ### `webFrame.getWordSuggestions(word)` -* `word` String - The misspelled word. +* `word` string - The misspelled word. -Returns `String[]` - A list of suggested words for a given word. If the word +Returns `string[]` - A list of suggested words for a given word. If the word is spelled correctly, the result will be empty. ## Properties @@ -302,8 +335,16 @@ A `WebFrame | null` representing next sibling frame, the property would be `null `webFrame` is the last frame in its parent or if the next sibling is not in the current renderer process. -### `webFrame.routingId` _Readonly_ +### `webFrame.routingId` _Readonly_ _Deprecated_ An `Integer` representing the unique frame id in the current renderer process. Distinct WebFrame instances that refer to the same underlying frame will have the same `routingId`. + +**Deprecated:** Use the new `webFrame.frameToken` API. + +### `webFrame.frameToken` _Readonly_ + +A `string` representing the unique frame token in the current renderer process. +Distinct WebFrame instances that refer to the same underlying frame will have +the same `frameToken`. diff --git a/docs/api/web-request.md b/docs/api/web-request.md index 1370f0b47a5a6..c8ee3cd1e4bf8 100644 --- a/docs/api/web-request.md +++ b/docs/api/web-request.md @@ -2,7 +2,8 @@ > Intercept and modify the contents of a request at various stages of its lifetime. -Process: [Main](../glossary.md#main-process) +Process: [Main](../glossary.md#main-process)<br /> +_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ Instances of the `WebRequest` class are accessed by using the `webRequest` property of a `Session`. @@ -22,12 +23,12 @@ called with a `response` object when `listener` has done its work. An example of adding `User-Agent` header for requests: -```javascript +```js const { session } = require('electron') // Modify the user agent for all requests to the following urls. const filter = { - urls: ['https://*.github.com/*', '*://electron.github.io'] + urls: ['https://*.github.com/*', '*://electron.github.io/*'] } session.defaultSession.webRequest.onBeforeSendHeaders(filter, (details, callback) => { @@ -42,23 +43,24 @@ The following methods are available on instances of `WebRequest`: #### `webRequest.onBeforeRequest([filter, ]listener)` -* `filter` Object (optional) - * `urls` String[] - Array of URL patterns that will be used to filter out the - requests that do not match the URL patterns. +* `filter` [WebRequestFilter](structures/web-request-filter.md) (optional) * `listener` Function | null * `details` Object * `id` Integer - * `url` String - * `method` String + * `url` string + * `method` string * `webContentsId` Integer (optional) - * `resourceType` String - * `referrer` String + * `webContents` WebContents (optional) + * `frame` WebFrameMain | null (optional) - Requesting frame. + May be `null` if accessed after the frame has either navigated or been destroyed. + * `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`. + * `referrer` string * `timestamp` Double * `uploadData` [UploadData[]](structures/upload-data.md) * `callback` Function * `response` Object - * `cancel` Boolean (optional) - * `redirectURL` String (optional) - The original request is prevented from + * `cancel` boolean (optional) + * `redirectURL` string (optional) - The original request is prevented from being sent or completed and is instead redirected to the given URL. The `listener` will be called with `listener(details, callback)` when a request @@ -71,6 +73,7 @@ The `callback` has to be called with an `response` object. Some examples of valid `urls`: ```js +'<all_urls>' 'http://foo:1234/' 'http://foo.com/' 'http://foo:1234/bar' @@ -85,23 +88,25 @@ Some examples of valid `urls`: #### `webRequest.onBeforeSendHeaders([filter, ]listener)` -* `filter` Object (optional) - * `urls` String[] - Array of URL patterns that will be used to filter out the - requests that do not match the URL patterns. +* `filter` [WebRequestFilter](structures/web-request-filter.md) (optional) * `listener` Function | null * `details` Object * `id` Integer - * `url` String - * `method` String + * `url` string + * `method` string * `webContentsId` Integer (optional) - * `resourceType` String - * `referrer` String + * `webContents` WebContents (optional) + * `frame` WebFrameMain | null (optional) - Requesting frame. + May be `null` if accessed after the frame has either navigated or been destroyed. + * `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`. + * `referrer` string * `timestamp` Double - * `requestHeaders` Record<string, string> + * `uploadData` [UploadData[]](structures/upload-data.md) (optional) + * `requestHeaders` Record\<string, string\> * `callback` Function * `beforeSendResponse` Object - * `cancel` Boolean (optional) - * `requestHeaders` Record<string, string | string[]> (optional) - When provided, request will be made + * `cancel` boolean (optional) + * `requestHeaders` Record\<string, string | string[]\> (optional) - When provided, request will be made with these headers. The `listener` will be called with `listener(details, callback)` before sending @@ -112,19 +117,20 @@ The `callback` has to be called with a `response` object. #### `webRequest.onSendHeaders([filter, ]listener)` -* `filter` Object (optional) - * `urls` String[] - Array of URL patterns that will be used to filter out the - requests that do not match the URL patterns. +* `filter` [WebRequestFilter](structures/web-request-filter.md) (optional) * `listener` Function | null * `details` Object * `id` Integer - * `url` String - * `method` String + * `url` string + * `method` string * `webContentsId` Integer (optional) - * `resourceType` String - * `referrer` String + * `webContents` WebContents (optional) + * `frame` WebFrameMain | null (optional) - Requesting frame. + May be `null` if accessed after the frame has either navigated or been destroyed. + * `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`. + * `referrer` string * `timestamp` Double - * `requestHeaders` Record<string, string> + * `requestHeaders` Record\<string, string\> The `listener` will be called with `listener(details)` just before a request is going to be sent to the server, modifications of previous `onBeforeSendHeaders` @@ -132,28 +138,28 @@ response are visible by the time this listener is fired. #### `webRequest.onHeadersReceived([filter, ]listener)` -* `filter` Object (optional) - * `urls` String[] - Array of URL patterns that will be used to filter out the - requests that do not match the URL patterns. +* `filter` [WebRequestFilter](structures/web-request-filter.md) (optional) * `listener` Function | null * `details` Object * `id` Integer - * `url` String - * `method` String + * `url` string + * `method` string * `webContentsId` Integer (optional) - * `resourceType` String - * `referrer` String + * `webContents` WebContents (optional) + * `frame` WebFrameMain | null (optional) - Requesting frame. + May be `null` if accessed after the frame has either navigated or been destroyed. + * `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`. + * `referrer` string * `timestamp` Double - * `statusLine` String + * `statusLine` string * `statusCode` Integer - * `requestHeaders` Record<string, string> - * `responseHeaders` Record<string, string[]> (optional) + * `responseHeaders` Record\<string, string[]\> (optional) * `callback` Function * `headersReceivedResponse` Object - * `cancel` Boolean (optional) - * `responseHeaders` Record<string, string | string[]> (optional) - When provided, the server is assumed + * `cancel` boolean (optional) + * `responseHeaders` Record\<string, string | string[]\> (optional) - When provided, the server is assumed to have responded with these headers. - * `statusLine` String (optional) - Should be provided when overriding + * `statusLine` string (optional) - Should be provided when overriding `responseHeaders` to change header status otherwise original response header's status will be used. @@ -164,23 +170,24 @@ The `callback` has to be called with a `response` object. #### `webRequest.onResponseStarted([filter, ]listener)` -* `filter` Object (optional) - * `urls` String[] - Array of URL patterns that will be used to filter out the - requests that do not match the URL patterns. +* `filter` [WebRequestFilter](structures/web-request-filter.md) (optional) * `listener` Function | null * `details` Object * `id` Integer - * `url` String - * `method` String + * `url` string + * `method` string * `webContentsId` Integer (optional) - * `resourceType` String - * `referrer` String + * `webContents` WebContents (optional) + * `frame` WebFrameMain | null (optional) - Requesting frame. + May be `null` if accessed after the frame has either navigated or been destroyed. + * `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`. + * `referrer` string * `timestamp` Double - * `responseHeaders` Record<string, string[]> (optional) - * `fromCache` Boolean - Indicates whether the response was fetched from disk + * `responseHeaders` Record\<string, string[]\> (optional) + * `fromCache` boolean - Indicates whether the response was fetched from disk cache. * `statusCode` Integer - * `statusLine` String + * `statusLine` string The `listener` will be called with `listener(details)` when first byte of the response body is received. For HTTP requests, this means that the status line @@ -188,67 +195,70 @@ and response headers are available. #### `webRequest.onBeforeRedirect([filter, ]listener)` -* `filter` Object (optional) - * `urls` String[] - Array of URL patterns that will be used to filter out the - requests that do not match the URL patterns. +* `filter` [WebRequestFilter](structures/web-request-filter.md) (optional) * `listener` Function | null * `details` Object * `id` Integer - * `url` String - * `method` String + * `url` string + * `method` string * `webContentsId` Integer (optional) - * `resourceType` String - * `referrer` String + * `webContents` WebContents (optional) + * `frame` WebFrameMain | null (optional) - Requesting frame. + May be `null` if accessed after the frame has either navigated or been destroyed. + * `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`. + * `referrer` string * `timestamp` Double - * `redirectURL` String + * `redirectURL` string * `statusCode` Integer - * `statusLine` String - * `ip` String (optional) - The server IP address that the request was + * `statusLine` string + * `ip` string (optional) - The server IP address that the request was actually sent to. - * `fromCache` Boolean - * `responseHeaders` Record<string, string[]> (optional) + * `fromCache` boolean + * `responseHeaders` Record\<string, string[]\> (optional) The `listener` will be called with `listener(details)` when a server initiated redirect is about to occur. #### `webRequest.onCompleted([filter, ]listener)` -* `filter` Object (optional) - * `urls` String[] - Array of URL patterns that will be used to filter out the - requests that do not match the URL patterns. +* `filter` [WebRequestFilter](structures/web-request-filter.md) (optional) * `listener` Function | null * `details` Object * `id` Integer - * `url` String - * `method` String + * `url` string + * `method` string * `webContentsId` Integer (optional) - * `resourceType` String - * `referrer` String + * `webContents` WebContents (optional) + * `frame` WebFrameMain | null (optional) - Requesting frame. + May be `null` if accessed after the frame has either navigated or been destroyed. + * `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`. + * `referrer` string * `timestamp` Double - * `responseHeaders` Record<string, string[]> (optional) - * `fromCache` Boolean + * `responseHeaders` Record\<string, string[]\> (optional) + * `fromCache` boolean * `statusCode` Integer - * `statusLine` String - * `error` String + * `statusLine` string + * `error` string The `listener` will be called with `listener(details)` when a request is completed. #### `webRequest.onErrorOccurred([filter, ]listener)` -* `filter` Object (optional) - * `urls` String[] - Array of URL patterns that will be used to filter out the - requests that do not match the URL patterns. +* `filter` [WebRequestFilter](structures/web-request-filter.md) (optional) * `listener` Function | null * `details` Object * `id` Integer - * `url` String - * `method` String + * `url` string + * `method` string * `webContentsId` Integer (optional) - * `resourceType` String - * `referrer` String + * `webContents` WebContents (optional) + * `frame` WebFrameMain | null (optional) - Requesting frame. + May be `null` if accessed after the frame has either navigated or been destroyed. + * `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`. + * `referrer` string * `timestamp` Double - * `fromCache` Boolean - * `error` String - The error description. + * `fromCache` boolean + * `error` string - The error description. The `listener` will be called with `listener(details)` when an error occurs. diff --git a/docs/api/web-utils.md b/docs/api/web-utils.md new file mode 100644 index 0000000000000..f1d04fcc9887b --- /dev/null +++ b/docs/api/web-utils.md @@ -0,0 +1,49 @@ +# webUtils + +> A utility layer to interact with Web API objects (Files, Blobs, etc.) + +Process: [Renderer](../glossary.md#renderer-process) + +> [!IMPORTANT] +> If you want to call this API from a renderer process with context isolation enabled, +> place the API call in your preload script and +> [expose](../tutorial/context-isolation.md#after-context-isolation-enabled) it using the +> [`contextBridge`](context-bridge.md) API. + +## Methods + +The `webUtils` module has the following methods: + +### `webUtils.getPathForFile(file)` + +* `file` File - A web [File](https://developer.mozilla.org/en-US/docs/Web/API/File) object. + +Returns `string` - The file system path that this `File` object points to. In the case where the object passed in is not a `File` object an exception is thrown. In the case where the File object passed in was constructed in JS and is not backed by a file on disk an empty string is returned. + +This method superseded the previous augmentation to the `File` object with the `path` property. An example is included below. + +```js @ts-nocheck +// Before (renderer) +const oldPath = document.querySelector('input[type=file]').files[0].path +``` + +```js @ts-nocheck +// After + +// Renderer: + +const file = document.querySelector('input[type=file]').files[0] +electronApi.doSomethingWithFile(file) + +// Preload script: + +const { contextBridge, webUtils } = require('electron') + +contextBridge.exposeInMainWorld('electronApi', { + doSomethingWithFile (file) { + const path = webUtils.getPathForFile(file) + // Do something with the path, e.g., send it over IPC to the main process. + // It's best not to expose the full file path to the web content if possible. + } +}) +``` diff --git a/docs/api/webview-tag.md b/docs/api/webview-tag.md index 6a904828ac921..409cc71e9e4ab 100644 --- a/docs/api/webview-tag.md +++ b/docs/api/webview-tag.md @@ -4,9 +4,10 @@ Electron's `webview` tag is based on [Chromium's `webview`][chrome-webview], which is undergoing dramatic architectural changes. This impacts the stability of `webviews`, -including rendering, navigation, and event routing. We currently recommend to not -use the `webview` tag and to consider alternatives, like `iframe`, Electron's `BrowserView`, -or an architecture that avoids embedded content altogether. +including rendering, navigation, and event routing. We currently recommend to +not use the `webview` tag and to consider alternatives, like `iframe`, a +[`WebContentsView`](web-contents-view.md), or an architecture that avoids +embedded content altogether. ## Enabling @@ -18,7 +19,8 @@ more information see the [BrowserWindow constructor docs](browser-window.md). > Display external web content in an isolated frame and process. -Process: [Renderer](../glossary.md#renderer-process) +Process: [Renderer](../glossary.md#renderer-process)<br /> +_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ Use the `webview` tag to embed 'guest' content (such as web pages) in your Electron app. The guest content is contained within the `webview` container. @@ -28,8 +30,10 @@ rendered. Unlike an `iframe`, the `webview` runs in a separate process than your app. It doesn't have the same permissions as your web page and all interactions between your app and embedded content will be asynchronous. This keeps your app -safe from the embedded content. **Note:** Most methods called on the -webview from the host page require a synchronous call to the main process. +safe from the embedded content. + +> [!NOTE] +> Most methods called on the webview from the host page require a synchronous call to the main process. ## Example @@ -100,7 +104,7 @@ The `webview` tag has the following attributes: <webview src="https://www.github.com/"></webview> ``` -A `String` representing the visible URL. Writing to this attribute initiates top-level +A `string` representing the visible URL. Writing to this attribute initiates top-level navigation. Assigning `src` its own value will reload the current page. @@ -111,10 +115,10 @@ The `src` attribute can also accept data URLs, such as ### `nodeintegration` ```html -<webview src="http://www.google.com/" nodeintegration></webview> +<webview src="https://www.google.com/" nodeintegration></webview> ``` -A `Boolean`. When this attribute is present the guest page in `webview` will have node +A `boolean`. When this attribute is present the guest page in `webview` will have node integration and can use node APIs like `require` and `process` to access low level system resources. Node integration is disabled by default in the guest page. @@ -122,56 +126,48 @@ page. ### `nodeintegrationinsubframes` ```html -<webview src="http://www.google.com/" nodeintegrationinsubframes></webview> +<webview src="https://www.google.com/" nodeintegrationinsubframes></webview> ``` -A `Boolean` for the experimental option for enabling NodeJS support in sub-frames such as iframes +A `boolean` for the experimental option for enabling NodeJS support in sub-frames such as iframes inside the `webview`. All your preloads will load for every iframe, you can use `process.isMainFrame` to determine if you are in the main frame or not. This option is disabled by default in the guest page. -### `enableremotemodule` - -```html -<webview src="http://www.google.com/" enableremotemodule="false"></webview> -``` - -A `Boolean`. When this attribute is `false` the guest page in `webview` will not have access -to the [`remote`](remote.md) module. The remote module is unavailable by default. - ### `plugins` ```html <webview src="https://www.github.com/" plugins></webview> ``` -A `Boolean`. When this attribute is present the guest page in `webview` will be able to use +A `boolean`. When this attribute is present the guest page in `webview` will be able to use browser plugins. Plugins are disabled by default. ### `preload` ```html +<!-- from a file --> <webview src="https://www.github.com/" preload="./test.js"></webview> +<!-- or if you want to load from an asar archive --> +<webview src="https://www.github.com/" preload="./app.asar/test.js"></webview> ``` -A `String` that specifies a script that will be loaded before other scripts run in the guest -page. The protocol of script's URL must be either `file:` or `asar:`, because it -will be loaded by `require` in guest page under the hood. +A `string` that specifies a script that will be loaded before other scripts run in the guest +page. The protocol of script's URL must be `file:` (even when using `asar:` archives) because +it will be loaded by Node's `require` under the hood, which treats `asar:` archives as virtual +directories. When the guest page doesn't have node integration this script will still have access to all Node APIs, but global objects injected by Node will be deleted after this script has finished executing. -**Note:** This option will appear as `preloadURL` (not `preload`) in -the `webPreferences` specified to the `will-attach-webview` event. - ### `httpreferrer` ```html -<webview src="https://www.github.com/" httpreferrer="http://cheng.guru"></webview> +<webview src="https://www.github.com/" httpreferrer="https://example.com/"></webview> ``` -A `String` that sets the referrer URL for the guest page. +A `string` that sets the referrer URL for the guest page. ### `useragent` @@ -179,7 +175,7 @@ A `String` that sets the referrer URL for the guest page. <webview src="https://www.github.com/" useragent="Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; AS; rv:11.0) like Gecko"></webview> ``` -A `String` that sets the user agent for the guest page before the page is navigated to. Once the +A `string` that sets the user agent for the guest page before the page is navigated to. Once the page is loaded, use the `setUserAgent` method to change the user agent. ### `disablewebsecurity` @@ -188,9 +184,11 @@ page is loaded, use the `setUserAgent` method to change the user agent. <webview src="https://www.github.com/" disablewebsecurity></webview> ``` -A `Boolean`. When this attribute is present the guest page will have web security disabled. +A `boolean`. When this attribute is present the guest page will have web security disabled. Web security is enabled by default. +This value can only be modified before the first navigation. + ### `partition` ```html @@ -198,7 +196,7 @@ Web security is enabled by default. <webview src="https://electronjs.org" partition="electron"></webview> ``` -A `String` that sets the session used by the page. If `partition` starts with `persist:`, the +A `string` that sets the session used by the page. If `partition` starts with `persist:`, the page will use a persistent session available to all pages in the app with the same `partition`. if there is no `persist:` prefix, the page will use an in-memory session. By assigning the same `partition`, multiple pages can share @@ -215,7 +213,7 @@ value will fail with a DOM exception. <webview src="https://www.github.com/" allowpopups></webview> ``` -A `Boolean`. When this attribute is present the guest page will be allowed to open new +A `boolean`. When this attribute is present the guest page will be allowed to open new windows. Popups are disabled by default. ### `webpreferences` @@ -224,7 +222,7 @@ windows. Popups are disabled by default. <webview src="https://github.com" webpreferences="allowRunningInsecureContent, javascript=no"></webview> ``` -A `String` which is a comma separated list of strings which specifies the web preferences to be set on the webview. +A `string` which is a comma separated list of strings which specifies the web preferences to be set on the webview. The full list of supported preference strings can be found in [BrowserWindow](browser-window.md#new-browserwindowoptions). The string follows the same format as the features string in `window.open`. @@ -238,7 +236,7 @@ Special values `yes` and `1` are interpreted as `true`, while `no` and `0` are i <webview src="https://www.github.com/" enableblinkfeatures="PreciseMemoryInfo, CSSVariables"></webview> ``` -A `String` which is a list of strings which specifies the blink features to be enabled separated by `,`. +A `string` which is a list of strings which specifies the blink features to be enabled separated by `,`. The full list of supported feature strings can be found in the [RuntimeEnabledFeatures.json5][runtime-enabled-features] file. @@ -248,7 +246,7 @@ The full list of supported feature strings can be found in the <webview src="https://www.github.com/" disableblinkfeatures="PreciseMemoryInfo, CSSVariables"></webview> ``` -A `String` which is a list of strings which specifies the blink features to be disabled separated by `,`. +A `string` which is a list of strings which specifies the blink features to be disabled separated by `,`. The full list of supported feature strings can be found in the [RuntimeEnabledFeatures.json5][runtime-enabled-features] file. @@ -256,11 +254,12 @@ The full list of supported feature strings can be found in the The `webview` tag has the following methods: -**Note:** The webview element must be loaded before using the methods. +> [!NOTE] +> The webview element must be loaded before using the methods. **Example** -```javascript +```js @ts-expect-error=[3] const webview = document.querySelector('webview') webview.addEventListener('dom-ready', () => { webview.openDevTools() @@ -271,11 +270,11 @@ webview.addEventListener('dom-ready', () => { * `url` URL * `options` Object (optional) - * `httpReferrer` (String | [Referrer](structures/referrer.md)) (optional) - An HTTP Referrer url. - * `userAgent` String (optional) - A user agent originating the request. - * `extraHeaders` String (optional) - Extra headers separated by "\n" - * `postData` ([UploadRawData[]](structures/upload-raw-data.md) | [UploadFile[]](structures/upload-file.md)) (optional) - * `baseURLForDataURL` String (optional) - Base url (with trailing path separator) for files to be loaded by the data url. This is needed only if the specified `url` is a data url and needs to load other files. + * `httpReferrer` (string | [Referrer](structures/referrer.md)) (optional) - An HTTP Referrer url. + * `userAgent` string (optional) - A user agent originating the request. + * `extraHeaders` string (optional) - Extra headers separated by "\n" + * `postData` ([UploadRawData](structures/upload-raw-data.md) | [UploadFile](structures/upload-file.md))[] (optional) + * `baseURLForDataURL` string (optional) - Base url (with trailing path separator) for files to be loaded by the data url. This is needed only if the specified `url` is a data url and needs to load other files. Returns `Promise<void>` - The promise will resolve when the page has finished loading (see [`did-finish-load`](webview-tag.md#event-did-finish-load)), and rejects @@ -285,32 +284,34 @@ if the page fails to load (see Loads the `url` in the webview, the `url` must contain the protocol prefix, e.g. the `http://` or `file://`. -### `<webview>.downloadURL(url)` +### `<webview>.downloadURL(url[, options])` -* `url` String +* `url` string +* `options` Object (optional) + * `headers` Record\<string, string\> (optional) - HTTP request headers. Initiates a download of the resource at `url` without navigating. ### `<webview>.getURL()` -Returns `String` - The URL of guest page. +Returns `string` - The URL of guest page. ### `<webview>.getTitle()` -Returns `String` - The title of guest page. +Returns `string` - The title of guest page. ### `<webview>.isLoading()` -Returns `Boolean` - Whether guest page is still loading resources. +Returns `boolean` - Whether guest page is still loading resources. ### `<webview>.isLoadingMainFrame()` -Returns `Boolean` - Whether the main frame (and not just iframes or frames within it) is +Returns `boolean` - Whether the main frame (and not just iframes or frames within it) is still loading. ### `<webview>.isWaitingForResponse()` -Returns `Boolean` - Whether the guest page is waiting for a first-response for the +Returns `boolean` - Whether the guest page is waiting for a first-response for the main resource of the page. ### `<webview>.stop()` @@ -327,17 +328,17 @@ Reloads the guest page and ignores cache. ### `<webview>.canGoBack()` -Returns `Boolean` - Whether the guest page can go back. +Returns `boolean` - Whether the guest page can go back. ### `<webview>.canGoForward()` -Returns `Boolean` - Whether the guest page can go forward. +Returns `boolean` - Whether the guest page can go forward. ### `<webview>.canGoToOffset(offset)` * `offset` Integer -Returns `Boolean` - Whether the guest page can go to `offset`. +Returns `boolean` - Whether the guest page can go to `offset`. ### `<webview>.clearHistory()` @@ -365,23 +366,23 @@ Navigates to the specified offset from the "current entry". ### `<webview>.isCrashed()` -Returns `Boolean` - Whether the renderer process has crashed. +Returns `boolean` - Whether the renderer process has crashed. ### `<webview>.setUserAgent(userAgent)` -* `userAgent` String +* `userAgent` string Overrides the user agent for the guest page. ### `<webview>.getUserAgent()` -Returns `String` - The user agent for guest page. +Returns `string` - The user agent for guest page. ### `<webview>.insertCSS(css)` -* `css` String +* `css` string -Returns `Promise<String>` - A promise that resolves with a key for the inserted +Returns `Promise<string>` - A promise that resolves with a key for the inserted CSS that can later be used to remove the CSS via `<webview>.removeInsertedCSS(key)`. @@ -390,7 +391,7 @@ stylesheet. ### `<webview>.removeInsertedCSS(key)` -* `key` String +* `key` string Returns `Promise<void>` - Resolves if the removal was successful. @@ -399,8 +400,8 @@ by its key, which is returned from `<webview>.insertCSS(css)`. ### `<webview>.executeJavaScript(code[, userGesture])` -* `code` String -* `userGesture` Boolean (optional) - Default `false`. +* `code` string +* `userGesture` boolean (optional) - Default `false`. Returns `Promise<any>` - A promise that resolves with the result of the executed code or is rejected if the result of the code is a rejected promise. @@ -419,11 +420,11 @@ Closes the DevTools window of guest page. ### `<webview>.isDevToolsOpened()` -Returns `Boolean` - Whether guest page has a DevTools window attached. +Returns `boolean` - Whether guest page has a DevTools window attached. ### `<webview>.isDevToolsFocused()` -Returns `Boolean` - Whether DevTools window of guest page is focused. +Returns `boolean` - Whether DevTools window of guest page is focused. ### `<webview>.inspectElement(x, y)` @@ -442,17 +443,17 @@ Opens the DevTools for the service worker context present in the guest page. ### `<webview>.setAudioMuted(muted)` -* `muted` Boolean +* `muted` boolean Set guest page muted. ### `<webview>.isAudioMuted()` -Returns `Boolean` - Whether guest page has been muted. +Returns `boolean` - Whether guest page has been muted. ### `<webview>.isCurrentlyAudible()` -Returns `Boolean` - Whether audio is currently playing. +Returns `boolean` - Whether audio is currently playing. ### `<webview>.undo()` @@ -470,6 +471,10 @@ Executes editing command `cut` in page. Executes editing command `copy` in page. +#### `<webview>.centerSelection()` + +Centers the current text selection in page. + ### `<webview>.paste()` Executes editing command `paste` in page. @@ -490,21 +495,40 @@ Executes editing command `selectAll` in page. Executes editing command `unselect` in page. +#### `<webview>.scrollToTop()` + +Scrolls to the top of the current `<webview>`. + +#### `<webview>.scrollToBottom()` + +Scrolls to the bottom of the current `<webview>`. + +#### `<webview>.adjustSelection(options)` + +* `options` Object + * `start` Number (optional) - Amount to shift the start index of the current selection. + * `end` Number (optional) - Amount to shift the end index of the current selection. + +Adjusts the current text selection starting and ending points in the focused frame by the given amounts. A negative amount moves the selection towards the beginning of the document, and a positive amount moves the selection towards the end of the document. + +See [`webContents.adjustSelection`](web-contents.md#contentsadjustselectionoptions) for +examples. + ### `<webview>.replace(text)` -* `text` String +* `text` string Executes editing command `replace` in page. ### `<webview>.replaceMisspelling(text)` -* `text` String +* `text` string Executes editing command `replaceMisspelling` in page. ### `<webview>.insertText(text)` -* `text` String +* `text` string Returns `Promise<void>` @@ -512,12 +536,11 @@ Inserts `text` to the focused element. ### `<webview>.findInPage(text[, options])` -* `text` String - Content to be searched, must not be empty. +* `text` string - Content to be searched, must not be empty. * `options` Object (optional) - * `forward` Boolean (optional) - Whether to search forward or backward, defaults to `true`. - * `findNext` Boolean (optional) - Whether the operation is first request or a follow up, - defaults to `false`. - * `matchCase` Boolean (optional) - Whether search should be case-sensitive, + * `forward` boolean (optional) - Whether to search forward or backward, defaults to `true`. + * `findNext` boolean (optional) - Whether to begin a new text finding session with this request. Should be `true` for initial requests, and `false` for follow-up requests. Defaults to `false`. + * `matchCase` boolean (optional) - Whether search should be case-sensitive, defaults to `false`. Returns `Integer` - The request id used for the request. @@ -527,7 +550,7 @@ can be obtained by subscribing to [`found-in-page`](webview-tag.md#event-found-i ### `<webview>.stopFindInPage(action)` -* `action` String - Specifies the action to take place when ending +* `action` string - Specifies the action to take place when ending [`<webview>.findInPage`](#webviewfindinpagetext-options) request. * `clearSelection` - Clear the selection. * `keepSelection` - Translate the selection into a normal selection. @@ -538,33 +561,34 @@ Stops any `findInPage` request for the `webview` with the provided `action`. ### `<webview>.print([options])` * `options` Object (optional) - * `silent` Boolean (optional) - Don't ask user for print settings. Default is `false`. - * `printBackground` Boolean (optional) - Prints the background color and image of + * `silent` boolean (optional) - Don't ask user for print settings. Default is `false`. + * `printBackground` boolean (optional) - Prints the background color and image of the web page. Default is `false`. - * `deviceName` String (optional) - Set the printer device name to use. Must be the system-defined name and not the 'friendly' name, e.g 'Brother_QL_820NWB' and not 'Brother QL-820NWB'. - * `color` Boolean (optional) - Set whether the printed web page will be in color or grayscale. Default is `true`. + * `deviceName` string (optional) - Set the printer device name to use. Must be the system-defined name and not the 'friendly' name, e.g 'Brother_QL_820NWB' and not 'Brother QL-820NWB'. + * `color` boolean (optional) - Set whether the printed web page will be in color or grayscale. Default is `true`. * `margins` Object (optional) - * `marginType` String (optional) - Can be `default`, `none`, `printableArea`, or `custom`. If `custom` is chosen, you will also need to specify `top`, `bottom`, `left`, and `right`. - * `top` Number (optional) - The top margin of the printed web page, in pixels. - * `bottom` Number (optional) - The bottom margin of the printed web page, in pixels. - * `left` Number (optional) - The left margin of the printed web page, in pixels. - * `right` Number (optional) - The right margin of the printed web page, in pixels. - * `landscape` Boolean (optional) - Whether the web page should be printed in landscape mode. Default is `false`. - * `scaleFactor` Number (optional) - The scale factor of the web page. - * `pagesPerSheet` Number (optional) - The number of pages to print per page sheet. - * `collate` Boolean (optional) - Whether the web page should be collated. - * `copies` Number (optional) - The number of copies of the web page to print. + * `marginType` string (optional) - Can be `default`, `none`, `printableArea`, or `custom`. If `custom` is chosen, you will also need to specify `top`, `bottom`, `left`, and `right`. + * `top` number (optional) - The top margin of the printed web page, in pixels. + * `bottom` number (optional) - The bottom margin of the printed web page, in pixels. + * `left` number (optional) - The left margin of the printed web page, in pixels. + * `right` number (optional) - The right margin of the printed web page, in pixels. + * `landscape` boolean (optional) - Whether the web page should be printed in landscape mode. Default is `false`. + * `scaleFactor` number (optional) - The scale factor of the web page. + * `pagesPerSheet` number (optional) - The number of pages to print per page sheet. + * `collate` boolean (optional) - Whether the web page should be collated. + * `copies` number (optional) - The number of copies of the web page to print. * `pageRanges` Object[] (optional) - The page range to print. - * `from` Number - Index of the first page to print (0-based). - * `to` Number - Index of the last page to print (inclusive) (0-based). - * `duplexMode` String (optional) - Set the duplex mode of the printed web page. Can be `simplex`, `shortEdge`, or `longEdge`. - * `dpi` Record<string, number> (optional) - * `horizontal` Number (optional) - The horizontal dpi. - * `vertical` Number (optional) - The vertical dpi. - * `header` String (optional) - String to be printed as page header. - * `footer` String (optional) - String to be printed as page footer. - * `pageSize` String | Size (optional) - Specify page size of the printed document. Can be `A3`, - `A4`, `A5`, `Legal`, `Letter`, `Tabloid` or an Object containing `height`. + * `from` number - Index of the first page to print (0-based). + * `to` number - Index of the last page to print (inclusive) (0-based). + * `duplexMode` string (optional) - Set the duplex mode of the printed web page. Can be `simplex`, `shortEdge`, or `longEdge`. + * `dpi` Record\<string, number\> (optional) + * `horizontal` number (optional) - The horizontal dpi. + * `vertical` number (optional) - The vertical dpi. + * `header` string (optional) - string to be printed as page header. + * `footer` string (optional) - string to be printed as page footer. + * `pageSize` string | Size (optional) - Specify page size of the printed document. Can be `A3`, + `A4`, `A5`, `Legal`, `Letter`, `Tabloid` or an Object containing `height` in microns. + * `usePrinterDefaultPageSize` boolean (optional) - Whether to use the system's default page size. Default is `false`. Cannot be combined with `pageSize`. When `deviceName` is provided, uses the default page size of that specific printer. When `deviceName` is not provided, uses the default page size of the system's default printer. If the printer's default page size cannot be retrieved, falls back to A4 (210mm x 297mm). Returns `Promise<void>` @@ -573,21 +597,23 @@ Prints `webview`'s web page. Same as `webContents.print([options])`. ### `<webview>.printToPDF(options)` * `options` Object - * `headerFooter` Record<string, string> (optional) - the header and footer for the PDF. - * `title` String - The title for the PDF header. - * `url` String - the url for the PDF footer. - * `landscape` Boolean (optional) - `true` for landscape, `false` for portrait. - * `marginsType` Integer (optional) - Specifies the type of margins to use. Uses 0 for - default margin, 1 for no margin, and 2 for minimum margin. - and `width` in microns. - * `scaleFactor` Number (optional) - The scale factor of the web page. Can range from 0 to 100. - * `pageRanges` Record<string, number> (optional) - The page range to print. On macOS, only the first range is honored. - * `from` Number - Index of the first page to print (0-based). - * `to` Number - Index of the last page to print (inclusive) (0-based). - * `pageSize` String | Size (optional) - Specify page size of the generated PDF. Can be `A3`, - `A4`, `A5`, `Legal`, `Letter`, `Tabloid` or an Object containing `height` - * `printBackground` Boolean (optional) - Whether to print CSS backgrounds. - * `printSelectionOnly` Boolean (optional) - Whether to print selection only. + * `landscape` boolean (optional) - Paper orientation.`true` for landscape, `false` for portrait. Defaults to false. + * `displayHeaderFooter` boolean (optional) - Whether to display header and footer. Defaults to false. + * `printBackground` boolean (optional) - Whether to print background graphics. Defaults to false. + * `scale` number(optional) - Scale of the webpage rendering. Defaults to 1. + * `pageSize` string | Size (optional) - Specify page size of the generated PDF. Can be `A0`, `A1`, `A2`, `A3`, + `A4`, `A5`, `A6`, `Legal`, `Letter`, `Tabloid`, `Ledger`, or an Object containing `height` and `width` in inches. Defaults to `Letter`. + * `margins` Object (optional) + * `top` number (optional) - Top margin in inches. Defaults to 1cm (~0.4 inches). + * `bottom` number (optional) - Bottom margin in inches. Defaults to 1cm (~0.4 inches). + * `left` number (optional) - Left margin in inches. Defaults to 1cm (~0.4 inches). + * `right` number (optional) - Right margin in inches. Defaults to 1cm (~0.4 inches). + * `pageRanges` string (optional) - Page ranges to print, e.g., '1-5, 8, 11-13'. Defaults to the empty string, which means print all pages. + * `headerTemplate` string (optional) - HTML template for the print header. Should be valid HTML markup with following classes used to inject printing values into them: `date` (formatted print date), `title` (document title), `url` (document location), `pageNumber` (current page number) and `totalPages` (total pages in the document). For example, `<span class=title></span>` would generate span containing the title. + * `footerTemplate` string (optional) - HTML template for the print footer. Should use the same format as the `headerTemplate`. + * `preferCSSPageSize` boolean (optional) - Whether or not to prefer page size as defined by css. Defaults to false, in which case the content will be scaled to fit the paper size. + * `generateTaggedPDF` boolean (optional) _Experimental_ - Whether or not to generate a tagged (accessible) PDF. Defaults to false. As this property is experimental, the generated PDF may not adhere fully to PDF/UA and WCAG standards. + * `generateDocumentOutline` boolean (optional) _Experimental_ - Whether or not to generate a PDF document outline from content headers. Defaults to false. Returns `Promise<Uint8Array>` - Resolves with the generated PDF data. @@ -603,7 +629,7 @@ Captures a snapshot of the page within `rect`. Omitting `rect` will capture the ### `<webview>.send(channel, ...args)` -* `channel` String +* `channel` string * `...args` any[] Returns `Promise<void>` @@ -615,6 +641,21 @@ listening to the `channel` event with the [`ipcRenderer`](ipc-renderer.md) modul See [webContents.send](web-contents.md#contentssendchannel-args) for examples. +### `<webview>.sendToFrame(frameId, channel, ...args)` + +* `frameId` \[number, number] - `[processId, frameId]` +* `channel` string +* `...args` any[] + +Returns `Promise<void>` + +Send an asynchronous message to renderer process via `channel`, you can also +send arbitrary arguments. The renderer process can handle the message by +listening to the `channel` event with the [`ipcRenderer`](ipc-renderer.md) module. + +See [webContents.sendToFrame](web-contents.md#contentssendtoframeframeid-channel-args) for +examples. + ### `<webview>.sendInputEvent(event)` * `event` [MouseInputEvent](structures/mouse-input-event.md) | [MouseWheelInputEvent](structures/mouse-wheel-input-event.md) | [KeyboardInputEvent](structures/keyboard-input-event.md) @@ -628,36 +669,37 @@ for detailed description of `event` object. ### `<webview>.setZoomFactor(factor)` -* `factor` Number - Zoom factor. +* `factor` number - Zoom factor. Changes the zoom factor to the specified factor. Zoom factor is zoom percent divided by 100, so 300% = 3.0. ### `<webview>.setZoomLevel(level)` -* `level` Number - Zoom level. +* `level` number - Zoom level. Changes the zoom level to the specified level. The original size is 0 and each increment above or below represents zooming 20% larger or smaller to default limits of 300% and 50% of original size, respectively. The formula for this is `scale := 1.2 ^ level`. -> **NOTE**: The zoom policy at the Chromium level is same-origin, meaning that the +> [!NOTE] +> The zoom policy at the Chromium level is same-origin, meaning that the > zoom level for a specific domain propagates across all instances of windows with > the same domain. Differentiating the window URLs will make zoom work per-window. ### `<webview>.getZoomFactor()` -Returns `Number` - the current zoom factor. +Returns `number` - the current zoom factor. ### `<webview>.getZoomLevel()` -Returns `Number` - the current zoom level. +Returns `number` - the current zoom level. ### `<webview>.setVisualZoomLevelLimits(minimumLevel, maximumLevel)` -* `minimumLevel` Number -* `maximumLevel` Number +* `minimumLevel` number +* `maximumLevel` number Returns `Promise<void>` @@ -669,7 +711,7 @@ Shows pop-up dictionary that searches the selected word on the page. ### `<webview>.getWebContentsId()` -Returns `Number` - The WebContents ID of this `webview`. +Returns `number` - The WebContents ID of this `webview`. ## DOM Events @@ -679,8 +721,8 @@ The following DOM events are available to the `webview` tag: Returns: -* `url` String -* `isMainFrame` Boolean +* `url` string +* `isMainFrame` boolean Fired when a load has committed. This includes navigation within the current document as well as subframe document-level loads, but does not include @@ -696,9 +738,9 @@ spinning, and the `onload` event is dispatched. Returns: * `errorCode` Integer -* `errorDescription` String -* `validatedURL` String -* `isMainFrame` Boolean +* `errorDescription` string +* `validatedURL` string +* `isMainFrame` boolean This event is like `did-finish-load`, but fired when the load failed or was cancelled, e.g. `window.stop()` is invoked. @@ -707,7 +749,7 @@ cancelled, e.g. `window.stop()` is invoked. Returns: -* `isMainFrame` Boolean +* `isMainFrame` boolean Fired when a frame has done navigation. @@ -719,6 +761,10 @@ Corresponds to the points in time when the spinner of the tab starts spinning. Corresponds to the points in time when the spinner of the tab stops spinning. +### Event: 'did-attach' + +Fired when attached to the embedder web contents. + ### Event: 'dom-ready' Fired when document in the given frame is loaded. @@ -727,8 +773,8 @@ Fired when document in the given frame is loaded. Returns: -* `title` String -* `explicitSet` Boolean +* `title` string +* `explicitSet` boolean Fired when page title is set during navigation. `explicitSet` is false when title is synthesized from file url. @@ -737,7 +783,7 @@ title is synthesized from file url. Returns: -* `favicons` String[] - Array of URLs. +* `favicons` string[] - Array of URLs. Fired when page receives favicon urls. @@ -754,16 +800,16 @@ Fired when page leaves fullscreen triggered by HTML API. Returns: * `level` Integer - The log level, from 0 to 3. In order it matches `verbose`, `info`, `warning` and `error`. -* `message` String - The actual console message +* `message` string - The actual console message * `line` Integer - The line number of the source that triggered this console message -* `sourceId` String +* `sourceId` string Fired when the guest window logs a console message. The following example code forwards all log messages to the embedder's console without regard for log level or other properties. -```javascript +```js @ts-expect-error=[3] const webview = document.querySelector('webview') webview.addEventListener('console-message', (e) => { console.log('Guest page logged a message:', e.message) @@ -779,12 +825,12 @@ Returns: * `activeMatchOrdinal` Integer - Position of the active match. * `matches` Integer - Number of Matches. * `selectionArea` Rectangle - Coordinates of first match region. - * `finalUpdate` Boolean + * `finalUpdate` boolean Fired when a result is available for [`webview.findInPage`](#webviewfindinpagetext-options) request. -```javascript +```js @ts-expect-error=[3,6] const webview = document.querySelector('webview') webview.addEventListener('found-in-page', (e) => { webview.stopFindInPage('keepSelection') @@ -794,41 +840,36 @@ const requestId = webview.findInPage('test') console.log(requestId) ``` -### Event: 'new-window' +### Event: 'will-navigate' Returns: -* `url` String -* `frameName` String -* `disposition` String - Can be `default`, `foreground-tab`, `background-tab`, - `new-window`, `save-to-disk` and `other`. -* `options` BrowserWindowConstructorOptions - The options which should be used for creating the new - [`BrowserWindow`](browser-window.md). +* `url` string -Fired when the guest page attempts to open a new browser window. +Emitted when a user or the page wants to start navigation. It can happen when +the `window.location` object is changed or a user clicks a link in the page. -The following example code opens the new url in system's default browser. +This event will not emit when the navigation is started programmatically with +APIs like `<webview>.loadURL` and `<webview>.back`. -```javascript -const { shell } = require('electron') -const webview = document.querySelector('webview') +It is also not emitted during in-page navigation, such as clicking anchor links +or updating the `window.location.hash`. Use `did-navigate-in-page` event for +this purpose. -webview.addEventListener('new-window', async (e) => { - const protocol = (new URL(e.url)).protocol - if (protocol === 'http:' || protocol === 'https:') { - await shell.openExternal(e.url) - } -}) -``` +Calling `event.preventDefault()` does **NOT** have any effect. -### Event: 'will-navigate' +### Event: 'will-frame-navigate' Returns: -* `url` String +* `url` string +* `isMainFrame` boolean +* `frameProcessId` Integer +* `frameRoutingId` Integer -Emitted when a user or the page wants to start navigation. It can happen when -the `window.location` object is changed or a user clicks a link in the page. +Emitted when a user or the page wants to start navigation anywhere in the `<webview>` +or any frames embedded within. It can happen when the `window.location` object is +changed or a user clicks a link in the page. This event will not emit when the navigation is started programmatically with APIs like `<webview>.loadURL` and `<webview>.back`. @@ -837,13 +878,39 @@ It is also not emitted during in-page navigation, such as clicking anchor links or updating the `window.location.hash`. Use `did-navigate-in-page` event for this purpose. -Calling `event.preventDefault()` does __NOT__ have any effect. +Calling `event.preventDefault()` does **NOT** have any effect. + +### Event: 'did-start-navigation' + +Returns: + +* `url` string +* `isInPlace` boolean +* `isMainFrame` boolean +* `frameProcessId` Integer +* `frameRoutingId` Integer + +Emitted when any frame (including main) starts navigating. `isInPlace` will be +`true` for in-page navigations. + +### Event: 'did-redirect-navigation' + +Returns: + +* `url` string +* `isInPlace` boolean +* `isMainFrame` boolean +* `frameProcessId` Integer +* `frameRoutingId` Integer + +Emitted after a server side redirect occurs during navigation. For example a 302 +redirect. ### Event: 'did-navigate' Returns: -* `url` String +* `url` string Emitted when a navigation is done. @@ -851,12 +918,29 @@ This event is not emitted for in-page navigations, such as clicking anchor links or updating the `window.location.hash`. Use `did-navigate-in-page` event for this purpose. +### Event: 'did-frame-navigate' + +Returns: + +* `url` string +* `httpResponseCode` Integer - -1 for non HTTP navigations +* `httpStatusText` string - empty for non HTTP navigations, +* `isMainFrame` boolean +* `frameProcessId` Integer +* `frameRoutingId` Integer + +Emitted when any frame navigation is done. + +This event is not emitted for in-page navigations, such as clicking anchor links +or updating the `window.location.hash`. Use `did-navigate-in-page` event for +this purpose. + ### Event: 'did-navigate-in-page' Returns: -* `isMainFrame` Boolean -* `url` String +* `isMainFrame` boolean +* `url` string Emitted when an in-page navigation happened. @@ -871,7 +955,7 @@ Fired when the guest page attempts to close itself. The following example code navigates the `webview` to `about:blank` when the guest attempts to close itself. -```javascript +```js @ts-expect-error=[3] const webview = document.querySelector('webview') webview.addEventListener('close', () => { webview.src = 'about:blank' @@ -882,7 +966,8 @@ webview.addEventListener('close', () => { Returns: -* `channel` String +* `frameId` \[number, number] - pair of `[processId, frameId]`. +* `channel` string * `args` any[] Fired when the guest page has sent an asynchronous message to embedder page. @@ -890,7 +975,7 @@ Fired when the guest page has sent an asynchronous message to embedder page. With `sendToHost` method and `ipc-message` event you can communicate between guest page and embedder page: -```javascript +```js @ts-expect-error=[4,7] // In embedder page. const webview = document.querySelector('webview') webview.addEventListener('ipc-message', (event) => { @@ -900,26 +985,23 @@ webview.addEventListener('ipc-message', (event) => { webview.send('ping') ``` -```javascript +```js // In guest page. const { ipcRenderer } = require('electron') + ipcRenderer.on('ping', () => { ipcRenderer.sendToHost('pong') }) ``` -### Event: 'crashed' - -Fired when the renderer process is crashed. - -### Event: 'plugin-crashed' +### Event: 'render-process-gone' Returns: -* `name` String -* `version` String +* `details` [RenderProcessGoneDetails](structures/render-process-gone-details.md) -Fired when a plugin process is crashed. +Fired when the renderer process unexpectedly disappears. This is normally +because it was crashed or killed. ### Event: 'destroyed' @@ -937,7 +1019,7 @@ Emitted when media is paused or done playing. Returns: -* `themeColor` String +* `themeColor` string Emitted when a page's theme color changes. This is usually due to encountering a meta tag: @@ -949,10 +1031,27 @@ Emitted when a page's theme color changes. This is usually due to encountering a Returns: -* `url` String +* `url` string Emitted when mouse moves over a link or the keyboard moves the focus to a link. +### Event: 'devtools-open-url' + +Returns: + +* `url` string - URL of the link that was clicked or selected. + +Emitted when a link is clicked in DevTools or 'Open in new tab' is selected for a link in its context menu. + +#### Event: 'devtools-search-query' + +Returns: + +* `event` Event +* `query` string - text to query for. + +Emitted when 'Search' is selected for text in its context menu. + ### Event: 'devtools-opened' Emitted when DevTools is opened. @@ -965,5 +1064,86 @@ Emitted when DevTools is closed. Emitted when DevTools is focused / opened. -[runtime-enabled-features]: https://cs.chromium.org/chromium/src/third_party/blink/renderer/platform/runtime_enabled_features.json5?l=70 -[chrome-webview]: https://developer.chrome.com/apps/tags/webview +[runtime-enabled-features]: https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/platform/runtime_enabled_features.json5 +[chrome-webview]: https://developer.chrome.com/docs/extensions/reference/webviewTag/ + +### Event: 'context-menu' + +Returns: + +* `params` Object + * `x` Integer - x coordinate. + * `y` Integer - y coordinate. + * `linkURL` string - URL of the link that encloses the node the context menu + was invoked on. + * `linkText` string - Text associated with the link. May be an empty + string if the contents of the link are an image. + * `pageURL` string - URL of the top level page that the context menu was + invoked on. + * `frameURL` string - URL of the subframe that the context menu was invoked + on. + * `srcURL` string - Source URL for the element that the context menu + was invoked on. Elements with source URLs are images, audio and video. + * `mediaType` string - Type of the node the context menu was invoked on. Can + be `none`, `image`, `audio`, `video`, `canvas`, `file` or `plugin`. + * `hasImageContents` boolean - Whether the context menu was invoked on an image + which has non-empty contents. + * `isEditable` boolean - Whether the context is editable. + * `selectionText` string - Text of the selection that the context menu was + invoked on. + * `titleText` string - Title text of the selection that the context menu was + invoked on. + * `altText` string - Alt text of the selection that the context menu was + invoked on. + * `suggestedFilename` string - Suggested filename to be used when saving file through 'Save + Link As' option of context menu. + * `selectionRect` [Rectangle](structures/rectangle.md) - Rect representing the coordinates in the document space of the selection. + * `selectionStartOffset` number - Start position of the selection text. + * `referrerPolicy` [Referrer](structures/referrer.md) - The referrer policy of the frame on which the menu is invoked. + * `misspelledWord` string - The misspelled word under the cursor, if any. + * `dictionarySuggestions` string[] - An array of suggested words to show the + user to replace the `misspelledWord`. Only available if there is a misspelled + word and spellchecker is enabled. + * `frameCharset` string - The character encoding of the frame on which the + menu was invoked. + * `formControlType` string - The source that the context menu was invoked on. + Possible values include `none`, `button-button`, `field-set`, + `input-button`, `input-checkbox`, `input-color`, `input-date`, + `input-datetime-local`, `input-email`, `input-file`, `input-hidden`, + `input-image`, `input-month`, `input-number`, `input-password`, `input-radio`, + `input-range`, `input-reset`, `input-search`, `input-submit`, `input-telephone`, + `input-text`, `input-time`, `input-url`, `input-week`, `output`, `reset-button`, + `select-list`, `select-list`, `select-multiple`, `select-one`, `submit-button`, + and `text-area`, + * `spellcheckEnabled` boolean - If the context is editable, whether or not spellchecking is enabled. + * `menuSourceType` string - Input source that invoked the context menu. + Can be `none`, `mouse`, `keyboard`, `touch`, `touchMenu`, `longPress`, `longTap`, `touchHandle`, `stylus`, `adjustSelection`, or `adjustSelectionReset`. + * `mediaFlags` Object - The flags for the media element the context menu was + invoked on. + * `inError` boolean - Whether the media element has crashed. + * `isPaused` boolean - Whether the media element is paused. + * `isMuted` boolean - Whether the media element is muted. + * `hasAudio` boolean - Whether the media element has audio. + * `isLooping` boolean - Whether the media element is looping. + * `isControlsVisible` boolean - Whether the media element's controls are + visible. + * `canToggleControls` boolean - Whether the media element's controls are + toggleable. + * `canPrint` boolean - Whether the media element can be printed. + * `canSave` boolean - Whether or not the media element can be downloaded. + * `canShowPictureInPicture` boolean - Whether the media element can show picture-in-picture. + * `isShowingPictureInPicture` boolean - Whether the media element is currently showing picture-in-picture. + * `canRotate` boolean - Whether the media element can be rotated. + * `canLoop` boolean - Whether the media element can be looped. + * `editFlags` Object - These flags indicate whether the renderer believes it + is able to perform the corresponding action. + * `canUndo` boolean - Whether the renderer believes it can undo. + * `canRedo` boolean - Whether the renderer believes it can redo. + * `canCut` boolean - Whether the renderer believes it can cut. + * `canCopy` boolean - Whether the renderer believes it can copy. + * `canPaste` boolean - Whether the renderer believes it can paste. + * `canDelete` boolean - Whether the renderer believes it can delete. + * `canSelectAll` boolean - Whether the renderer believes it can select all. + * `canEditRichly` boolean - Whether the renderer believes it can edit text richly. + +Emitted when there is a new context menu that needs to be handled. diff --git a/docs/api/window-open.md b/docs/api/window-open.md index 2323731d1cda0..75f746f2c3ec4 100644 --- a/docs/api/window-open.md +++ b/docs/api/window-open.md @@ -3,19 +3,14 @@ There are several ways to control how windows are created from trusted or untrusted content within a renderer. Windows can be created from the renderer in two ways: -- clicking on links or submitting forms adorned with `target=_blank` -- JavaScript calling `window.open()` +* clicking on links or submitting forms adorned with `target=_blank` +* JavaScript calling `window.open()` -In non-sandboxed renderers, or when `nativeWindowOpen` is false (the default), this results in the creation of a -[`BrowserWindowProxy`](browser-window-proxy.md), a light wrapper around -`BrowserWindow`. - -However, when the `sandbox` (or directly, `nativeWindowOpen`) option is set, a -`Window` instance is created, as you'd expect in the browser. For same-origin -content, the new window is created within the same process, enabling the parent -to access the child window directly. This can be very useful for app sub-windows that act -as preference panels, or similar, as the parent can render to the sub-window -directly, as if it were a `div` in the parent. +For same-origin content, the new window is created within the same process, +enabling the parent to access the child window directly. This can be very +useful for app sub-windows that act as preference panels, or similar, as the +parent can render to the sub-window directly, as if it were a `div` in the +parent. This is the same behavior as in the browser. Electron pairs this native Chrome `Window` with a BrowserWindow under the hood. You can take advantage of all the customization available when creating a @@ -23,30 +18,33 @@ BrowserWindow in the main process by using `webContents.setWindowOpenHandler()` for renderer-created windows. BrowserWindow constructor options are set by, in increasing precedence -order: options inherited from the parent, parsed options -from the `features` string from `window.open()`, security-related webPreferences -inherited from the parent, and options given by +order: parsed options from the `features` string from `window.open()`, +security-related webPreferences inherited from the parent, and options given by [`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandlerhandler). Note that `webContents.setWindowOpenHandler` has final say and full privilege because it is invoked in the main process. ### `window.open(url[, frameName][, features])` -* `url` String -* `frameName` String (optional) -* `features` String (optional) +* `url` string +* `frameName` string (optional) +* `features` string (optional) -Returns [`BrowserWindowProxy`](browser-window-proxy.md) | [`Window`](https://developer.mozilla.org/en-US/docs/Web/API/Window) +Returns [`Window`](https://developer.mozilla.org/en-US/docs/Web/API/Window) | null `features` is a comma-separated key-value list, following the standard format of -the browser. Electron will parse `BrowserWindowConstructorOptions` out of this -list where possible, for convenience. For full control and better ergonomics, -consider using `webContents.setWindowOpenHandler` to customize the -BrowserWindow creation. - -A subset of `WebPreferences` can be set directly, -unnested, from the features string: `zoomFactor`, `nodeIntegration`, `preload`, -`javascript`, `contextIsolation`, and `webviewTag`. +the browser. For convenience, Electron will parse a subset of presentational +[`BrowserWindowConstructorOptions`](structures/browser-window-options.md) out of +this list (such as `width`, `height`, `x`, `y`, `show`, `frame`, `title`, +`backgroundColor`). Because the renderer is untrusted, options that cause the +main process to access the filesystem or that are otherwise privileged (such as +`icon`) are ignored. For full control and better ergonomics, use +`webContents.setWindowOpenHandler` to customize the BrowserWindow creation from +the main process. + +A subset of [`WebPreferences`](structures/web-preferences.md) can be set directly, +unnested, from the features string: `zoomFactor`, `nodeIntegration`, `javascript`, +`contextIsolation`, and `webviewTag`. For example: @@ -62,74 +60,56 @@ window.open('https://github.com', '_blank', 'top=500,left=200,frame=false,nodeIn enabled on the parent window. * JavaScript will always be disabled in the opened `window` if it is disabled on the parent window. -* Non-standard features (that are not handled by Chromium or Electron) given in - `features` will be passed to any registered `webContents`'s - `did-create-window` event handler in the `additionalFeatures` argument. +* Features that are not handled by Chromium and not in Electron's allowlist of + presentational `BrowserWindowConstructorOptions` are ignored. The raw + `features` string is still available to the main process via + `setWindowOpenHandler`. +* `frameName` follows the specification of `target` located in the [native documentation](https://developer.mozilla.org/en-US/docs/Web/API/Window/open#parameters). +* When opening `about:blank`, the child window's [`WebPreferences`](structures/web-preferences.md) will be copied + from the parent window, and there is no way to override it because Chromium + skips browser side navigation in this case. To customize or cancel the creation of the window, you can optionally set an override handler with `webContents.setWindowOpenHandler()` from the main -process. Returning `false` cancels the window, while returning an object sets -the `BrowserWindowConstructorOptions` used when creating the window. Note that -this is more powerful than passing options through the feature string, as the -renderer has more limited privileges in deciding security preferences than the -main process. - -### `BrowserWindowProxy` example - -```javascript - -// main.js -const mainWindow = new BrowserWindow() - -mainWindow.webContents.setWindowOpenHandler(({ url }) => { - if (url.startsWith('https://github.com/')) { - return true - } - return false -}) - -mainWindow.webContents.on('did-create-window', (childWindow) => { - // For example... - childWindow.webContents('will-navigate', (e) => { - e.preventDefault() - }) -}) -``` - -```javascript -// renderer.js -const windowProxy = window.open('https://github.com/', null, 'minimizable=false') -windowProxy.postMessage('hi', '*') -``` +process. Returning `{ action: 'deny' }` cancels the window. Returning `{ +action: 'allow', overrideBrowserWindowOptions: { ... } }` will allow opening +the window and setting the [`BrowserWindowConstructorOptions`](structures/browser-window-options.md) to be used when +creating the window. Note that this is more powerful than passing options +through the feature string, as the renderer has more limited privileges in +deciding security preferences than the main process. + +In addition to passing in `action` and `overrideBrowserWindowOptions`, +`outlivesOpener` can be passed like: `{ action: 'allow', outlivesOpener: true, +overrideBrowserWindowOptions: { ... } }`. If set to `true`, the newly created +window will not close when the opener window closes. The default value is `false`. ### Native `Window` example -```javascript +```js // main.js -const mainWindow = new BrowserWindow({ - webPreferences: { - nativeWindowOpen: true - } -}) +const mainWindow = new BrowserWindow() // In this example, only windows with the `about:blank` url will be created. // All other urls will be blocked. mainWindow.webContents.setWindowOpenHandler(({ url }) => { if (url === 'about:blank') { return { - frame: false, - fullscreenable: false, - backgroundColor: 'black', - webPreferences: { - preload: 'my-child-window-preload-script.js' + action: 'allow', + overrideBrowserWindowOptions: { + frame: false, + fullscreenable: false, + backgroundColor: 'black', + webPreferences: { + preload: 'my-child-window-preload-script.js' + } } } } - return false + return { action: 'deny' } }) ``` -```javascript +```js // renderer process (mainWindow) const childWindow = window.open('', 'modal') childWindow.document.write('<h1>Hello</h1>') diff --git a/docs/breaking-changes.md b/docs/breaking-changes.md index d527648c58ac6..de3418cfba1a8 100644 --- a/docs/breaking-changes.md +++ b/docs/breaking-changes.md @@ -6,14 +6,1663 @@ Breaking changes will be documented here, and deprecation warnings added to JS c This document uses the following convention to categorize breaking changes: -- **API Changed:** An API was changed in such a way that code that has not been updated is guaranteed to throw an exception. -- **Behavior Changed:** The behavior of Electron has changed, but not in such a way that an exception will necessarily be thrown. -- **Default Changed:** Code depending on the old default may break, not necessarily throwing an exception. The old behavior can be restored by explicitly specifying the value. -- **Deprecated:** An API was marked as deprecated. The API will continue to function, but will emit a deprecation warning, and will be removed in a future release. -- **Removed:** An API or feature was removed, and is no longer supported by Electron. +* **API Changed:** An API was changed in such a way that code that has not been updated is guaranteed to throw an exception. +* **Behavior Changed:** The behavior of Electron has changed, but not in such a way that an exception will necessarily be thrown. +* **Default Changed:** Code depending on the old default may break, not necessarily throwing an exception. The old behavior can be restored by explicitly specifying the value. +* **Deprecated:** An API was marked as deprecated. The API will continue to function, but will emit a deprecation warning, and will be removed in a future release. +* **Removed:** An API or feature was removed, and is no longer supported by Electron. + +## Planned Breaking API Changes (43.0) + +### Behavior Changed: Dialog methods default to Downloads directory + +The `defaultPath` option for the following methods now defaults to the user's Downloads folder (or their home directory if Downloads doesn't exist) when not explicitly provided: + +* `dialog.showOpenDialog` +* `dialog.showOpenDialogSync` +* `dialog.showSaveDialog` +* `dialog.showSaveDialogSync` + +Previously, when no `defaultPath` was provided, the underlying OS file dialog would determine the initial directory — typically remembering the last directory the user navigated to, or falling back to an OS-specific default. Now, Electron explicitly sets the initial directory to Downloads, which also means the OS will no longer track and restore the last-used directory between dialog invocations. + +To preserve the old behavior, you can track the last-used directory yourself and pass it as `defaultPath`: + +```js +const path = require('node:path') + +let lastUsedPath +const result = await dialog.showOpenDialog({ + defaultPath: lastUsedPath +}) + +if (!result.canceled && result.filePaths.length > 0) { + lastUsedPath = path.dirname(result.filePaths[0]) +} +``` + +## Planned Breaking API Changes (42.0) + +### Behavior Changed: macOS notifications now use `UNNotification` API + +Electron has migrated from the deprecated `NSUserNotification` API to the +[`UNNotification`](https://developer.apple.com/documentation/usernotifications) +API on macOS. The new API requires that an application be code-signed in order +for notifications to be displayed. If an application is not code-signed, +notifications will emit a `failed` event on the `Notification` object. + +### Behavior Changed: Offscreen rendering will use `1.0` as default device scale factor. + +Previously, OSR used the primary display's device scale factor for rendering, which made the output frame size vary across users. +Developers had to manually calculate the correct size using `screen.getPrimaryDisplay().scaleFactor`. We now provide an optional property +`webPreferences.offscreen.deviceScaleFactor` to specify a custom value when creating an OSR window. At first, if the property is not set, it defaults +to the primary display's scale factor (preserving the old behavior). Starting from Electron 42, the default will change to a constant value of `1.0` +for more consistent output sizes. + +### Behavior Changed: `electron` no longer downloads itself via `postinstall` script + +Previously, the `electron` npm package would download the Electron binary from the repository's +GitHub Releases in the package's `postinstall` script. + +With recent supply chain security attacks against the npm ecosystem with `postinstall` scripts as a +common attack vector, Electron will now download itself dynamically the first time that its main +`bin` script is run (e.g. via `npx electron`). With this change, you can now use Electron with the +npm `--ignore-scripts` flag. See [RFC #22](https://github.com/electron/rfcs/pull/22) for more context. + +```sh +# won't install binary to `node_modules/electron` +npm install electron --save-dev --ignore-scripts + +# will download the binary on demand before starting electron process +npx electron . + +# subsequent runs will used the binary downloaded from the first run +npx electron . +``` + +If you need to download the Electron binary on-demand, you can now call the `install-electron` script, +which contains the exact same code from the former `postinstall` script. + +```sh +npm install electron --save-dev --ignore-scripts +npx install-electron --no +``` + +If you need to test changes across platforms or architectures, you should now use the +`ELECTRON_INSTALL_ARCH` and `ELECTRON_INSTALL_PLATFORM` environment variables. + +```sh +# before: pass npm config flag on install command +npm install --platform=mas electron --save-dev +# after: add env var when you first run the Electron command +npm install electron --save-dev +ELECTRON_INSTALL_PLATFORM=mas npx electron . --no +``` + +This also means the `ELECTRON_SKIP_BINARY_DOWNLOAD` environment variable is no +longer supported, as its primary purpose was to prevent the `postinstall` script from running. + +### Removed: `quotas` object from `Session.clearStorageData(options)` + +When calling `Session.clearStorageData(options)`, the `options.quotas` object is no longer supported because it has been +[removed](https://chromium-review.googlesource.com/c/chromium/src/+/7596126) +from upstream Chromium. + +## Planned Breaking API Changes (41.0) + +### Behavior Changed: PDFs no longer create a separate WebContents + +Previously, PDF resources created a separate guest [WebContents](https://www.electronjs.org/docs/latest/api/web-contents) for rendering. Now, PDFs are rendered within the same WebContents instead. If you have code to detect PDF resources, use the [frame tree](https://www.electronjs.org/docs/latest/api/web-frame-main) instead of WebContents. + +Under the hood, Chromium [enabled](https://chromium-review.googlesource.com/c/chromium/src/+/7239572) a feature that changes PDFs to use out-of-process iframes (OOPIFs) instead of the `MimeHandlerViewGuest` extension. + +### Behavior Changed: Updated Cookie Change Cause in the Cookie 'changed' Event + +We have updated the [cookie](https://www.electronjs.org/docs/latest/api/cookies#event-changed) change cause in the cookie 'changed' event. +When a new cookie is set, the change cause is `inserted`. +When a cookie is deleted, the change cause remains `explicit`. +When the cookie being set is identical to an existing one (same name, domain, path, and value, with no actual changes), the change cause is `inserted-no-change-overwrite`. +When the value of the cookie being set remains unchanged but some of its attributes are updated, such as the expiration attribute, the change cause will be `inserted-no-value-change-overwrite`. + +## Planned Breaking API Changes (40.0) + +### Deprecated: `clipboard` API access from renderer processes + +Using the `clipboard` API directly in the renderer process is deprecated. +If you want to call this API from a renderer process, place the API call in +your preload script and expose it using the [contextBridge](https://www.electronjs.org/docs/latest/api/context-bridge) API. + +### Behavior Changed: MacOS dSYM files now compressed with tar.xz + +Debug symbols for MacOS (dSYM) now use xz compression in order to handle larger file sizes. `dsym.zip` files are now +`dsym.tar.xz` files. End users using debug symbols may need to update their zip utilities. + +### Deprecated: `showHiddenFiles` in Dialogs on Linux + +This property will still be honored on macOS and Windows, but support on Linux +will be removed in Electron 42. GTK intends for this to be a user choice rather +than an app choice and has removed the API to do this programmatically. + +## Planned Breaking API Changes (39.0) + +### Deprecated: `--host-rules` command line switch + +Chromium is deprecating the `--host-rules` switch. + +You should use `--host-resolver-rules` instead. + +### Behavior Changed: window.open popups are always resizable + +Per current [WHATWG spec](https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-open-dev), the `window.open` API will now always create a resizable popup window. + +To restore previous behavior: + +```js +webContents.setWindowOpenHandler((details) => { + return { + action: 'allow', + overrideBrowserWindowOptions: { + resizable: details.features.includes('resizable=yes') + } + } +}) +``` + +### Behavior Changed: `NSAudioCaptureUsageDescription` should be included in your app's Info.plist file to use `desktopCapturer` (🍏 macOS ≥14.2) + +Per [Chromium update](https://source.chromium.org/chromium/chromium/src/+/ad17e8f8b93d5f34891b06085d373a668918255e) which enables Apple's newer [CoreAudio Tap API](https://developer.apple.com/documentation/CoreAudio/capturing-system-audio-with-core-audio-taps#Configure-the-sample-code-project) by default, you now must have `NSAudioCaptureUsageDescription` defined in your `Info.plist` to use `desktopCapturer`. + +Electron's `desktopCapturer` will create a dead audio stream if the new permission is absent however no errors or warnings will occur. This is partially a side-effect of Chromium not falling back to the older `Screen & System Audio Recording` permissions system if the new system fails. + +To restore previous behavior: + +```js +// main.js (right beneath your require/import statments) +app.commandLine.appendSwitch( + 'disable-features', + 'MacCatapLoopbackAudioForScreenShare' +) +``` + +### Behavior Changed: shared texture OSR `paint` event data structure + +When using shared texture offscreen rendering feature, the `paint` event now emits a more structured object. +It moves the `sharedTextureHandle`, `planes`, `modifier` into a unified `handle` property. +See the [OffscreenSharedTexture](./api/structures/offscreen-shared-texture.md) API structure for more details. + +## Planned Breaking API Changes (38.0) + +### Removed: `ELECTRON_OZONE_PLATFORM_HINT` environment variable + +The default value of the `--ozone-platform` flag [changed to `auto`](https://chromium-review.googlesource.com/c/chromium/src/+/6775426). + +Electron now defaults to running as a native Wayland app when launched in a Wayland session (when `XDG_SESSION_TYPE=wayland`). +Users can force XWayland by passing `--ozone-platform=x11`. + +### Removed: `ORIGINAL_XDG_CURRENT_DESKTOP` environment variable + +Previously, Electron changed the value of `XDG_CURRENT_DESKTOP` internally to `Unity`, and stored the original name of the desktop session +in a separate variable. `XDG_CURRENT_DESKTOP` is no longer overridden and now reflects the actual desktop environment. + +### Removed: macOS 11 support + +macOS 11 (Big Sur) is no longer supported by [Chromium](https://chromium-review.googlesource.com/c/chromium/src/+/6594615). + +Older versions of Electron will continue to run on Big Sur, but macOS 12 (Monterey) +or later will be required to run Electron v38.0.0 and higher. + +### Removed: `plugin-crashed` event + +The `plugin-crashed` event has been removed from `webContents`. + +### Deprecated: `webFrame.routingId` property + +The `routingId` property will be removed from `webFrame` objects. + +You should use `webFrame.frameToken` instead. + +### Deprecated: `webFrame.findFrameByRoutingId(routingId)` + +The `webFrame.findFrameByRoutingId(routingId)` function will be removed. + +You should use `webFrame.findFrameByToken(frameToken)` instead. + +## Planned Breaking API Changes (37.0) + +### Utility Process unhandled rejection behavior change + +Utility Processes will now warn with an error message when an unhandled +rejection occurs instead of crashing the process. + +To restore the previous behavior, you can use: + +```js +process.on('unhandledRejection', () => { + process.exit(1) +}) +``` + +### Behavior Changed: `process.exit()` kills utility process synchronously + +Calling `process.exit()` in a utility process will now kill the utility process synchronously. +This brings the behavior of `process.exit()` in line with Node.js behavior. + +Please refer to the +[Node.js docs](https://nodejs.org/docs/latest-v22.x/api/process.html#processexitcode) and +[PR #45690](https://github.com/electron/electron/pull/45690) to understand the potential +implications of that, e.g., when calling `console.log()` before `process.exit()`. + +### Behavior Changed: WebUSB and WebSerial Blocklist Support + +[WebUSB](https://developer.mozilla.org/en-US/docs/Web/API/WebUSB_API) and [Web Serial](https://developer.mozilla.org/en-US/docs/Web/API/Web_Serial_API) now support the [WebUSB Blocklist](https://wicg.github.io/webusb/#blocklist) and [Web Serial Blocklist](https://wicg.github.io/serial/#blocklist) used by Chromium and outlined in their respective specifications. + +To disable these, users can pass `disable-usb-blocklist` and `disable-serial-blocklist` as command line flags. + +### Removed: `null` value for `session` property in `ProtocolResponse` + +This deprecated feature has been removed. + +Previously, setting the `ProtocolResponse.session` property to `null` +would create a random independent session. This is no longer supported. + +Using single-purpose sessions here is discouraged due to overhead costs; +however, old code that needs to preserve this behavior can emulate it by +creating a random session with `session.fromPartition(some_random_string)` +and then using it in `ProtocolResponse.session`. + +### Behavior Changed: `BrowserWindow.IsVisibleOnAllWorkspaces()` on Linux + +`BrowserWindow.IsVisibleOnAllWorkspaces()` will now return false on Linux if the +window is not currently visible. + +## Planned Breaking API Changes (36.0) + +### Behavior Changes: `app.commandLine` + +`app.commandLine` will convert upper-cases switches and arguments to lowercase. + +`app.commandLine` was only meant to handle chromium switches (which aren't case-sensitive) and switches passed via `app.commandLine` will not be passed down to any of the child processes. + +If you were using `app.commandLine` to control the behavior of the main process, you should do this via `process.argv`. + +### Deprecated: `NativeImage.getBitmap()` + +`NativeImage.toBitmap()` returns a newly-allocated copy of the bitmap. `NativeImage.getBitmap()` was originally an alternative function that returned the original instead of a copy. This changed when sandboxing was introduced, so both return a copy and are functionally equivalent. + +Client code should call `NativeImage.toBitmap()` instead: + +```js +// Deprecated +bitmap = image.getBitmap() +// Use this instead +bitmap = image.toBitmap() +``` + +### Removed: `isDefault` and `status` properties on `PrinterInfo` + +These properties have been removed from the PrinterInfo Object +because they have been removed from upstream Chromium. + +### Removed: `quota` type `syncable` in `Session.clearStorageData(options)` + +When calling `Session.clearStorageData(options)`, the `options.quota` type +`syncable` is no longer supported because it has been +[removed](https://chromium-review.googlesource.com/c/chromium/src/+/6309405) +from upstream Chromium. + +### Deprecated: `null` value for `session` property in `ProtocolResponse` + +Previously, setting the ProtocolResponse.session property to `null` +would create a random independent session. This is no longer supported. + +Using single-purpose sessions here is discouraged due to overhead costs; +however, old code that needs to preserve this behavior can emulate it by +creating a random session with `session.fromPartition(some_random_string)` +and then using it in `ProtocolResponse.session`. + +### Deprecated: `quota` property in `Session.clearStorageData(options)` + +When calling `Session.clearStorageData(options)`, the `options.quota` +property is deprecated. Since the `syncable` type was removed, there +is only one type left -- `'temporary'` -- so specifying it is unnecessary. + +### Deprecated: Extension methods and events on `session` + +`session.loadExtension`, `session.removeExtension`, `session.getExtension`, +`session.getAllExtensions`, 'extension-loaded' event, 'extension-unloaded' +event, and 'extension-ready' events have all moved to the new +`session.extensions` class. + +### Removed: `systemPreferences.isAeroGlassEnabled()` + +The `systemPreferences.isAeroGlassEnabled()` function has been removed without replacement. +It has been always returning `true` since Electron 23, which only supports Windows 10+, where DWM composition can no longer be disabled. + +https://learn.microsoft.com/en-us/windows/win32/dwm/composition-ovw#disabling-dwm-composition-windows7-and-earlier + +### Changed: GTK 4 is default when running GNOME + +After an [upstream change](https://chromium-review.googlesource.com/c/chromium/src/+/6310469), GTK 4 is now the default when running GNOME. + +In rare cases, this may cause some applications or configurations to [error](https://github.com/electron/electron/issues/46538) with the following message: + +```stderr +Gtk-ERROR **: 11:30:38.382: GTK 2/3 symbols detected. Using GTK 2/3 and GTK 4 in the same process is not supported +``` + +Affected users can work around this by specifying the `gtk-version` command-line flag: + +```shell +$ electron --gtk-version=3 # or --gtk-version=2 +``` + +The same can be done with the [`app.commandLine.appendSwitch`](https://www.electronjs.org/docs/latest/api/command-line#commandlineappendswitchswitch-value) function. + +## Planned Breaking API Changes (35.0) + +### Behavior Changed: Dialog API's `defaultPath` option on Linux + +On Linux, the required portal version for file dialogs has been reverted +to 3 from 4. Using the `defaultPath` option of the Dialog API is not +supported when using portal file chooser dialogs unless the portal +backend is version 4 or higher. The `--xdg-portal-required-version` +[command-line switch](api/command-line-switches.md#--xdg-portal-required-versionversion) +can be used to force a required version for your application. +See [#44426](https://github.com/electron/electron/pull/44426) for more details. + +### Deprecated: `getFromVersionID` on `session.serviceWorkers` + +The `session.serviceWorkers.fromVersionID(versionId)` API has been deprecated +in favor of `session.serviceWorkers.getInfoFromVersionID(versionId)`. This was +changed to make it more clear which object is returned with the introduction +of the `session.serviceWorkers.getWorkerFromVersionID(versionId)` API. + +```js +// Deprecated +session.serviceWorkers.fromVersionID(versionId) + +// Replace with +session.serviceWorkers.getInfoFromVersionID(versionId) +``` + +### Deprecated: `setPreloads`, `getPreloads` on `Session` + +`registerPreloadScript`, `unregisterPreloadScript`, and `getPreloadScripts` are introduced as a +replacement for the deprecated methods. These new APIs allow third-party libraries to register +preload scripts without replacing existing scripts. Also, the new `type` option allows for +additional preload targets beyond `frame`. + +```js +// Deprecated +session.setPreloads([path.join(__dirname, 'preload.js')]) + +// Replace with: +session.registerPreloadScript({ + type: 'frame', + id: 'app-preload', + filePath: path.join(__dirname, 'preload.js') +}) +``` + +### Deprecated: `level`, `message`, `line`, and `sourceId` arguments in `console-message` event on `WebContents` + +The `console-message` event on `WebContents` has been updated to provide details on the `Event` +argument. + +```js +// Deprecated +webContents.on('console-message', (event, level, message, line, sourceId) => {}) + +// Replace with: +webContents.on('console-message', ({ level, message, lineNumber, sourceId, frame }) => {}) +``` + +Additionally, `level` is now a string with possible values of `info`, `warning`, `error`, and `debug`. + +### Behavior Changed: `urls` property of `WebRequestFilter`. + +Previously, an empty urls array was interpreted as including all URLs. To explicitly include all URLs, developers should now use the `<all_urls>` pattern, which is a [designated URL pattern](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Match_patterns#all_urls) that matches every possible URL. This change clarifies the intent and ensures more predictable behavior. + +```js +// Deprecated +const deprecatedFilter = { + urls: [] +} + +// Replace with +const newFilter = { + urls: ['<all_urls>'] +} +``` + +### Deprecated: `systemPreferences.isAeroGlassEnabled()` + +The `systemPreferences.isAeroGlassEnabled()` function has been deprecated without replacement. +It has been always returning `true` since Electron 23, which only supports Windows 10+, where DWM composition can no longer be disabled. + +https://learn.microsoft.com/en-us/windows/win32/dwm/composition-ovw#disabling-dwm-composition-windows7-and-earlier + +## Planned Breaking API Changes (34.0) + +### Behavior Changed: menu bar will be hidden during fullscreen on Windows + +This brings the behavior to parity with Linux. Prior behavior: Menu bar is still visible during fullscreen on Windows. New behavior: Menu bar is hidden during fullscreen on Windows. + +**Correction**: This was previously listed as a breaking change in Electron 33, but was first released in Electron 34. + +## Planned Breaking API Changes (33.0) + +### Deprecated: `document.execCommand("paste")` + +The synchronous clipboard read API [document.execCommand("paste")](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Interact_with_the_clipboard) has been +deprecated in favor of [async clipboard API](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API). This is to align with the browser defaults. + +The `enableDeprecatedPaste` option on `WebPreferences` that triggers the permission +checks for this API and the associated permission type `deprecated-sync-clipboard-read` +are also deprecated. + +### Behavior Changed: frame properties may retrieve detached WebFrameMain instances or none at all + +APIs which provide access to a `WebFrameMain` instance may return an instance +with `frame.detached` set to `true`, or possibly return `null`. + +When a frame performs a cross-origin navigation, it enters into a detached state +in which it's no longer attached to the page. In this state, it may be running +[unload](https://developer.mozilla.org/en-US/docs/Web/API/Window/unload_event) +handlers prior to being deleted. In the event of an IPC sent during this state, +`frame.detached` will be set to `true` with the frame being destroyed shortly +thereafter. + +When receiving an event, it's important to access WebFrameMain properties +immediately upon being received. Otherwise, it's not guaranteed to point to the +same webpage as when received. To avoid misaligned expectations, Electron will +return `null` in the case of late access where the webpage has changed. + +```js +ipcMain.on('unload-event', (event) => { + event.senderFrame // ✅ accessed immediately +}) + +ipcMain.on('unload-event', async (event) => { + await crossOriginNavigationPromise + event.senderFrame // ❌ returns `null` due to late access +}) +``` + +### Behavior Changed: custom protocol URL handling on Windows + +Due to changes made in Chromium to support [Non-Special Scheme URLs](http://bit.ly/url-non-special), custom protocol URLs that use Windows file paths will no longer work correctly with the deprecated `protocol.registerFileProtocol` and the `baseURLForDataURL` property on `BrowserWindow.loadURL`, `WebContents.loadURL`, and `<webview>.loadURL`. `protocol.handle` will also not work with these types of URLs but this is not a change since it has always worked that way. + +```js +// No longer works +protocol.registerFileProtocol('other', () => { + callback({ filePath: '/path/to/my/file' }) +}) + +const mainWindow = new BrowserWindow() +mainWindow.loadURL('data:text/html,<script src="loaded-from-dataurl.js"></script>', { baseURLForDataURL: 'other://C:\\myapp' }) +mainWindow.loadURL('other://C:\\myapp\\index.html') + +// Replace with +const path = require('node:path') +const nodeUrl = require('node:url') +protocol.handle(other, (req) => { + const srcPath = 'C:\\myapp\\' + const reqURL = new URL(req.url) + return net.fetch(nodeUrl.pathToFileURL(path.join(srcPath, reqURL.pathname)).toString()) +}) + +mainWindow.loadURL('data:text/html,<script src="loaded-from-dataurl.js"></script>', { baseURLForDataURL: 'other://' }) +mainWindow.loadURL('other://index.html') +``` + +### Behavior Changed: `webContents` property on `login` on `app` + +The `webContents` property in the `login` event from `app` will be `null` +when the event is triggered for requests from the [utility process](api/utility-process.md) +created with `respondToAuthRequestsFromMainProcess` option. + +### Deprecated: `textured` option in `BrowserWindowConstructorOption.type` + +The `textured` option of `type` in `BrowserWindowConstructorOptions` has been deprecated with no replacement. This option relied on the [`NSWindowStyleMaskTexturedBackground`](https://developer.apple.com/documentation/appkit/nswindowstylemask/nswindowstylemasktexturedbackground) style mask on macOS, which has been deprecated with no alternative. + +### Removed: macOS 10.15 support + +macOS 10.15 (Catalina) is no longer supported by [Chromium](https://chromium-review.googlesource.com/c/chromium/src/+/5734361). + +Older versions of Electron will continue to run on Catalina, but macOS 11 (Big Sur) +or later will be required to run Electron v33.0.0 and higher. + +### Behavior Changed: Native modules now require C++20 + +Due to changes made upstream, both +[V8](https://chromium-review.googlesource.com/c/v8/v8/+/5587859) and +[Node.js](https://github.com/nodejs/node/pull/45427) now require C++20 as a +minimum version. Developers using native node modules should build their +modules with `--std=c++20` rather than `--std=c++17`. Images using gcc9 or +lower may need to update to gcc10 in order to compile. See +[#43555](https://github.com/electron/electron/pull/43555) for more details. + +### Deprecated: `systemPreferences.accessibilityDisplayShouldReduceTransparency` + +The `systemPreferences.accessibilityDisplayShouldReduceTransparency` property is now deprecated in favor of the new `nativeTheme.prefersReducedTransparency`, which provides identical information and works cross-platform. + +```js +// Deprecated +const shouldReduceTransparency = systemPreferences.accessibilityDisplayShouldReduceTransparency + +// Replace with: +const prefersReducedTransparency = nativeTheme.prefersReducedTransparency +``` + +## Planned Breaking API Changes (32.0) + +### Removed: `File.path` + +The nonstandard `path` property of the Web `File` object was added in an early version of Electron as a convenience method for working with native files when doing everything in the renderer was more common. However, it represents a deviation from the standard and poses a minor security risk as well, so beginning in Electron 32.0 it has been removed in favor of the [`webUtils.getPathForFile`](api/web-utils.md#webutilsgetpathforfilefile) method. + +```js +// Before (renderer) + +const file = document.querySelector('input[type=file]').files[0] +alert(`Uploaded file path was: ${file.path}`) +``` + +```js +// After (renderer) + +const file = document.querySelector('input[type=file]').files[0] +electron.showFilePath(file) + +// (preload) +const { contextBridge, webUtils } = require('electron') + +contextBridge.exposeInMainWorld('electron', { + showFilePath (file) { + // It's best not to expose the full file path to the web content if + // possible. + const path = webUtils.getPathForFile(file) + alert(`Uploaded file path was: ${path}`) + } +}) +``` + +### Deprecated: `clearHistory`, `canGoBack`, `goBack`, `canGoForward`, `goForward`, `goToIndex`, `canGoToOffset`, `goToOffset` on `WebContents` + +The navigation-related APIs are now deprecated. + +These APIs have been moved to the `navigationHistory` property of `WebContents` to provide a more structured and intuitive interface for managing navigation history. + +```js +// Deprecated +win.webContents.clearHistory() +win.webContents.canGoBack() +win.webContents.goBack() +win.webContents.canGoForward() +win.webContents.goForward() +win.webContents.goToIndex(index) +win.webContents.canGoToOffset() +win.webContents.goToOffset(index) + +// Replace with +win.webContents.navigationHistory.clear() +win.webContents.navigationHistory.canGoBack() +win.webContents.navigationHistory.goBack() +win.webContents.navigationHistory.canGoForward() +win.webContents.navigationHistory.goForward() +win.webContents.navigationHistory.canGoToOffset() +win.webContents.navigationHistory.goToOffset(index) +``` + +### Behavior changed: Directory `databases` in `userData` will be deleted + +If you have a directory called `databases` in the directory returned by +`app.getPath('userData')`, it will be deleted when Electron 32 is first run. +The `databases` directory was used by WebSQL, which was removed in Electron 31. +Chromium now performs a cleanup that deletes this directory. See +[issue #45396](https://github.com/electron/electron/issues/45396). + +## Planned Breaking API Changes (31.0) + +### Removed: `WebSQL` support + +Chromium has removed support for WebSQL upstream, transitioning it to Android only. See +[Chromium's intent to remove discussion](https://groups.google.com/a/chromium.org/g/blink-dev/c/fWYb6evVA-w/m/wGI863zaAAAJ) +for more information. + +### Behavior Changed: `nativeImage.toDataURL` will preserve PNG colorspace + +PNG decoder implementation has been changed to preserve colorspace data, the +encoded data returned from this function now matches it. + +See [crbug.com/332584706](https://issues.chromium.org/issues/332584706) for more information. + +### Behavior Changed: `window.flashFrame(bool)` will flash dock icon continuously on macOS + +This brings the behavior to parity with Windows and Linux. Prior behavior: The first `flashFrame(true)` bounces the dock icon only once (using the [NSInformationalRequest](https://developer.apple.com/documentation/appkit/nsrequestuserattentiontype/nsinformationalrequest) level) and `flashFrame(false)` does nothing. New behavior: Flash continuously until `flashFrame(false)` is called. This uses the [NSCriticalRequest](https://developer.apple.com/documentation/appkit/nsrequestuserattentiontype/nscriticalrequest) level instead. To explicitly use `NSInformationalRequest` to cause a single dock icon bounce, it is still possible to use [`dock.bounce('informational')`](https://www.electronjs.org/docs/latest/api/dock#dockbouncetype-macos). + +## Planned Breaking API Changes (30.0) + +### Behavior Changed: cross-origin iframes now use Permission Policy to access features + +Cross-origin iframes must now specify features available to a given `iframe` via the `allow` +attribute in order to access them. + +See [documentation](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#allow) for +more information. + +### Removed: The `--disable-color-correct-rendering` switch + +This switch was never formally documented but its removal is being noted here regardless. Chromium itself now has better support for color spaces so this flag should not be needed. + +### Behavior Changed: `BrowserView.setAutoResize` behavior on macOS + +In Electron 30, BrowserView is now a wrapper around the new [WebContentsView](api/web-contents-view.md) API. + +Previously, the `setAutoResize` function of the `BrowserView` API was backed by [autoresizing](https://developer.apple.com/documentation/appkit/nsview/1483281-autoresizingmask?language=objc) on macOS, and by a custom algorithm on Windows and Linux. +For simple use cases such as making a BrowserView fill the entire window, the behavior of these two approaches was identical. +However, in more advanced cases, BrowserViews would be autoresized differently on macOS than they would be on other platforms, as the custom resizing algorithm for Windows and Linux did not perfectly match the behavior of macOS's autoresizing API. +The autoresizing behavior is now standardized across all platforms. + +If your app uses `BrowserView.setAutoResize` to do anything more complex than making a BrowserView fill the entire window, it's likely you already had custom logic in place to handle this difference in behavior on macOS. +If so, that logic will no longer be needed in Electron 30 as autoresizing behavior is consistent. + +### Deprecated: `BrowserView` + +The [`BrowserView`](./api/browser-view.md) class has been deprecated and +replaced by the new [`WebContentsView`](./api/web-contents-view.md) class. + +`BrowserView` related methods in [`BrowserWindow`](./api/browser-window.md) have +also been deprecated: + +```js +BrowserWindow.fromBrowserView(browserView) +win.setBrowserView(browserView) +win.getBrowserView() +win.addBrowserView(browserView) +win.removeBrowserView(browserView) +win.setTopBrowserView(browserView) +win.getBrowserViews() +``` + +### Removed: `params.inputFormType` property on `context-menu` on `WebContents` + +The `inputFormType` property of the params object in the `context-menu` +event from `WebContents` has been removed. Use the new `formControlType` +property instead. + +### Removed: `process.getIOCounters()` + +Chromium has removed access to this information. + +## Planned Breaking API Changes (29.0) + +### Behavior Changed: `ipcRenderer` can no longer be sent over the `contextBridge` + +Attempting to send the entire `ipcRenderer` module as an object over the `contextBridge` will now result in +an empty object on the receiving side of the bridge. This change was made to remove / mitigate +a security footgun. You should not directly expose ipcRenderer or its methods over the bridge. +Instead, provide a safe wrapper like below: + +```js +contextBridge.exposeInMainWorld('app', { + onEvent: (cb) => ipcRenderer.on('foo', (e, ...args) => cb(args)) +}) +``` + +### Removed: `renderer-process-crashed` event on `app` + +The `renderer-process-crashed` event on `app` has been removed. +Use the new `render-process-gone` event instead. + +```js +// Removed +app.on('renderer-process-crashed', (event, webContents, killed) => { /* ... */ }) + +// Replace with +app.on('render-process-gone', (event, webContents, details) => { /* ... */ }) +``` + +### Removed: `crashed` event on `WebContents` and `<webview>` + +The `crashed` events on `WebContents` and `<webview>` have been removed. +Use the new `render-process-gone` event instead. + +```js +// Removed +win.webContents.on('crashed', (event, killed) => { /* ... */ }) +webview.addEventListener('crashed', (event) => { /* ... */ }) + +// Replace with +win.webContents.on('render-process-gone', (event, details) => { /* ... */ }) +webview.addEventListener('render-process-gone', (event) => { /* ... */ }) +``` + +### Removed: `gpu-process-crashed` event on `app` + +The `gpu-process-crashed` event on `app` has been removed. +Use the new `child-process-gone` event instead. + +```js +// Removed +app.on('gpu-process-crashed', (event, killed) => { /* ... */ }) + +// Replace with +app.on('child-process-gone', (event, details) => { /* ... */ }) +``` + +## Planned Breaking API Changes (28.0) + +### Behavior Changed: `WebContents.backgroundThrottling` set to false affects all `WebContents` in the host `BrowserWindow` + +`WebContents.backgroundThrottling` set to false will disable frames throttling +in the `BrowserWindow` for all `WebContents` displayed by it. + +### Removed: `BrowserWindow.setTrafficLightPosition(position)` + +`BrowserWindow.setTrafficLightPosition(position)` has been removed, the +`BrowserWindow.setWindowButtonPosition(position)` API should be used instead +which accepts `null` instead of `{ x: 0, y: 0 }` to reset the position to +system default. + +```js +// Removed in Electron 28 +win.setTrafficLightPosition({ x: 10, y: 10 }) +win.setTrafficLightPosition({ x: 0, y: 0 }) + +// Replace with +win.setWindowButtonPosition({ x: 10, y: 10 }) +win.setWindowButtonPosition(null) +``` + +### Removed: `BrowserWindow.getTrafficLightPosition()` + +`BrowserWindow.getTrafficLightPosition()` has been removed, the +`BrowserWindow.getWindowButtonPosition()` API should be used instead +which returns `null` instead of `{ x: 0, y: 0 }` when there is no custom +position. + +```js +// Removed in Electron 28 +const pos = win.getTrafficLightPosition() +if (pos.x === 0 && pos.y === 0) { + // No custom position. +} + +// Replace with +const ret = win.getWindowButtonPosition() +if (ret === null) { + // No custom position. +} +``` + +### Removed: `ipcRenderer.sendTo()` + +The `ipcRenderer.sendTo()` API has been removed. It should be replaced by setting up a [`MessageChannel`](tutorial/message-ports.md#setting-up-a-messagechannel-between-two-renderers) between the renderers. + +The `senderId` and `senderIsMainFrame` properties of `IpcRendererEvent` have been removed as well. + +### Removed: `app.runningUnderRosettaTranslation` + +The `app.runningUnderRosettaTranslation` property has been removed. +Use `app.runningUnderARM64Translation` instead. + +```js +// Removed +console.log(app.runningUnderRosettaTranslation) +// Replace with +console.log(app.runningUnderARM64Translation) +``` + +### Deprecated: `renderer-process-crashed` event on `app` + +The `renderer-process-crashed` event on `app` has been deprecated. +Use the new `render-process-gone` event instead. + +```js +// Deprecated +app.on('renderer-process-crashed', (event, webContents, killed) => { /* ... */ }) + +// Replace with +app.on('render-process-gone', (event, webContents, details) => { /* ... */ }) +``` + +### Deprecated: `params.inputFormType` property on `context-menu` on `WebContents` + +The `inputFormType` property of the params object in the `context-menu` +event from `WebContents` has been deprecated. Use the new `formControlType` +property instead. + +### Deprecated: `crashed` event on `WebContents` and `<webview>` + +The `crashed` events on `WebContents` and `<webview>` have been deprecated. +Use the new `render-process-gone` event instead. + +```js +// Deprecated +win.webContents.on('crashed', (event, killed) => { /* ... */ }) +webview.addEventListener('crashed', (event) => { /* ... */ }) + +// Replace with +win.webContents.on('render-process-gone', (event, details) => { /* ... */ }) +webview.addEventListener('render-process-gone', (event) => { /* ... */ }) +``` + +### Deprecated: `gpu-process-crashed` event on `app` + +The `gpu-process-crashed` event on `app` has been deprecated. +Use the new `child-process-gone` event instead. + +```js +// Deprecated +app.on('gpu-process-crashed', (event, killed) => { /* ... */ }) + +// Replace with +app.on('child-process-gone', (event, details) => { /* ... */ }) +``` + +## Planned Breaking API Changes (27.0) + +### Removed: macOS 10.13 / 10.14 support + +macOS 10.13 (High Sierra) and macOS 10.14 (Mojave) are no longer supported by [Chromium](https://chromium-review.googlesource.com/c/chromium/src/+/4629466). + +Older versions of Electron will continue to run on these operating systems, but macOS 10.15 (Catalina) +or later will be required to run Electron v27.0.0 and higher. + +### Deprecated: `ipcRenderer.sendTo()` + +The `ipcRenderer.sendTo()` API has been deprecated. It should be replaced by setting up a [`MessageChannel`](tutorial/message-ports.md#setting-up-a-messagechannel-between-two-renderers) between the renderers. + +The `senderId` and `senderIsMainFrame` properties of `IpcRendererEvent` have been deprecated as well. + +### Removed: color scheme events in `systemPreferences` + +The following `systemPreferences` events have been removed: + +* `inverted-color-scheme-changed` +* `high-contrast-color-scheme-changed` + +Use the new `updated` event on the `nativeTheme` module instead. + +```js +// Removed +systemPreferences.on('inverted-color-scheme-changed', () => { /* ... */ }) +systemPreferences.on('high-contrast-color-scheme-changed', () => { /* ... */ }) + +// Replace with +nativeTheme.on('updated', () => { /* ... */ }) +``` + +### Removed: Some `window.setVibrancy` options on macOS + +The following vibrancy options have been removed: + +* 'light' +* 'medium-light' +* 'dark' +* 'ultra-dark' +* 'appearance-based' + +These were previously deprecated and have been removed by Apple in 10.15. + +### Removed: `webContents.getPrinters` + +The `webContents.getPrinters` method has been removed. Use +`webContents.getPrintersAsync` instead. + +```js +const w = new BrowserWindow({ show: false }) + +// Removed +console.log(w.webContents.getPrinters()) +// Replace with +w.webContents.getPrintersAsync().then((printers) => { + console.log(printers) +}) +``` + +### Removed: `systemPreferences.{get,set}AppLevelAppearance` and `systemPreferences.appLevelAppearance` + +The `systemPreferences.getAppLevelAppearance` and `systemPreferences.setAppLevelAppearance` +methods have been removed, as well as the `systemPreferences.appLevelAppearance` property. +Use the `nativeTheme` module instead. + +```js +// Removed +systemPreferences.getAppLevelAppearance() +// Replace with +nativeTheme.shouldUseDarkColors + +// Removed +systemPreferences.appLevelAppearance +// Replace with +nativeTheme.shouldUseDarkColors + +// Removed +systemPreferences.setAppLevelAppearance('dark') +// Replace with +nativeTheme.themeSource = 'dark' +``` + +### Removed: `alternate-selected-control-text` value for `systemPreferences.getColor` + +The `alternate-selected-control-text` value for `systemPreferences.getColor` +has been removed. Use `selected-content-background` instead. + +```js +// Removed +systemPreferences.getColor('alternate-selected-control-text') +// Replace with +systemPreferences.getColor('selected-content-background') +``` + +## Planned Breaking API Changes (26.0) + +### Deprecated: `webContents.getPrinters` + +The `webContents.getPrinters` method has been deprecated. Use +`webContents.getPrintersAsync` instead. + +```js +const w = new BrowserWindow({ show: false }) + +// Deprecated +console.log(w.webContents.getPrinters()) +// Replace with +w.webContents.getPrintersAsync().then((printers) => { + console.log(printers) +}) +``` + +### Deprecated: `systemPreferences.{get,set}AppLevelAppearance` and `systemPreferences.appLevelAppearance` + +The `systemPreferences.getAppLevelAppearance` and `systemPreferences.setAppLevelAppearance` +methods have been deprecated, as well as the `systemPreferences.appLevelAppearance` property. +Use the `nativeTheme` module instead. + +```js +// Deprecated +systemPreferences.getAppLevelAppearance() +// Replace with +nativeTheme.shouldUseDarkColors + +// Deprecated +systemPreferences.appLevelAppearance +// Replace with +nativeTheme.shouldUseDarkColors + +// Deprecated +systemPreferences.setAppLevelAppearance('dark') +// Replace with +nativeTheme.themeSource = 'dark' +``` + +### Deprecated: `alternate-selected-control-text` value for `systemPreferences.getColor` + +The `alternate-selected-control-text` value for `systemPreferences.getColor` +has been deprecated. Use `selected-content-background` instead. + +```js +// Deprecated +systemPreferences.getColor('alternate-selected-control-text') +// Replace with +systemPreferences.getColor('selected-content-background') +``` + +## Planned Breaking API Changes (25.0) + +### Deprecated: `protocol.{un,}{register,intercept}{Buffer,String,Stream,File,Http}Protocol` and `protocol.isProtocol{Registered,Intercepted}` + +The `protocol.register*Protocol` and `protocol.intercept*Protocol` methods have +been replaced with [`protocol.handle`](api/protocol.md#protocolhandlescheme-handler). + +The new method can either register a new protocol or intercept an existing +protocol, and responses can be of any type. + +```js +// Deprecated in Electron 25 +protocol.registerBufferProtocol('some-protocol', () => { + callback({ mimeType: 'text/html', data: Buffer.from('<h5>Response</h5>') }) +}) + +// Replace with +protocol.handle('some-protocol', () => { + return new Response( + Buffer.from('<h5>Response</h5>'), // Could also be a string or ReadableStream. + { headers: { 'content-type': 'text/html' } } + ) +}) +``` + +```js +// Deprecated in Electron 25 +protocol.registerHttpProtocol('some-protocol', () => { + callback({ url: 'https://electronjs.org' }) +}) + +// Replace with +protocol.handle('some-protocol', () => { + return net.fetch('https://electronjs.org') +}) +``` + +```js +// Deprecated in Electron 25 +protocol.registerFileProtocol('some-protocol', () => { + callback({ filePath: '/path/to/my/file' }) +}) + +// Replace with +protocol.handle('some-protocol', () => { + return net.fetch('file:///path/to/my/file') +}) +``` + +### Deprecated: `BrowserWindow.setTrafficLightPosition(position)` + +`BrowserWindow.setTrafficLightPosition(position)` has been deprecated, the +`BrowserWindow.setWindowButtonPosition(position)` API should be used instead +which accepts `null` instead of `{ x: 0, y: 0 }` to reset the position to +system default. + +```js +// Deprecated in Electron 25 +win.setTrafficLightPosition({ x: 10, y: 10 }) +win.setTrafficLightPosition({ x: 0, y: 0 }) + +// Replace with +win.setWindowButtonPosition({ x: 10, y: 10 }) +win.setWindowButtonPosition(null) +``` + +### Deprecated: `BrowserWindow.getTrafficLightPosition()` + +`BrowserWindow.getTrafficLightPosition()` has been deprecated, the +`BrowserWindow.getWindowButtonPosition()` API should be used instead +which returns `null` instead of `{ x: 0, y: 0 }` when there is no custom +position. + +```js +// Deprecated in Electron 25 +const pos = win.getTrafficLightPosition() +if (pos.x === 0 && pos.y === 0) { + // No custom position. +} + +// Replace with +const ret = win.getWindowButtonPosition() +if (ret === null) { + // No custom position. +} +``` + +## Planned Breaking API Changes (24.0) + +### API Changed: `nativeImage.createThumbnailFromPath(path, size)` + +The `maxSize` parameter has been changed to `size` to reflect that the size passed in will be the size the thumbnail created. Previously, Windows would not scale the image up if it were smaller than `maxSize`, and +macOS would always set the size to `maxSize`. Behavior is now the same across platforms. + +Updated Behavior: + +```js +// a 128x128 image. +const imagePath = path.join('path', 'to', 'capybara.png') + +// Scaling up a smaller image. +const upSize = { width: 256, height: 256 } +nativeImage.createThumbnailFromPath(imagePath, upSize).then(result => { + console.log(result.getSize()) // { width: 256, height: 256 } +}) + +// Scaling down a larger image. +const downSize = { width: 64, height: 64 } +nativeImage.createThumbnailFromPath(imagePath, downSize).then(result => { + console.log(result.getSize()) // { width: 64, height: 64 } +}) +``` + +Previous Behavior (on Windows): + +```js +// a 128x128 image +const imagePath = path.join('path', 'to', 'capybara.png') +const size = { width: 256, height: 256 } +nativeImage.createThumbnailFromPath(imagePath, size).then(result => { + console.log(result.getSize()) // { width: 128, height: 128 } +}) +``` + +## Planned Breaking API Changes (23.0) + +### Behavior Changed: Draggable Regions on macOS + +The implementation of draggable regions (using the CSS property `-webkit-app-region: drag`) has changed on macOS to bring it in line with Windows and Linux. Previously, when a region with `-webkit-app-region: no-drag` overlapped a region with `-webkit-app-region: drag`, the `no-drag` region would always take precedence on macOS, regardless of CSS layering. That is, if a `drag` region was above a `no-drag` region, it would be ignored. Beginning in Electron 23, a `drag` region on top of a `no-drag` region will correctly cause the region to be draggable. + +Additionally, the `customButtonsOnHover` BrowserWindow property previously created a draggable region which ignored the `-webkit-app-region` CSS property. This has now been fixed (see [#37210](https://github.com/electron/electron/issues/37210#issuecomment-1440509592) for discussion). + +As a result, if your app uses a frameless window with draggable regions on macOS, the regions which are draggable in your app may change in Electron 23. + +### Removed: Windows 7 / 8 / 8.1 support + +[Windows 7, Windows 8, and Windows 8.1 are no longer supported](https://www.electronjs.org/blog/windows-7-to-8-1-deprecation-notice). Electron follows the planned Chromium deprecation policy, which will [deprecate Windows 7 support beginning in Chromium 109](https://support.google.com/chrome/thread/185534985/sunsetting-support-for-windows-7-8-8-1-in-early-2023?hl=en). + +Older versions of Electron will continue to run on these operating systems, but Windows 10 or later will be required to run Electron v23.0.0 and higher. + +### Removed: BrowserWindow `scroll-touch-*` events + +The deprecated `scroll-touch-begin`, `scroll-touch-end` and `scroll-touch-edge` +events on BrowserWindow have been removed. Instead, use the newly available +[`input-event` event](api/web-contents.md#event-input-event) on WebContents. + +```js +// Removed in Electron 23.0 +win.on('scroll-touch-begin', scrollTouchBegin) +win.on('scroll-touch-edge', scrollTouchEdge) +win.on('scroll-touch-end', scrollTouchEnd) + +// Replace with +win.webContents.on('input-event', (_, event) => { + if (event.type === 'gestureScrollBegin') { + scrollTouchBegin() + } else if (event.type === 'gestureScrollUpdate') { + scrollTouchEdge() + } else if (event.type === 'gestureScrollEnd') { + scrollTouchEnd() + } +}) +``` + +### Removed: `webContents.incrementCapturerCount(stayHidden, stayAwake)` + +The `webContents.incrementCapturerCount(stayHidden, stayAwake)` function has been removed. +It is now automatically handled by `webContents.capturePage` when a page capture completes. + +```js +const w = new BrowserWindow({ show: false }) + +// Removed in Electron 23 +w.webContents.incrementCapturerCount() +w.capturePage().then(image => { + console.log(image.toDataURL()) + w.webContents.decrementCapturerCount() +}) + +// Replace with +w.capturePage().then(image => { + console.log(image.toDataURL()) +}) +``` + +### Removed: `webContents.decrementCapturerCount(stayHidden, stayAwake)` + +The `webContents.decrementCapturerCount(stayHidden, stayAwake)` function has been removed. +It is now automatically handled by `webContents.capturePage` when a page capture completes. + +```js +const w = new BrowserWindow({ show: false }) + +// Removed in Electron 23 +w.webContents.incrementCapturerCount() +w.capturePage().then(image => { + console.log(image.toDataURL()) + w.webContents.decrementCapturerCount() +}) + +// Replace with +w.capturePage().then(image => { + console.log(image.toDataURL()) +}) +``` + +## Planned Breaking API Changes (22.0) + +### Deprecated: `webContents.incrementCapturerCount(stayHidden, stayAwake)` + +`webContents.incrementCapturerCount(stayHidden, stayAwake)` has been deprecated. +It is now automatically handled by `webContents.capturePage` when a page capture completes. + +```js +const w = new BrowserWindow({ show: false }) + +// Removed in Electron 23 +w.webContents.incrementCapturerCount() +w.capturePage().then(image => { + console.log(image.toDataURL()) + w.webContents.decrementCapturerCount() +}) + +// Replace with +w.capturePage().then(image => { + console.log(image.toDataURL()) +}) +``` + +### Deprecated: `webContents.decrementCapturerCount(stayHidden, stayAwake)` + +`webContents.decrementCapturerCount(stayHidden, stayAwake)` has been deprecated. +It is now automatically handled by `webContents.capturePage` when a page capture completes. + +```js +const w = new BrowserWindow({ show: false }) + +// Removed in Electron 23 +w.webContents.incrementCapturerCount() +w.capturePage().then(image => { + console.log(image.toDataURL()) + w.webContents.decrementCapturerCount() +}) + +// Replace with +w.capturePage().then(image => { + console.log(image.toDataURL()) +}) +``` + +### Removed: WebContents `new-window` event + +The `new-window` event of WebContents has been removed. It is replaced by [`webContents.setWindowOpenHandler()`](api/web-contents.md#contentssetwindowopenhandlerhandler). + +```js +// Removed in Electron 22 +webContents.on('new-window', (event) => { + event.preventDefault() +}) + +// Replace with +webContents.setWindowOpenHandler((details) => { + return { action: 'deny' } +}) +``` + +### Removed: `<webview>` `new-window` event + +The `new-window` event of `<webview>` has been removed. There is no direct replacement. + +```js +// Removed in Electron 22 +webview.addEventListener('new-window', (event) => {}) +``` + +```js +// Replace with + +// main.js +mainWindow.webContents.on('did-attach-webview', (event, wc) => { + wc.setWindowOpenHandler((details) => { + mainWindow.webContents.send('webview-new-window', wc.id, details) + return { action: 'deny' } + }) +}) + +// preload.js +const { ipcRenderer } = require('electron') +ipcRenderer.on('webview-new-window', (e, webContentsId, details) => { + console.log('webview-new-window', webContentsId, details) + document.getElementById('webview').dispatchEvent(new Event('new-window')) +}) + +// renderer.js +document.getElementById('webview').addEventListener('new-window', () => { + console.log('got new-window event') +}) +``` + +### Deprecated: BrowserWindow `scroll-touch-*` events + +The `scroll-touch-begin`, `scroll-touch-end` and `scroll-touch-edge` events on +BrowserWindow are deprecated. Instead, use the newly available +[`input-event` event](api/web-contents.md#event-input-event) on WebContents. + +```js +// Deprecated +win.on('scroll-touch-begin', scrollTouchBegin) +win.on('scroll-touch-edge', scrollTouchEdge) +win.on('scroll-touch-end', scrollTouchEnd) + +// Replace with +win.webContents.on('input-event', (_, event) => { + if (event.type === 'gestureScrollBegin') { + scrollTouchBegin() + } else if (event.type === 'gestureScrollUpdate') { + scrollTouchEdge() + } else if (event.type === 'gestureScrollEnd') { + scrollTouchEnd() + } +}) +``` + +## Planned Breaking API Changes (21.0) + +### Behavior Changed: V8 Memory Cage enabled + +The V8 memory cage has been enabled, which has implications for native modules +which wrap non-V8 memory with `ArrayBuffer` or `Buffer`. See the +[blog post about the V8 memory cage](https://www.electronjs.org/blog/v8-memory-cage) for +more details. + +### API Changed: `webContents.printToPDF()` + +`webContents.printToPDF()` has been modified to conform to [`Page.printToPDF`](https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-printToPDF) in the Chrome DevTools Protocol. This has been changed in order to +address changes upstream that made our previous implementation untenable and rife with bugs. + +**Arguments Changed** + +* `pageRanges` + +**Arguments Removed** + +* `printSelectionOnly` +* `marginsType` +* `headerFooter` +* `scaleFactor` + +**Arguments Added** + +* `headerTemplate` +* `footerTemplate` +* `displayHeaderFooter` +* `margins` +* `scale` +* `preferCSSPageSize` + +```js +// Main process +const { webContents } = require('electron') + +webContents.printToPDF({ + landscape: true, + displayHeaderFooter: true, + printBackground: true, + scale: 2, + pageSize: 'Ledger', + margins: { + top: 2, + bottom: 2, + left: 2, + right: 2 + }, + pageRanges: '1-5, 8, 11-13', + headerTemplate: '<h1>Title</h1>', + footerTemplate: '<div><span class="pageNumber"></span></div>', + preferCSSPageSize: true +}).then(data => { + fs.writeFile(pdfPath, data, (error) => { + if (error) throw error + console.log(`Wrote PDF successfully to ${pdfPath}`) + }) +}).catch(error => { + console.log(`Failed to write PDF to ${pdfPath}: `, error) +}) +``` + +## Planned Breaking API Changes (20.0) + +### Removed: macOS 10.11 / 10.12 support + +macOS 10.11 (El Capitan) and macOS 10.12 (Sierra) are no longer supported by [Chromium](https://chromium-review.googlesource.com/c/chromium/src/+/3646050). + +Older versions of Electron will continue to run on these operating systems, but macOS 10.13 (High Sierra) +or later will be required to run Electron v20.0.0 and higher. + +### Default Changed: renderers without `nodeIntegration: true` are sandboxed by default + +Previously, renderers that specified a preload script defaulted to being +unsandboxed. This meant that by default, preload scripts had access to Node.js. +In Electron 20, this default has changed. Beginning in Electron 20, renderers +will be sandboxed by default, unless `nodeIntegration: true` or `sandbox: false` +is specified. + +If your preload scripts do not depend on Node, no action is needed. If your +preload scripts _do_ depend on Node, either refactor them to remove Node usage +from the renderer, or explicitly specify `sandbox: false` for the relevant +renderers. + +### Removed: `skipTaskbar` on Linux + +On X11, `skipTaskbar` sends a `_NET_WM_STATE_SKIP_TASKBAR` message to the X11 +window manager. There is not a direct equivalent for Wayland, and the known +workarounds have unacceptable tradeoffs (e.g. Window.is_skip_taskbar in GNOME +requires unsafe mode), so Electron is unable to support this feature on Linux. + +### API Changed: `session.setDevicePermissionHandler(handler)` + +The handler invoked when `session.setDevicePermissionHandler(handler)` is used +has a change to its arguments. This handler no longer is passed a frame +[`WebFrameMain`](api/web-frame-main.md), but instead is passed the `origin`, which +is the origin that is checking for device permission. + +## Planned Breaking API Changes (19.0) + +### Removed: IA32 Linux binaries + +This is a result of Chromium 102.0.4999.0 dropping support for IA32 Linux. +This concludes the [removal of support for IA32 Linux](#removed-ia32-linux-support). + +## Planned Breaking API Changes (18.0) + +### Removed: `nativeWindowOpen` + +Prior to Electron 15, `window.open` was by default shimmed to use +`BrowserWindowProxy`. This meant that `window.open('about:blank')` did not work +to open synchronously scriptable child windows, among other incompatibilities. +Since Electron 15, `nativeWindowOpen` has been enabled by default. + +See the documentation for [window.open in Electron](api/window-open.md) +for more details. + +## Planned Breaking API Changes (17.0) + +### Removed: `desktopCapturer.getSources` in the renderer + +The `desktopCapturer.getSources` API is now only available in the main process. +This has been changed in order to improve the default security of Electron +apps. + +If you need this functionality, it can be replaced as follows: + +```js +// Main process +const { ipcMain, desktopCapturer } = require('electron') + +ipcMain.handle( + 'DESKTOP_CAPTURER_GET_SOURCES', + (event, opts) => desktopCapturer.getSources(opts) +) +``` + +```js +// Renderer process +const { ipcRenderer } = require('electron') + +const desktopCapturer = { + getSources: (opts) => ipcRenderer.invoke('DESKTOP_CAPTURER_GET_SOURCES', opts) +} +``` + +However, you should consider further restricting the information returned to +the renderer; for instance, displaying a source selector to the user and only +returning the selected source. + +### Deprecated: `nativeWindowOpen` + +Prior to Electron 15, `window.open` was by default shimmed to use +`BrowserWindowProxy`. This meant that `window.open('about:blank')` did not work +to open synchronously scriptable child windows, among other incompatibilities. +Since Electron 15, `nativeWindowOpen` has been enabled by default. + +See the documentation for [window.open in Electron](api/window-open.md) +for more details. + +## Planned Breaking API Changes (16.0) + +### Behavior Changed: `crashReporter` implementation switched to Crashpad on Linux + +The underlying implementation of the `crashReporter` API on Linux has changed +from Breakpad to Crashpad, bringing it in line with Windows and Mac. As a +result of this, child processes are now automatically monitored, and calling +`process.crashReporter.start` in Node child processes is no longer needed (and +is not advisable, as it will start a second instance of the Crashpad reporter). + +There are also some subtle changes to how annotations will be reported on +Linux, including that long values will no longer be split between annotations +appended with `__1`, `__2` and so on, and instead will be truncated at the +(new, longer) annotation value limit. + +### Deprecated: `desktopCapturer.getSources` in the renderer + +Usage of the `desktopCapturer.getSources` API in the renderer has been +deprecated and will be removed. This change improves the default security of +Electron apps. + +See [here](#removed-desktopcapturergetsources-in-the-renderer) for details on +how to replace this API in your app. + +## Planned Breaking API Changes (15.0) + +### Default Changed: `nativeWindowOpen` defaults to `true` + +Prior to Electron 15, `window.open` was by default shimmed to use +`BrowserWindowProxy`. This meant that `window.open('about:blank')` did not work +to open synchronously scriptable child windows, among other incompatibilities. +`nativeWindowOpen` is no longer experimental, and is now the default. + +See the documentation for [window.open in Electron](api/window-open.md) +for more details. + +### Deprecated: `app.runningUnderRosettaTranslation` + +The `app.runningUnderRosettaTranslation` property has been deprecated. +Use `app.runningUnderARM64Translation` instead. + +```js +// Deprecated +console.log(app.runningUnderRosettaTranslation) +// Replace with +console.log(app.runningUnderARM64Translation) +``` + +## Planned Breaking API Changes (14.0) + +### Removed: `remote` module + +The `remote` module was deprecated in Electron 12, and will be removed in +Electron 14. It is replaced by the +[`@electron/remote`](https://github.com/electron/remote) module. + +```js +// Deprecated in Electron 12: +const { BrowserWindow } = require('electron').remote +``` + +```js +// Replace with: +const { BrowserWindow } = require('@electron/remote') + +// In the main process: +require('@electron/remote/main').initialize() +``` + +### Removed: `app.allowRendererProcessReuse` + +The `app.allowRendererProcessReuse` property will be removed as part of our plan to +more closely align with Chromium's process model for security, performance and maintainability. + +For more detailed information see [#18397](https://github.com/electron/electron/issues/18397). + +### Removed: Browser Window Affinity + +The `affinity` option when constructing a new `BrowserWindow` will be removed +as part of our plan to more closely align with Chromium's process model for security, +performance and maintainability. + +For more detailed information see [#18397](https://github.com/electron/electron/issues/18397). + +### API Changed: `window.open()` + +The optional parameter `frameName` will no longer set the title of the window. This now follows the specification described by the [native documentation](https://developer.mozilla.org/en-US/docs/Web/API/Window/open#parameters) under the corresponding parameter `windowName`. + +If you were using this parameter to set the title of a window, you can instead use [win.setTitle(title)](api/browser-window.md#winsettitletitle). + +### Removed: `worldSafeExecuteJavaScript` + +In Electron 14, `worldSafeExecuteJavaScript` will be removed. There is no alternative, please +ensure your code works with this property enabled. It has been enabled by default since Electron +12. + +You will be affected by this change if you use either `webFrame.executeJavaScript` or `webFrame.executeJavaScriptInIsolatedWorld`. You will need to ensure that values returned by either of those methods are supported by the [Context Bridge API](api/context-bridge.md#parameter--error--return-type-support) as these methods use the same value passing semantics. + +### Removed: BrowserWindowConstructorOptions inheriting from parent windows + +Prior to Electron 14, windows opened with `window.open` would inherit +BrowserWindow constructor options such as `transparent` and `resizable` from +their parent window. Beginning with Electron 14, this behavior is removed, and +windows will not inherit any BrowserWindow constructor options from their +parents. + +Instead, explicitly set options for the new window with `setWindowOpenHandler`: + +```js +webContents.setWindowOpenHandler((details) => { + return { + action: 'allow', + overrideBrowserWindowOptions: { + // ... + } + } +}) +``` + +### Removed: `additionalFeatures` + +The deprecated `additionalFeatures` property in the `new-window` and +`did-create-window` events of WebContents has been removed. Since `new-window` +uses positional arguments, the argument is still present, but will always be +the empty array `[]`. (Though note, the `new-window` event itself is +deprecated, and is replaced by `setWindowOpenHandler`.) Bare keys in window +features will now present as keys with the value `true` in the options object. + +```js +// Removed in Electron 14 +// Triggered by window.open('...', '', 'my-key') +webContents.on('did-create-window', (window, details) => { + if (details.additionalFeatures.includes('my-key')) { + // ... + } +}) + +// Replace with +webContents.on('did-create-window', (window, details) => { + if (details.options['my-key']) { + // ... + } +}) +``` ## Planned Breaking API Changes (13.0) +### API Changed: `session.setPermissionCheckHandler(handler)` + +The `handler` methods first parameter was previously always a `webContents`, it can now sometimes be `null`. You should use the `requestingOrigin`, `embeddingOrigin` and `securityOrigin` properties to respond to the permission check correctly. As the `webContents` can be `null` it can no longer be relied on. + +```js +// Old code +session.setPermissionCheckHandler((webContents, permission) => { + if (webContents.getURL().startsWith('https://google.com/') && permission === 'notification') { + return true + } + return false +}) + +// Replace with +session.setPermissionCheckHandler((webContents, permission, requestingOrigin) => { + if (new URL(requestingOrigin).hostname === 'google.com' && permission === 'notification') { + return true + } + return false +}) +``` + ### Removed: `shell.moveItemToTrash()` The deprecated synchronous `shell.moveItemToTrash()` API has been removed. Use @@ -26,6 +1675,94 @@ shell.moveItemToTrash(path) shell.trashItem(path).then(/* ... */) ``` +### Removed: `BrowserWindow` extension APIs + +The deprecated extension APIs have been removed: + +* `BrowserWindow.addExtension(path)` +* `BrowserWindow.addDevToolsExtension(path)` +* `BrowserWindow.removeExtension(name)` +* `BrowserWindow.removeDevToolsExtension(name)` +* `BrowserWindow.getExtensions()` +* `BrowserWindow.getDevToolsExtensions()` + +Use the session APIs instead: + +* `ses.loadExtension(path)` +* `ses.removeExtension(extension_id)` +* `ses.getAllExtensions()` + +```js +// Removed in Electron 13 +BrowserWindow.addExtension(path) +BrowserWindow.addDevToolsExtension(path) +// Replace with +session.defaultSession.loadExtension(path) +``` + +```js +// Removed in Electron 13 +BrowserWindow.removeExtension(name) +BrowserWindow.removeDevToolsExtension(name) +// Replace with +session.defaultSession.removeExtension(extension_id) +``` + +```js +// Removed in Electron 13 +BrowserWindow.getExtensions() +BrowserWindow.getDevToolsExtensions() +// Replace with +session.defaultSession.getAllExtensions() +``` + +### Removed: methods in `systemPreferences` + +The following `systemPreferences` methods have been deprecated: + +* `systemPreferences.isDarkMode()` +* `systemPreferences.isInvertedColorScheme()` +* `systemPreferences.isHighContrastColorScheme()` + +Use the following `nativeTheme` properties instead: + +* `nativeTheme.shouldUseDarkColors` +* `nativeTheme.shouldUseInvertedColorScheme` +* `nativeTheme.shouldUseHighContrastColors` + +```js +// Removed in Electron 13 +systemPreferences.isDarkMode() +// Replace with +nativeTheme.shouldUseDarkColors + +// Removed in Electron 13 +systemPreferences.isInvertedColorScheme() +// Replace with +nativeTheme.shouldUseInvertedColorScheme + +// Removed in Electron 13 +systemPreferences.isHighContrastColorScheme() +// Replace with +nativeTheme.shouldUseHighContrastColors +``` + +### Deprecated: WebContents `new-window` event + +The `new-window` event of WebContents has been deprecated. It is replaced by [`webContents.setWindowOpenHandler()`](api/web-contents.md#contentssetwindowopenhandlerhandler). + +```js +// Deprecated in Electron 13 +webContents.on('new-window', (event) => { + event.preventDefault() +}) + +// Replace with +webContents.setWindowOpenHandler((details) => { + return { action: 'deny' } +}) +``` + ## Planned Breaking API Changes (12.0) ### Removed: Pepper Flash support @@ -34,26 +1771,50 @@ Chromium has removed support for Flash, and so we must follow suit. See Chromium's [Flash Roadmap](https://www.chromium.org/flash-roadmap) for more details. +### Default Changed: `worldSafeExecuteJavaScript` defaults to `true` + +In Electron 12, `worldSafeExecuteJavaScript` will be enabled by default. To restore +the previous behavior, `worldSafeExecuteJavaScript: false` must be specified in WebPreferences. +Please note that setting this option to `false` is **insecure**. + +This option will be removed in Electron 14 so please migrate your code to support the default +value. + ### Default Changed: `contextIsolation` defaults to `true` In Electron 12, `contextIsolation` will be enabled by default. To restore the previous behavior, `contextIsolation: false` must be specified in WebPreferences. -We [recommend having contextIsolation enabled](https://github.com/electron/electron/blob/master/docs/tutorial/security.md#3-enable-context-isolation-for-remote-content) for the security of your application. +We [recommend having contextIsolation enabled](tutorial/security.md#3-enable-context-isolation) for the security of your application. + +Another implication is that `require()` cannot be used in the renderer process unless +`nodeIntegration` is `true` and `contextIsolation` is `false`. For more details see: https://github.com/electron/electron/issues/23506 +### Removed: `crashReporter.getCrashesDirectory()` + +The `crashReporter.getCrashesDirectory` method has been removed. Usage +should be replaced by `app.getPath('crashDumps')`. + +```js +// Removed in Electron 12 +crashReporter.getCrashesDirectory() +// Replace with +app.getPath('crashDumps') +``` + ### Removed: `crashReporter` methods in the renderer process The following `crashReporter` methods are no longer available in the renderer process: -- `crashReporter.start` -- `crashReporter.getLastCrashReport` -- `crashReporter.getUploadedReports` -- `crashReporter.getUploadToServer` -- `crashReporter.setUploadToServer` -- `crashReporter.getCrashesDirectory` +* `crashReporter.start` +* `crashReporter.getLastCrashReport` +* `crashReporter.getUploadedReports` +* `crashReporter.getUploadToServer` +* `crashReporter.setUploadToServer` +* `crashReporter.getCrashesDirectory` They should be called only from the main process. @@ -144,12 +1905,12 @@ app.getPath('crashDumps') Calling the following `crashReporter` methods from the renderer process is deprecated: -- `crashReporter.start` -- `crashReporter.getLastCrashReport` -- `crashReporter.getUploadedReports` -- `crashReporter.getUploadToServer` -- `crashReporter.setUploadToServer` -- `crashReporter.getCrashesDirectory` +* `crashReporter.start` +* `crashReporter.getLastCrashReport` +* `crashReporter.getUploadedReports` +* `crashReporter.getUploadToServer` +* `crashReporter.setUploadToServer` +* `crashReporter.getCrashesDirectory` The only non-deprecated methods remaining in the `crashReporter` module in the renderer are `addExtraParameter`, `removeExtraParameter` and `getParameters`. @@ -164,14 +1925,6 @@ Setting `{ compress: false }` in `crashReporter.start` is deprecated. Nearly all crash ingestion servers support gzip compression. This option will be removed in a future version of Electron. -### Removed: Browser Window Affinity - -The `affinity` option when constructing a new `BrowserWindow` will be removed -as part of our plan to more closely align with Chromium's process model for security, -performance and maintainability. - -For more detailed information see [#18397](https://github.com/electron/electron/issues/18397). - ### Default Changed: `enableRemoteModule` defaults to `false` In Electron 9, using the remote module without explicitly enabling it via the @@ -187,8 +1940,7 @@ const w = new BrowserWindow({ }) ``` -We [recommend moving away from the remote -module](https://medium.com/@nornagon/electrons-remote-module-considered-harmful-70d69500f31). +We [recommend moving away from the remote module](https://medium.com/@nornagon/electrons-remote-module-considered-harmful-70d69500f31). ### `protocol.unregisterProtocol` @@ -196,7 +1948,7 @@ module](https://medium.com/@nornagon/electrons-remote-module-considered-harmful- The APIs are now synchronous and the optional callback is no longer needed. -```javascript +```js // Deprecated protocol.unregisterProtocol(scheme, () => { /* ... */ }) // Replace with @@ -225,7 +1977,7 @@ protocol.unregisterProtocol(scheme) The APIs are now synchronous and the optional callback is no longer needed. -```javascript +```js // Deprecated protocol.registerFileProtocol(scheme, handler, () => { /* ... */ }) // Replace with @@ -240,7 +1992,7 @@ until navigation happens. This API is deprecated and users should use `protocol.isProtocolRegistered` and `protocol.isProtocolIntercepted` instead. -```javascript +```js // Deprecated protocol.isProtocolHandled(scheme).then(() => { /* ... */ }) // Replace with @@ -262,6 +2014,47 @@ you should plan to update your native modules to be context aware. For more detailed information see [#18397](https://github.com/electron/electron/issues/18397). +### Deprecated: `BrowserWindow` extension APIs + +The following extension APIs have been deprecated: + +* `BrowserWindow.addExtension(path)` +* `BrowserWindow.addDevToolsExtension(path)` +* `BrowserWindow.removeExtension(name)` +* `BrowserWindow.removeDevToolsExtension(name)` +* `BrowserWindow.getExtensions()` +* `BrowserWindow.getDevToolsExtensions()` + +Use the session APIs instead: + +* `ses.loadExtension(path)` +* `ses.removeExtension(extension_id)` +* `ses.getAllExtensions()` + +```js +// Deprecated in Electron 9 +BrowserWindow.addExtension(path) +BrowserWindow.addDevToolsExtension(path) +// Replace with +session.defaultSession.loadExtension(path) +``` + +```js +// Deprecated in Electron 9 +BrowserWindow.removeExtension(name) +BrowserWindow.removeDevToolsExtension(name) +// Replace with +session.defaultSession.removeExtension(extension_id) +``` + +```js +// Deprecated in Electron 9 +BrowserWindow.getExtensions() +BrowserWindow.getDevToolsExtensions() +// Replace with +session.defaultSession.getAllExtensions() +``` + ### Removed: `<webview>.getWebContents()` This API, which was deprecated in Electron 8.0, is now removed. @@ -301,20 +2094,19 @@ error. ### API Changed: `shell.openItem` is now `shell.openPath` The `shell.openItem` API has been replaced with an asynchronous `shell.openPath` API. -You can see the original API proposal and reasoning [here](https://github.com/electron/governance/blob/master/wg-api/spec-documents/shell-openitem.md). +You can see the original API proposal and reasoning [here](https://github.com/electron/governance/blob/main/wg-api/spec-documents/shell-openitem.md). ## Planned Breaking API Changes (8.0) ### Behavior Changed: Values sent over IPC are now serialized with Structured Clone Algorithm -The algorithm used to serialize objects sent over IPC (through -`ipcRenderer.send`, `ipcRenderer.sendSync`, `WebContents.send` and related -methods) has been switched from a custom algorithm to V8's built-in [Structured -Clone Algorithm][SCA], the same algorithm used to serialize messages for -`postMessage`. This brings about a 2x performance improvement for large -messages, but also brings some breaking changes in behavior. +The algorithm used to serialize objects sent over IPC (through `ipcRenderer.send`, +`ipcRenderer.sendSync`, `WebContents.send` and related methods) has been switched from a custom +algorithm to V8's built-in [Structured Clone Algorithm][SCA], the same algorithm used to serialize +messages for `postMessage`. This brings about a 2x performance improvement for large messages, +but also brings some breaking changes in behavior. -- Sending Functions, Promises, WeakMaps, WeakSets, or objects containing any +* Sending Functions, Promises, WeakMaps, WeakSets, or objects containing any such values, over IPC will now throw an exception, instead of silently converting the functions to `undefined`. @@ -328,21 +2120,21 @@ ipcRenderer.send('channel', { value: 3, someFunction: () => {} }) // => throws Error("() => {} could not be cloned.") ``` -- `NaN`, `Infinity` and `-Infinity` will now be correctly serialized, instead +* `NaN`, `Infinity` and `-Infinity` will now be correctly serialized, instead of being converted to `null`. -- Objects containing cyclic references will now be correctly serialized, +* Objects containing cyclic references will now be correctly serialized, instead of being converted to `null`. -- `Set`, `Map`, `Error` and `RegExp` values will be correctly serialized, +* `Set`, `Map`, `Error` and `RegExp` values will be correctly serialized, instead of being converted to `{}`. -- `BigInt` values will be correctly serialized, instead of being converted to +* `BigInt` values will be correctly serialized, instead of being converted to `null`. -- Sparse arrays will be serialized as such, instead of being converted to dense +* Sparse arrays will be serialized as such, instead of being converted to dense arrays with `null`s. -- `Date` objects will be transferred as `Date` objects, instead of being +* `Date` objects will be transferred as `Date` objects, instead of being converted to their ISO string representation. -- Typed Arrays (such as `Uint8Array`, `Uint16Array`, `Uint32Array` and so on) +* Typed Arrays (such as `Uint8Array`, `Uint16Array`, `Uint32Array` and so on) will be transferred as such, instead of being converted to Node.js `Buffer`. -- Node.js `Buffer` objects will be transferred as `Uint8Array`s. You can +* Node.js `Buffer` objects will be transferred as `Uint8Array`s. You can convert a `Uint8Array` back to a Node.js `Buffer` by wrapping the underlying `ArrayBuffer`: @@ -408,6 +2200,55 @@ in Electron 8.x, and cease to exist in Electron 9.x. The layout zoom level limits are now fixed at a minimum of 0.25 and a maximum of 5.0, as defined [here](https://chromium.googlesource.com/chromium/src/+/938b37a6d2886bf8335fc7db792f1eb46c65b2ae/third_party/blink/common/page/page_zoom.cc#11). +### Deprecated events in `systemPreferences` + +The following `systemPreferences` events have been deprecated: + +* `inverted-color-scheme-changed` +* `high-contrast-color-scheme-changed` + +Use the new `updated` event on the `nativeTheme` module instead. + +```js +// Deprecated +systemPreferences.on('inverted-color-scheme-changed', () => { /* ... */ }) +systemPreferences.on('high-contrast-color-scheme-changed', () => { /* ... */ }) + +// Replace with +nativeTheme.on('updated', () => { /* ... */ }) +``` + +### Deprecated: methods in `systemPreferences` + +The following `systemPreferences` methods have been deprecated: + +* `systemPreferences.isDarkMode()` +* `systemPreferences.isInvertedColorScheme()` +* `systemPreferences.isHighContrastColorScheme()` + +Use the following `nativeTheme` properties instead: + +* `nativeTheme.shouldUseDarkColors` +* `nativeTheme.shouldUseInvertedColorScheme` +* `nativeTheme.shouldUseHighContrastColors` + +```js +// Deprecated +systemPreferences.isDarkMode() +// Replace with +nativeTheme.shouldUseDarkColors + +// Deprecated +systemPreferences.isInvertedColorScheme() +// Replace with +nativeTheme.shouldUseInvertedColorScheme + +// Deprecated +systemPreferences.isHighContrastColorScheme() +// Replace with +nativeTheme.shouldUseHighContrastColors +``` + ## Planned Breaking API Changes (7.0) ### Deprecated: Atom.io Node Headers URL @@ -489,7 +2330,7 @@ folder └── file3 ``` -In Electron <=6, this would return a `FileList` with a `File` object for: +In Electron <=6, this would return a `FileList` with a `File` object for: ```console path/to/folder @@ -505,7 +2346,56 @@ In Electron 7, this now returns a `FileList` with a `File` object for: Note that `webkitdirectory` no longer exposes the path to the selected folder. If you require the path to the selected folder rather than the folder contents, -see the `dialog.showOpenDialog` API ([link](https://github.com/electron/electron/blob/master/docs/api/dialog.md#dialogshowopendialogbrowserwindow-options)). +see the `dialog.showOpenDialog` API ([link](api/dialog.md#dialogshowopendialogwindow-options)). + +### API Changed: Callback-based versions of promisified APIs + +Electron 5 and Electron 6 introduced Promise-based versions of existing +asynchronous APIs and deprecated their older, callback-based counterparts. +In Electron 7, all deprecated callback-based APIs are now removed. + +These functions now only return Promises: + +* `app.getFileIcon()` [#15742](https://github.com/electron/electron/pull/15742) +* `app.dock.show()` [#16904](https://github.com/electron/electron/pull/16904) +* `contentTracing.getCategories()` [#16583](https://github.com/electron/electron/pull/16583) +* `contentTracing.getTraceBufferUsage()` [#16600](https://github.com/electron/electron/pull/16600) +* `contentTracing.startRecording()` [#16584](https://github.com/electron/electron/pull/16584) +* `contentTracing.stopRecording()` [#16584](https://github.com/electron/electron/pull/16584) +* `contents.executeJavaScript()` [#17312](https://github.com/electron/electron/pull/17312) +* `cookies.flushStore()` [#16464](https://github.com/electron/electron/pull/16464) +* `cookies.get()` [#16464](https://github.com/electron/electron/pull/16464) +* `cookies.remove()` [#16464](https://github.com/electron/electron/pull/16464) +* `cookies.set()` [#16464](https://github.com/electron/electron/pull/16464) +* `debugger.sendCommand()` [#16861](https://github.com/electron/electron/pull/16861) +* `dialog.showCertificateTrustDialog()` [#17181](https://github.com/electron/electron/pull/17181) +* `inAppPurchase.getProducts()` [#17355](https://github.com/electron/electron/pull/17355) +* `inAppPurchase.purchaseProduct()`[#17355](https://github.com/electron/electron/pull/17355) +* `netLog.stopLogging()` [#16862](https://github.com/electron/electron/pull/16862) +* `session.clearAuthCache()` [#17259](https://github.com/electron/electron/pull/17259) +* `session.clearCache()` [#17185](https://github.com/electron/electron/pull/17185) +* `session.clearHostResolverCache()` [#17229](https://github.com/electron/electron/pull/17229) +* `session.clearStorageData()` [#17249](https://github.com/electron/electron/pull/17249) +* `session.getBlobData()` [#17303](https://github.com/electron/electron/pull/17303) +* `session.getCacheSize()` [#17185](https://github.com/electron/electron/pull/17185) +* `session.resolveProxy()` [#17222](https://github.com/electron/electron/pull/17222) +* `session.setProxy()` [#17222](https://github.com/electron/electron/pull/17222) +* `shell.openExternal()` [#16176](https://github.com/electron/electron/pull/16176) +* `webContents.loadFile()` [#15855](https://github.com/electron/electron/pull/15855) +* `webContents.loadURL()` [#15855](https://github.com/electron/electron/pull/15855) +* `webContents.hasServiceWorker()` [#16535](https://github.com/electron/electron/pull/16535) +* `webContents.printToPDF()` [#16795](https://github.com/electron/electron/pull/16795) +* `webContents.savePage()` [#16742](https://github.com/electron/electron/pull/16742) +* `webFrame.executeJavaScript()` [#17312](https://github.com/electron/electron/pull/17312) +* `webFrame.executeJavaScriptInIsolatedWorld()` [#17312](https://github.com/electron/electron/pull/17312) +* `webviewTag.executeJavaScript()` [#17312](https://github.com/electron/electron/pull/17312) +* `win.capturePage()` [#15743](https://github.com/electron/electron/pull/15743) + +These functions now have two forms, synchronous and Promise-based asynchronous: + +* `dialog.showMessageBox()`/`dialog.showMessageBoxSync()` [#17298](https://github.com/electron/electron/pull/17298) +* `dialog.showOpenDialog()`/`dialog.showOpenDialogSync()` [#16973](https://github.com/electron/electron/pull/16973) +* `dialog.showSaveDialog()`/`dialog.showSaveDialogSync()` [#17054](https://github.com/electron/electron/pull/17054) ## Planned Breaking API Changes (6.0) @@ -518,19 +2408,6 @@ win.setMenu(null) win.removeMenu() ``` -### API Changed: `contentTracing.getTraceBufferUsage()` is now a promise - -```js -// Deprecated -contentTracing.getTraceBufferUsage((percentage, value) => { - // do something -}) -// Replace with -contentTracing.getTraceBufferUsage().then(infoObject => { - // infoObject has percentage and value fields -}) -``` - ### API Changed: `electron.screen` in the renderer process should be accessed via `remote` ```js @@ -669,6 +2546,31 @@ webFrame.setSpellCheckProvider('en-US', { }) ``` +### API Changed: `webContents.getZoomLevel` and `webContents.getZoomFactor` are now synchronous + +`webContents.getZoomLevel` and `webContents.getZoomFactor` no longer take callback parameters, +instead directly returning their number values. + +```js +// Deprecated +webContents.getZoomLevel((level) => { + console.log(level) +}) +// Replace with +const level = webContents.getZoomLevel() +console.log(level) +``` + +```js +// Deprecated +webContents.getZoomFactor((factor) => { + console.log(factor) +}) +// Replace with +const factor = webContents.getZoomFactor() +console.log(factor) +``` + ## Planned Breaking API Changes (4.0) The following list includes the breaking API changes made in Electron 4.0. @@ -709,8 +2611,12 @@ app.getGPUInfo('basic') When building native modules for windows, the `win_delay_load_hook` variable in the module's `binding.gyp` must be true (which is the default). If this hook is not present, then the native module will fail to load on Windows, with an error -message like `Cannot find module`. See the [native module -guide](/docs/tutorial/using-native-node-modules.md) for more. +message like `Cannot find module`. +See the [native module guide](./tutorial/using-native-node-modules.md) for more. + +### Removed: IA32 Linux support + +Electron 18 will no longer run on 32-bit Linux systems. See [discontinuing support for 32-bit Linux](https://www.electronjs.org/blog/linux-32bit-support) for more information. ## Breaking API Changes (3.0) @@ -904,6 +2810,18 @@ Replace with: https://atom.io/download/electron The following list includes the breaking API changes made in Electron 2.0. +### `autoUpdater` + +```js +// Deprecated +autoUpdater.setFeedURL(url, headers) +// Replace with +autoUpdater.setFeedURL({ + url, + headers +}) +``` + ### `BrowserWindow` ```js diff --git a/docs/development/README.md b/docs/development/README.md index f5c9d6073fa1f..2fcb45e965731 100644 --- a/docs/development/README.md +++ b/docs/development/README.md @@ -4,23 +4,77 @@ These guides are intended for people working on the Electron project itself. For guides on Electron app development, see [/docs/README.md](../README.md#guides-and-tutorials). -* [Code of Conduct](https://github.com/electron/electron/blob/master/CODE_OF_CONDUCT.md) -* [Contributing to Electron](https://github.com/electron/electron/blob/master/CONTRIBUTING.md) +## Table of Contents + * [Issues](issues.md) * [Pull Requests](pull-requests.md) * [Documentation Styleguide](coding-style.md#documentation) * [Source Code Directory Structure](source-code-directory-structure.md) * [Coding Style](coding-style.md) -* [Using clang-format on C++ Code](clang-format.md) * [Using clang-tidy on C++ Code](clang-tidy.md) -* [Build System Overview](build-system-overview.md) -* [Build Instructions (macOS)](build-instructions-macos.md) -* [Build Instructions (Windows)](build-instructions-windows.md) -* [Build Instructions (Linux)](build-instructions-linux.md) +* [Build Instructions](build-instructions-gn.md) + * [macOS](build-instructions-macos.md) + * [Windows](build-instructions-windows.md) + * [Linux](build-instructions-linux.md) * [Chromium Development](chromium-development.md) * [V8 Development](v8-development.md) * [Testing](testing.md) -* [Debugging on Windows](debug-instructions-windows.md) -* [Debugging on macOS](debugging-instructions-macos.md) -* [Setting Up Symbol Server in Debugger](setting-up-symbol-server.md) +* [Debugging](debugging.md) * [Patches](patches.md) + +## Getting Started + +In order to contribute to Electron, the first thing you'll want to do is get the code. + +[Electron's `build-tools`](https://github.com/electron/build-tools) automate much of the setup for compiling Electron from source with different configurations and build targets. + +If you would prefer to build Electron manually, see the [build instructions](build-instructions-gn.md). + +Once you've checked out and built the code, you may want to take a look around the source tree to get a better idea +of what each directory is responsible for. The [source code directory structure](source-code-directory-structure.md) gives a good overview of the purpose of each directory. + +## Opening Issues on Electron + +For any issue, there are generally three ways an individual can contribute: + +1. By opening the issue for discussion + * If you believe that you have found a new bug in Electron, you should report it by creating a new issue in + the [`electron/electron` issue tracker](https://github.com/electron/electron/issues). +2. By helping to triage the issue + * You can do this either by providing assistive details (a reproducible test case that demonstrates a bug) or by providing suggestions to address the issue. +3. By helping to resolve the issue + * This can be done by demonstrating that the issue is not a bug or is fixed; + but more often, by opening a pull request that changes the source in `electron/electron` + in a concrete and reviewable manner. + +See [issues](issues.md) for more information. + +## Making a Pull Request to Electron + +Most pull requests opened against the `electron/electron` repository include +changes to either the C/C++ code in the `shell/` folder, +the TypeScript code in the `lib/` folder, the documentation in `docs/`, +or tests in the `spec/` folder. + +See [pull requests](pull-requests.md) for more information. + +If you want to add a new API module to Electron, you'll want to look in [creating API](creating-api.md). + +## Governance + +Electron has a fully-fledged governance system that oversees activity in Electron and whose working groups are responsible for areas like APIs, releases, and upgrades to Electron's dependencies including Chromium and Node.js. Depending on how frequently and to what end you want to contribute, you may want to consider joining a working group. + +Details about each group and their responsibilities can be found in the [governance repo](https://github.com/electron/governance). + +## Patches in Electron + +Electron is built on two major upstream projects: Chromium and Node.js. Each of these projects has several of their own dependencies, too. We try our best to use these dependencies exactly as they are but sometimes we can't achieve our goals without patching those upstream dependencies to fit our use cases. + +As such, we maintain a collection of patches as part of our source tree. The process for adding or altering one of these patches to Electron's source tree via a pull request can be found in [patches](patches.md). + +## Debugging + +There are many different approaches to debugging issues and bugs in Electron, many of which +are platform specific. + +For an overview of information related to debugging Electron itself (and not an app _built with Electron_), see [debugging](debugging.md). diff --git a/docs/development/api-history-migration-guide.md b/docs/development/api-history-migration-guide.md new file mode 100644 index 0000000000000..0c1ae7c54a25e --- /dev/null +++ b/docs/development/api-history-migration-guide.md @@ -0,0 +1,190 @@ +# Electron API History Migration Guide + +This document demonstrates how to add API History blocks to existing APIs. + +## API history information + +Here are some resources you can use to find information on the history of an API: + +### Breaking Changes + +* [`breaking-changes.md`](../breaking-changes.md) + +### Additions + +* `git blame` +* [Release notes](https://github.com/electron/electron/releases/) +* [`electron-api-historian`](https://github.com/electron/electron-api-historian) + +## Example + +> [!NOTE] +> The associated API is already removed, we will ignore that for the purpose of +> this example. + +If we search through [`breaking-changes.md`](../breaking-changes.md) we can find +[a function that was deprecated in Electron `25.0`](../breaking-changes.md#deprecated-browserwindowsettrafficlightpositionposition). + +```markdown +<!-- docs/breaking-changes.md --> +### Deprecated: `BrowserWindow.getTrafficLightPosition()` + +`BrowserWindow.getTrafficLightPosition()` has been deprecated, the +`BrowserWindow.getWindowButtonPosition()` API should be used instead +which returns `null` instead of `{ x: 0, y: 0 }` when there is no custom +position. + +<!-- docs/api/browser-window.md --> +#### `win.getTrafficLightPosition()` _macOS_ _Deprecated_ + +Returns `Point` - The custom position for the traffic light buttons in +frameless window, `{ x: 0, y: 0 }` will be returned when there is no custom +position. +``` + +We can then use `git blame` to find the Pull Request associated with that entry: + +```bash +$ grep -n "BrowserWindow.getTrafficLightPosition" docs/breaking-changes.md +523:### Deprecated: `BrowserWindow.getTrafficLightPosition()` +525:`BrowserWindow.getTrafficLightPosition()` has been deprecated, the + +$ git blame -L523,524 -- docs/breaking-changes.md +1e206deec3e (Keeley Hammond 2023-04-06 21:23:29 -0700 523) ### Deprecated: `BrowserWindow.getTrafficLightPosition()` +1e206deec3e (Keeley Hammond 2023-04-06 21:23:29 -0700 524) + +$ git log -1 1e206deec3e +commit 1e206deec3ef142460c780307752a84782f9baed (tag: v26.0.0-nightly.20230407) +Author: Keeley Hammond <vertedinde@electronjs.org> +Date: Thu Apr 6 21:23:29 2023 -0700 + + docs: update E24/E25 breaking changes (#37878) <-- This is the associated Pull Request +``` + +Verify that the Pull Request is correct and make a corresponding entry in the +API History: + +> [!NOTE] +> Refer to the [API History section of `style-guide.md`](./style-guide.md#api-history) +for information on how to create API History blocks. + +`````markdown +#### `win.getTrafficLightPosition()` _macOS_ _Deprecated_ + +<!-- +```YAML history +deprecated: + - pr-url: https://github.com/electron/electron/pull/37878 + breaking-changes-header: deprecated-browserwindowgettrafficlightposition +``` +--> + +Returns `Point` - The custom position for the traffic light buttons in +frameless window, `{ x: 0, y: 0 }` will be returned when there is no custom +position. +````` + +You can keep looking through `breaking-changes.md` to find other breaking changes +and add those in. + +You can also use [`git log -L :<funcname>:<file>`](https://git-scm.com/docs/git-log#Documentation/git-log.txt--Lltfuncnamegtltfilegt): + +```bash +$ git log --reverse -L :GetTrafficLightPosition:shell/browser/native_window_mac.mm +commit e01b1831d96d5d68f54af879b00c617358df5372 +Author: Cheng Zhao <zcbenz@gmail.com> +Date: Wed Dec 16 14:30:39 2020 +0900 + + feat: make trafficLightPosition work for customButtonOnHover (#26789) +``` + +Verify that the Pull Request is correct and make a corresponding entry in the +API History: + +`````markdown +#### `win.getTrafficLightPosition()` _macOS_ _Deprecated_ + +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/22533 +changes: + - pr-url: https://github.com/electron/electron/pull/26789 + description: "Made `trafficLightPosition` option work for `customButtonOnHover` window." + breaking-changes-header: behavior-changed-draggable-regions-on-macos +``` +--> + +Returns `Point` - The custom position for the traffic light buttons in +frameless window, `{ x: 0, y: 0 }` will be returned when there is no custom +position. +````` + +We will then look for when the API was originally added: + +```bash +$ git log --reverse -L :GetTrafficLightPosition:shell/browser/native_window_mac.mm +commit 3e2cec83d927b991855e21cc311ca9046e332601 +Author: Samuel Attard <sattard@slack-corp.com> +Date: Thu Mar 5 14:22:12 2020 -0800 + + feat: programmatically modify traffic light positioning (#22533) +``` + +Alternatively, you can use `git blame`: + +```bash +$ git checkout 1e206deec3e^ +HEAD is now at e8c87859c4 fix: showAboutPanel also on linux (#37828) + +$ grep -n "getTrafficLightPosition" docs/api/browser-window.md +1867:#### `win.getTrafficLightPosition()` _macOS_ _Deprecated_ + +$ git blame -L1867,1868 -- docs/api/browser-window.md +0de1012280e (Cheng Zhao 2023-02-17 19:06:32 +0900 1867) #### `win.getTrafficLightPosition()` _macOS_ _Deprecated_ +3e2cec83d92 (Samuel Attard 2020-03-05 14:22:12 -0800 1868) + +$ git checkout 0de1012280e^ +HEAD is now at 0a5e634736 test: rename & split internal module tests (#37318) + +$ grep -n "getTrafficLightPosition" docs/api/browser-window.md +1851:#### `win.getTrafficLightPosition()` _macOS_ + +$ git blame -L1851,1852 -- docs/api/browser-window.md +3e2cec83d92 (Samuel Attard 2020-03-05 14:22:12 -0800 1851) #### `win.getTrafficLightPosition()` _macOS_ +3e2cec83d92 (Samuel Attard 2020-03-05 14:22:12 -0800 1852) + +$ git checkout 3e2cec83d92^ +HEAD is now at 1811751c6c docs: clean up dark mode related docs (#22489) + +$ grep -n "getTrafficLightPosition" docs/api/browser-window.md +(Nothing) + +$ git checkout 3e2cec83d92 +HEAD is now at 3e2cec83d9 feat: programmatically modify traffic light positioning (#22533) +``` + +Verify that the Pull Request is correct and make a corresponding entry in the +API History: + +`````markdown +#### `win.getTrafficLightPosition()` _macOS_ _Deprecated_ + +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/22533 +changes: + - pr-url: https://github.com/electron/electron/pull/26789 + description: "Made `trafficLightPosition` option work for `customButtonOnHover` window." + breaking-changes-header: behavior-changed-draggable-regions-on-macos +deprecated: + - pr-url: https://github.com/electron/electron/pull/37878 + breaking-changes-header: deprecated-browserwindowgettrafficlightposition +``` +--> + +Returns `Point` - The custom position for the traffic light buttons in +frameless window, `{ x: 0, y: 0 }` will be returned when there is no custom +position. +````` diff --git a/docs/development/azure-vm-setup.md b/docs/development/azure-vm-setup.md deleted file mode 100644 index c69aa5a064288..0000000000000 --- a/docs/development/azure-vm-setup.md +++ /dev/null @@ -1,62 +0,0 @@ -# Updating an Appveyor Azure Image - -Electron CI on Windows uses AppVeyor, which in turn uses Azure VM images to run. Occasionally, these VM images need to be updated due to changes in Chromium requirements. In order to update you will need [PowerShell](https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell?view=powershell-6) and the [Azure PowerShell module](https://docs.microsoft.com/en-us/powershell/azure/install-az-ps?view=azps-1.8.0&viewFallbackFrom=azurermps-6.13.0). - -Occasionally we need to update these images owing to changes in Chromium or other miscellaneous build requirement changes. - -Example Use Case: - * We need `VS15.9` and we have `VS15.7` installed; this would require us to update an Azure image. - -1. Identify the image you wish to modify. - * In [appveyor.yml](https://github.com/electron/electron/blob/master/appveyor.yml), the image is identified by the property *image*. - * The names used correspond to the *"images"* defined for a build cloud, eg the [libcc-20 cloud](https://windows-ci.electronjs.org/build-clouds/8). - * Find the image you wish to modify in the build cloud and make note of the **VHD Blob Path** for that image, which is the value for that corresponding key. - * You will need this URI path to copy into a new image. - * You will also need the storage account name which is labeled in AppVeyor as the **Disk Storage Account Name** - -2. Get the Azure storage account key - * Log into Azure using credentials stored in LastPass (under Azure Enterprise) and then find the storage account corresponding to the name found in AppVeyor. - * Example, for `appveyorlibccbuilds` **Disk Storage Account Name** you'd look for `appveyorlibccbuilds` in the list of storage accounts @ Home < Storage Accounts - * Click into it and look for `Access Keys`, and then you can use any of the keys present in the list. - -3. Get the full virtual machine image URI from Azure - * Navigate to Home < Storage Accounts < `$ACCT_NAME` < Blobs < Images - * In the following list, look for the VHD path name you got from Appveyor and then click on it. - * Copy the whole URL from the top of the subsequent window. - -4. Copy the image using the [Copy Master Image PowerShell script](https://github.com/appveyor/ci/blob/master/scripts/enterprise/copy-master-image-azure.ps1). - * It is essential to copy the VM because if you spin up a VM against an image that image cannot at the same time be used by AppVeyor. - * Use the storage account name, key, and URI obtained from Azure to run this script. - * See Step 3 for URI & when prompted, press enter to use same storage account as destination. - * Use default destination container name `(images)` - * Also, when naming the copy, use a name that indicates what the new image will contain (if that has changed) and date stamp. - * Ex. `libcc-20core-vs2017-15.9-2019-04-15.vhd` - * Go into Azure and get the URI for the newly created image as described in a previous step - -5. Spin up a new VM using the [Create Master VM from VHD PowerShell](https://github.com/appveyor/ci/blob/master/scripts/enterprise/create_master_vm_from_vhd.ps1). - * From PowerShell, execute `ps1` file with `./create_master_vm_from_vhd.ps1` - * You will need the credential information available in the AppVeyor build cloud definition. - * This includes: - * Client ID - * Client Secret - * Tenant ID - * Subscription ID - * Resource Group - * Virtual Network - * You will also need to specify - * Master VM name - just a unique name to identify the temporary VM - * Master VM size - use `Standard_F32s_v2` - * Master VHD URI - use URI obtained @ end of previous step - * Location use `East US` - -6. Log back into Azure and find the VM you just created in Home < Virtual Machines < `$YOUR_NEW_VM` - * You can download a RDP (Remote Desktop) file to access the VM. - -7. Using Microsoft Remote Desktop, click `Connect` to connect to the VM. - * Credentials for logging into the VM are found in LastPass under the `AppVeyor Enterprise master VM` credentials. - -8. Modify the VM as required. - -9. Shut down the VM and then delete it in Azure. - -10. Add the new image to the Appveyor Cloud settings or modify an existing image to point to the new VHD. diff --git a/docs/development/build-instructions-gn.md b/docs/development/build-instructions-gn.md index 85b799a8272a6..4d1037f26bd7d 100644 --- a/docs/development/build-instructions-gn.md +++ b/docs/development/build-instructions-gn.md @@ -1,20 +1,109 @@ # Build Instructions -Follow the guidelines below for building Electron. +Follow the guidelines below for building **Electron itself**, for the purposes of creating custom Electron binaries. For bundling and distributing your app code with the prebuilt Electron binaries, see the [application distribution][application-distribution] guide. + +[application-distribution]: ../tutorial/application-distribution.md ## Platform prerequisites -Check the build prerequisites for your platform before proceeding +Check the build prerequisites for your platform before proceeding: * [macOS](build-instructions-macos.md#prerequisites) * [Linux](build-instructions-linux.md#prerequisites) * [Windows](build-instructions-windows.md#prerequisites) -## Build Tools +## Setting up `@electron/build-tools` (recommended) + +[Electron Build Tools](https://github.com/electron/build-tools) automate much of the setup for +compiling Electron from source with different configurations and build targets. +Most of the [manual setup](#manual-setup-advanced) instructions can be replaced by simpler Build Tools commands. + +> [!TIP] +> Build Tools also gives you access to [remote execution and caching of build actions](./reclient.md), +> which will dramatically improve build times. + +Electron Build Tools can be installed globally from npm: + +```sh +npm install -g @electron/build-tools +``` + +Once installed, the `e` command should be globally available in your command line. The `e init` +command bootstraps a local checkout of Electron: + +```sh +# The 'Hello, World!' of build-tools: get and build `main` +# Choose the directory where Electron's source and build files will reside. +# You can specify any path you like; this command defaults to `$PWD/electron`. +# If you're going to use multiple branches, you may want something like: +# `--root=~/electron/branch` (e.g. `~/electron-gn/main`) +e init --root=~/electron --bootstrap testing +``` + +The `--bootstrap` flag also runs `e sync` (synchronizes source code branches from +[`DEPS`](../../DEPS) using +[`gclient`](https://chromium.googlesource.com/chromium/tools/depot_tools.git/+/HEAD/README.gclient.md)) +and `e build` (compiles the Electron binary into the `${root}/src/out` folder). + +> [!IMPORTANT] +> +> Sometime after the initial `e sync` phase, you will be asked to run `e d rbe login` to auth into +> remote build execution and proceed into the build. This may take about 20-30 minutes! + +Once the build is done compiling, you can test it by running `e start` (or by loading it into +[Electron Fiddle](http://electronjs.org/fiddle)). -[Electron's Build Tools](https://github.com/electron/build-tools) automate much of the setup for compiling Electron from source with different configurations and build targets. If you wish to set up the environment manually, the instructions are listed below. +### Navigating the project -## GN prerequisites +Some quick tips on building once your checkout is set up: + +* **Directory structure:** Within the project, Chromium code is synced to `${root}/src/` while Electron's code (i.e. code in + https://github.com/electron/electron) lives in `${root}/src/electron/`. Note that both directories + have their own git repositories. +* **Updating your checkout:** Run git commands such as `git checkout <branch>` and `git pull` from `${root}/src/electron`. + Whenever you update your commit `HEAD`, make sure to `e sync` before `e build` to sync dependencies + such as Chromium and Node.js. This is especially relevant because the Chromium version in + [`DEPS`](../../DEPS) changes frequently. +* **Rebuilding:** When making changes to code in `${root}/src/electron/` in a local branch, you only need to re-run `e build`. +* **Adding patches:** When contributing changes in `${root}/src/` outside of `${root}/src/electron/`, you need to do so + via Electron's [patch system](./patches.md). The `e patches` command can export all relevant patches to + `${root}/src/electron/patches/` once your code change is ready. + +> [!IMPORTANT] +> Unless you're applying upstream patches, you should treat `${root}/src/` as a read-only folder and +> spend most of your development time in `${root}/src/electron/`. You should not need to make any +> changes or run `git` commands in `${root}/src/`. + +> [!TIP] +> Detailed documentation for all available `e` commands can be found in the +> repository's [README.md](https://github.com/electron/build-tools/blob/main/README.md). You can +> also run `e --help` to list all commands and use the `--help` flag on any command to get more +> usage info. + +> [!TIP] +> For more information on project structure, see the [Source Code Directory Structure](./source-code-directory-structure.md) +> guide. + +<details> +<!-- markdownlint-disable-next-line MD033 --> +<summary><strong>Manual setup (advanced)</strong></summary> + +## Manual setup (advanced) + +Electron uses [GN](https://gn.googlesource.com/gn) for project generation and +[siso](https://chromium.googlesource.com/build/+/refs/heads/main/siso/README.md) for building. +Project configurations can be found in the `.gn` and `.gni` files in the `electron/electron` repo. + +### GN files + +The following `gn` files contain the main rules for building Electron: + +* [`BUILD.gn`](../../BUILD.gn) defines how Electron itself + is built and includes the default configurations for linking with Chromium. +* [`build/args/{testing,release,all}.gn`](https://github.com/electron/electron/tree/main/build/args) + contain the default build arguments for building Electron. + +### GN prerequisites You'll need to install [`depot_tools`][depot-tools], the toolset used for fetching Chromium and its dependencies. @@ -41,7 +130,7 @@ $ mkdir -p "${GIT_CACHE_PATH}" # This will use about 16G. ``` -## Getting the code +### Getting the code ```sh $ mkdir electron && cd electron @@ -53,7 +142,7 @@ $ gclient sync --with_branch_heads --with_tags > Instead of `https://github.com/electron/electron`, you can use your own fork > here (something like `https://github.com/<username>/electron`). -### A note on pulling/pushing +#### A note on pulling/pushing If you intend to `git pull` or `git push` from the official `electron` repository in the future, you now need to update the respective folder's @@ -63,17 +152,18 @@ origin URLs. $ cd src/electron $ git remote remove origin $ git remote add origin https://github.com/electron/electron -$ git checkout master -$ git branch --set-upstream-to=origin/master +$ git checkout main +$ git branch --set-upstream-to=origin/main $ cd - ``` -:memo: `gclient` works by checking a file called `DEPS` inside the -`src/electron` folder for dependencies (like Chromium or Node.js). +> [!TIP] +> `gclient` works by checking a file called `DEPS` inside the +`${root}/src/electron` folder for dependencies (like Chromium or Node.js). Running `gclient sync -f` ensures that all dependencies required to build Electron match that file. -So, in order to pull, you'd run the following commands: +In order to pull, you'd run the following commands: ```sh $ cd src/electron @@ -81,49 +171,72 @@ $ git pull $ gclient sync -f ``` -## Building +### Building + +**Set the environment variable for chromium build tools** + +On Linux & MacOS ```sh $ cd src $ export CHROMIUM_BUILDTOOLS_PATH=`pwd`/buildtools -# this next line is needed only if building with sccache -$ export GN_EXTRA_ARGS="${GN_EXTRA_ARGS} cc_wrapper=\"${PWD}/electron/external_binaries/sccache\"" -$ gn gen out/Testing --args="import(\"//electron/build/args/testing.gn\") $GN_EXTRA_ARGS" ``` -Or on Windows (without the optional argument): +On Windows: ```sh +# cmd $ cd src $ set CHROMIUM_BUILDTOOLS_PATH=%cd%\buildtools + +# PowerShell +$ cd src +$ $env:CHROMIUM_BUILDTOOLS_PATH = "$(Get-Location)\buildtools" +``` + +**To generate Testing build config of Electron:** + +On Linux & MacOS + +```sh $ gn gen out/Testing --args="import(\"//electron/build/args/testing.gn\")" ``` -This will generate a build directory `out/Testing` under `src/` with -the testing build configuration. You can replace `Testing` with another name, -but it should be a subdirectory of `out`. -Also you shouldn't have to run `gn gen` again—if you want to change the -build arguments, you can run `gn args out/Testing` to bring up an editor. +On Windows: -To see the list of available build configuration options, run `gn args -out/Testing --list`. +```sh +# cmd +$ gn gen out/Testing --args="import(\"//electron/build/args/testing.gn\")" + +# PowerShell +gn gen out/Testing --args="import(\`"//electron/build/args/testing.gn\`")" +``` + +**To generate Release build config of Electron:** -**For generating Testing build config of -Electron:** +On Linux & MacOS ```sh -$ gn gen out/Testing --args="import(\"//electron/build/args/testing.gn\") $GN_EXTRA_ARGS" +$ gn gen out/Release --args="import(\"//electron/build/args/release.gn\")" ``` -**For generating Release (aka "non-component" or "static") build config of -Electron:** +On Windows: ```sh -$ gn gen out/Release --args="import(\"//electron/build/args/release.gn\") $GN_EXTRA_ARGS" +# cmd +$ gn gen out/Release --args="import(\"//electron/build/args/release.gn\")" + +# PowerShell +$ gn gen out/Release --args="import(\`"//electron/build/args/release.gn\`")" ``` +> [!NOTE] +> This will generate a `out/Testing` or `out/Release` build directory under `${root}/src/` with the testing or release build depending upon the configuration passed above. You can replace `Testing|Release` with another names, but it should be a subdirectory of `out`. + +Also you shouldn't have to run `gn gen` again—if you want to change the build arguments, you can run `gn args out/Testing` to bring up an editor. To see the list of available build configuration options, run `gn args out/Testing --list`. + **To build, run `ninja` with the `electron` target:** -Nota Bene: This will also take a while and probably heat up your lap. +Note: This will also take a while and probably heat up your lap. For the testing configuration: @@ -138,15 +251,9 @@ $ ninja -C out/Release electron ``` This will build all of what was previously 'libchromiumcontent' (i.e. the -`content/` directory of `chromium` and its dependencies, incl. WebKit and V8), +`content/` directory of `chromium` and its dependencies, incl. Blink and V8), so it will take a while. -To speed up subsequent builds, you can use [sccache][sccache]. Add the GN arg -`cc_wrapper = "sccache"` by running `gn args out/Testing` to bring up an -editor and adding a line to the end of the file. - -[sccache]: https://github.com/mozilla/sccache - The built executable will be under `./out/Testing`: ```sh @@ -157,21 +264,15 @@ $ ./out/Testing/electron.exe $ ./out/Testing/electron ``` -### Packaging - -On linux, first strip the debugging and symbol information: - -```sh -electron/script/strip-binaries.py -d out/Release -``` +#### Packaging To package the electron build as a distributable zip file: ```sh -ninja -C out/Release electron:electron_dist_zip +$ ninja -C out/Release electron:electron_dist_zip ``` -### Cross-compiling +#### Cross-compiling To compile for a platform that isn't the same as the one you're building on, set the `target_cpu` and `target_os` GN arguments. For example, to compile an @@ -194,12 +295,12 @@ If you test other combinations and find them to work, please update this documen See the GN reference for allowable values of [`target_os`][target_os values] and [`target_cpu`][target_cpu values]. -[target_os values]: https://gn.googlesource.com/gn/+/master/docs/reference.md#built_in-predefined-variables-target_os_the-desired-operating-system-for-the-build-possible-values -[target_cpu values]: https://gn.googlesource.com/gn/+/master/docs/reference.md#built_in-predefined-variables-target_cpu_the-desired-cpu-architecture-for-the-build-possible-values +[target_os values]: https://gn.googlesource.com/gn/+/main/docs/reference.md#built_in-predefined-variables-target_os_the-desired-operating-system-for-the-build-possible-values +[target_cpu values]: https://gn.googlesource.com/gn/+/main/docs/reference.md#built_in-predefined-variables-target_cpu_the-desired-cpu-architecture-for-the-build-possible-values -#### Windows on Arm (experimental) +#### Windows on Arm -To cross-compile for Windows on Arm, [follow Chromium's guide](https://chromium.googlesource.com/chromium/src/+/refs/heads/master/docs/windows_build_instructions.md#Visual-Studio) to get the necessary dependencies, SDK and libraries, then build with `ELECTRON_BUILDING_WOA=1` in your environment before running `gclient sync`. +To cross-compile for Windows on Arm, [follow Chromium's guide](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/windows_build_instructions.md#Visual-Studio) to get the necessary dependencies, SDK and libraries, then build with `ELECTRON_BUILDING_WOA=1` in your environment before running `gclient sync`. ```bat set ELECTRON_BUILDING_WOA=1 @@ -215,15 +316,15 @@ gclient sync -f --with_branch_heads --with_tags Next, run `gn gen` as above with `target_cpu="arm64"`. -## Tests +### Tests To run the tests, you'll first need to build the test modules against the same version of Node.js that was built as part of the build process. To generate build headers for the modules to compile against, run the following -under `src/` directory. +under `${root}/src/` directory. ```sh -$ ninja -C out/Testing third_party/electron_node:headers +$ ninja -C out/Testing electron:node_headers ``` You can now [run the tests](testing.md#unit-tests). @@ -236,7 +337,7 @@ $ npm run test -- \ --enable-logging -g 'BrowserWindow module' ``` -## Sharing the git cache between multiple machines +### Sharing the git cache between multiple machines It is possible to share the gclient git cache with other machines by exporting it as SMB share on linux, but only one process/machine can be using the cache at a @@ -258,11 +359,14 @@ This can be set quickly in powershell (ran as administrator): New-ItemProperty -Path "HKLM:\System\CurrentControlSet\Services\Lanmanworkstation\Parameters" -Name DirectoryCacheLifetime -Value 0 -PropertyType DWORD -Force ``` +</details> + ## Troubleshooting -### gclient sync complains about rebase +### `sync` complains about rebase -If `gclient sync` is interrupted the git tree may be left in a bad state, leading to a cryptic message when running `gclient sync` in the future: +If `e sync` (or `gclient sync`) is interrupted, the git tree may be left in a bad state, leading to +a cryptic message when running `sync` in the future: ```plaintext 2> Conflict while rebasing this branch. @@ -270,18 +374,27 @@ If `gclient sync` is interrupted the git tree may be left in a bad state, leadin 2> See man git-rebase for details. ``` -If there are no git conflicts or rebases in `src/electron`, you may need to abort a `git am` in `src`: +If there are no git conflicts or rebases in `${root}/src/electron`, you may need to abort a `git am` +in `${root}/src`: ```sh $ cd ../ $ git am --abort $ cd electron -$ gclient sync -f +$ e sync -f ``` +This may also happen if you have checked out a branch (as opposed to having a detached head) in `${root}/src/` +or some other dependency’s repository. If that is the case, a `git checkout --detach HEAD` in the +appropriate repository should do the trick. + ### I'm being asked for a username/password for chromium-internal.googlesource.com If you see a prompt for `Username for 'https://chrome-internal.googlesource.com':` when running `gclient sync` on Windows, it's probably because the `DEPOT_TOOLS_WIN_TOOLCHAIN` environment variable is not set to 0. Open `Control Panel` → `System and Security` → `System` → `Advanced system settings` and add a system variable `DEPOT_TOOLS_WIN_TOOLCHAIN` with value `0`. This tells `depot_tools` to use your locally installed version of Visual Studio (by default, `depot_tools` will try to download a Google-internal version that only Googlers have access to). + +### RBE authentication randomly fails with "Token not valid" + +This could be caused by the local clock time on the machine being off by a small amount. Use [time.is](https://time.is/) to check. diff --git a/docs/development/build-instructions-linux.md b/docs/development/build-instructions-linux.md index a83436ab788ff..6fd1b0ee62abc 100644 --- a/docs/development/build-instructions-linux.md +++ b/docs/development/build-instructions-linux.md @@ -1,81 +1,25 @@ # Build Instructions (Linux) -Follow the guidelines below for building Electron on Linux. +Follow the guidelines below for building **Electron itself** on Linux, for the purposes of creating custom Electron binaries. For bundling and distributing your app code with the prebuilt Electron binaries, see the [application distribution][application-distribution] guide. -## Prerequisites - -* At least 25GB disk space and 8GB RAM. -* Python 2.7.x. Some distributions like CentOS 6.x still use Python 2.6.x - so you may need to check your Python version with `python -V`. - - Please also ensure that your system and Python version support at least TLS 1.2. - For a quick test, run the following script: - - ```sh - $ npx @electron/check-python-tls - ``` - - If the script returns that your configuration is using an outdated security - protocol, use your system's package manager to update Python to the latest - version in the 2.7.x branch. Alternatively, visit https://www.python.org/downloads/ - for detailed instructions. - -* Node.js. There are various ways to install Node. You can download - source code from [nodejs.org](https://nodejs.org) and compile it. - Doing so permits installing Node on your own home directory as a standard user. - Or try repositories such as [NodeSource](https://nodesource.com/blog/nodejs-v012-iojs-and-the-nodesource-linux-repositories). -* [clang](https://clang.llvm.org/get_started.html) 3.4 or later. -* Development headers of GTK 3 and libnotify. - -On Ubuntu, install the following libraries: - -```sh -$ sudo apt-get install build-essential clang libdbus-1-dev libgtk-3-dev \ - libnotify-dev libgnome-keyring-dev \ - libasound2-dev libcap-dev libcups2-dev libxtst-dev \ - libxss1 libnss3-dev gcc-multilib g++-multilib curl \ - gperf bison python-dbusmock openjdk-8-jre -``` - -On RHEL / CentOS, install the following libraries: +[application-distribution]: ../tutorial/application-distribution.md -```sh -$ sudo yum install clang dbus-devel gtk3-devel libnotify-devel \ - libgnome-keyring-devel xorg-x11-server-utils libcap-devel \ - cups-devel libXtst-devel alsa-lib-devel libXrandr-devel \ - nss-devel python-dbusmock openjdk-8-jre -``` - -On Fedora, install the following libraries: +## Prerequisites -```sh -$ sudo dnf install clang dbus-devel gtk3-devel libnotify-devel \ - libgnome-keyring-devel xorg-x11-server-utils libcap-devel \ - cups-devel libXtst-devel alsa-lib-devel libXrandr-devel \ - nss-devel python-dbusmock openjdk-8-jre -``` +Due to Electron's dependency on Chromium, prerequisites and dependencies for Electron change over time. [Chromium's documentation on building on Linux](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/linux/build_instructions.md) has up to date information for building Chromium on Linux. This documentation can generally +be followed for building Electron on Linux as well. -Other distributions may offer similar packages for installation via package -managers such as pacman. Or one can compile from source code. +Additionally, Electron's [Linux dependency installer](https://github.com/electron/build-images/blob/main/tools/install-deps.sh) can be referenced to get the current dependencies that Electron requires in addition to what Chromium installs via [build/install-deps.sh](https://chromium.googlesource.com/chromium/src/+/HEAD/build/install-build-deps.sh). ### Cross compilation -If you want to build for an `arm` target you should also install the following -dependencies: - -```sh -$ sudo apt-get install libc6-dev-armhf-cross linux-libc-dev-armhf-cross \ - g++-arm-linux-gnueabihf -``` - -Similarly for `arm64`, install the following: +If you want to build for an `arm` target, you can use Electron's [Linux dependency installer](https://github.com/electron/build-images/blob/main/tools/install-deps.sh) to install the additional dependencies by passing the `--arm argument`: ```sh -$ sudo apt-get install libc6-dev-arm64-cross linux-libc-dev-arm64-cross \ - g++-aarch64-linux-gnu +$ sudo install-deps.sh --arm ``` -And to cross-compile for `arm` or `ia32` targets, you should pass the +And to cross-compile for `arm` or targets, you should pass the `target_cpu` parameter to `gn gen`: ```sh diff --git a/docs/development/build-instructions-macos.md b/docs/development/build-instructions-macos.md index 62720006c1dc4..09df5388309ed 100644 --- a/docs/development/build-instructions-macos.md +++ b/docs/development/build-instructions-macos.md @@ -1,49 +1,58 @@ # Build Instructions (macOS) -Follow the guidelines below for building Electron on macOS. +Follow the guidelines below for building **Electron itself** on macOS, for the purposes of creating custom Electron binaries. For bundling and distributing your app code with the prebuilt Electron binaries, see the [application distribution][application-distribution] guide. -## Prerequisites +[application-distribution]: ../tutorial/application-distribution.md -* macOS >= 10.11.6 -* [Xcode](https://developer.apple.com/technologies/tools/) >= 9.0.0 -* [node.js](https://nodejs.org) (external) -* Python 2.7 with support for TLS 1.2 +## Prerequisites -## Python +* macOS >= 12 +* [Xcode](https://developer.apple.com/technologies/tools/). The exact version + needed depends on what branch you are building, but the latest version of + Xcode is generally a good bet for building `main`. +* Python >= 3.9 +* [Node.js](https://nodejs.org/download/) >= 22.12.0 -Please also ensure that your system and Python version support at least TLS 1.2. -This depends on both your version of macOS and Python. For a quick test, run: +### Arm64-specific prerequisites -```sh -$ npx @electron/check-python-tls -``` +* Rosetta 2 + * We recommend installing Rosetta if using dependencies that need to cross-compile on x64 and arm64 machines. Rosetta can be installed by using the softwareupdate command line tool. + * `$ softwareupdate --install-rosetta` -If the script returns that your configuration is using an outdated security -protocol, you can either update macOS to High Sierra or install a new version -of Python 2.7.x. To upgrade Python, use [Homebrew](https://brew.sh/): +## Building Electron -```sh -$ brew install python@2 && brew link python@2 --force -``` +See [Build Instructions: GN](build-instructions-gn.md). -If you are using Python as provided by Homebrew, you also need to install -the following Python modules: +## Troubleshooting -* [pyobjc](https://pypi.org/project/pyobjc/#description) +### Xcode "incompatible architecture" errors (MacOS arm64-specific) -You can use `pip` to install it: +If both Xcode and Xcode command line tools are installed (`$ xcode -select --install`, or directly download the correct version [here](https://developer.apple.com/download/all/?q=command%20line%20tools)), but the stack trace says otherwise like so: ```sh -$ pip install pyobjc +xcrun: error: unable to load libxcrun +(dlopen(/Users/<user>/.electron_build_tools/third_party/Xcode/Xcode.app/Contents/Developer/usr/lib/libxcrun.dylib (http://xcode.app/Contents/Developer/usr/lib/libxcrun.dylib), 0x0005): + tried: '/Users/<user>/.electron_build_tools/third_party/Xcode/Xcode.app/Contents/Developer/usr/lib/libxcrun.dylib (http://xcode.app/Contents/Developer/usr/lib/libxcrun.dylib)' + (mach-o file, but is an incompatible architecture (have (x86_64), need (arm64e))), '/Users/<user>/.electron_build_tools/third_party/Xcode/Xcode-11.1.0.app/Contents/Developer/usr/lib/libxcrun.dylib (http://xcode-11.1.0.app/Contents/Developer/usr/lib/libxcrun.dylib)' (mach-o file, but is an incompatible architecture (have (x86_64), need (arm64e)))).` ``` -## macOS SDK +If you are on arm64 architecture, the build script may be pointing to the wrong Xcode version (11.x.y doesn't support arm64). Navigate to `/Users/<user>/.electron_build_tools/third_party/Xcode/` and rename `Xcode-13.3.0.app` to `Xcode.app` to ensure the right Xcode version is used. -If you're developing Electron and don't plan to redistribute your -custom Electron build, you may skip this section. +### Certificates fail to verify -Official Electron builds are built with [Xcode 9.4.1](http://adcdownload.apple.com/Developer_Tools/Xcode_9.4.1/Xcode_9.4.1.xip), and the macOS 10.13 SDK. Building with a newer SDK works too, but the releases currently use the 10.13 SDK. +Installing [`certifi`](https://pypi.org/project/certifi/) will fix the following error: -## Building Electron +```sh +________ running 'python3 src/tools/clang/scripts/update.py' in '/Users/<user>/electron' +Downloading https://commondatastorage.googleapis.com/chromium-browser-clang/Mac_arm64/clang-llvmorg-15-init-15652-g89a99ec9-1.tgz +<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)> +Retrying in 5 s ... +Downloading https://commondatastorage.googleapis.com/chromium-browser-clang/Mac_arm64/clang-llvmorg-15-init-15652-g89a99ec9-1.tgz +<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)> +Retrying in 10 s ... +Downloading https://commondatastorage.googleapis.com/chromium-browser-clang/Mac_arm64/clang-llvmorg-15-init-15652-g89a99ec9-1.tgz +<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)> +Retrying in 20 s ... +``` -See [Build Instructions: GN](build-instructions-gn.md). +This issue has to do with Python 3.6 using its [own](https://github.com/python/cpython/blob/560ea272b01acaa6c531cc7d94331b2ef0854be6/Mac/BuildScript/resources/ReadMe.rtf#L35) copy of OpenSSL in lieu of the deprecated Apple-supplied OpenSSL libraries. `certifi` adds a curated bundle of default root certificates. This issue is documented in the Electron repo [here](https://github.com/electron/build-tools/issues/55). Further information about this issue can be found [here](https://stackoverflow.com/questions/27835619/urllib-and-ssl-certificate-verify-failed-error) and [here](https://stackoverflow.com/questions/40684543/how-to-make-python-use-ca-certificates-from-mac-os-truststore). diff --git a/docs/development/build-instructions-windows.md b/docs/development/build-instructions-windows.md index 258d88dba2b3a..3ff011c45e04e 100644 --- a/docs/development/build-instructions-windows.md +++ b/docs/development/build-instructions-windows.md @@ -1,30 +1,29 @@ # Build Instructions (Windows) -Follow the guidelines below for building Electron on Windows. +Follow the guidelines below for building **Electron itself** on Windows, for the purposes of creating custom Electron binaries. For bundling and distributing your app code with the prebuilt Electron binaries, see the [application distribution][application-distribution] guide. + +[application-distribution]: ../tutorial/application-distribution.md ## Prerequisites * Windows 10 / Server 2012 R2 or higher -* Visual Studio 2017 15.7.2 or higher - [download VS 2019 Community Edition for - free](https://www.visualstudio.com/vs/) - * See [the Chromium build documentation](https://chromium.googlesource.com/chromium/src/+/master/docs/windows_build_instructions.md#visual-studio) for more details on which Visual Studio +* Visual Studio 2019 (>=16.0.0) to build, but Visual Studio 2022 (>=17.0.0) is preferred - [download VS 2022 Community Edition for free](https://www.visualstudio.com/vs/) + * See [the Chromium build documentation](https://chromium.googlesource.com/chromium/src/+/main/docs/windows_build_instructions.md#visual-studio) for more details on which Visual Studio components are required. * If your Visual Studio is installed in a directory other than the default, you'll need to set a few environment variables to point the toolchains to your installation path. - * `vs2019_install = DRIVE:\path\to\Microsoft Visual Studio\2019\Community`, replacing `2019` and `Community` with your installed versions and replacing `DRIVE:` with the drive that Visual Studio is on. Often, this will be `C:`. + * `vs2022_install = DRIVE:\path\to\Microsoft Visual Studio\2022\Community`, replacing `2022` and `Community` with your installed versions and replacing `DRIVE:` with the drive that Visual Studio is on. Often, this will be `C:`. * `WINDOWSSDKDIR = DRIVE:\path\to\Windows Kits\10`, replacing `DRIVE:` with the drive that Windows Kits is on. Often, this will be `C:`. - * [Python for Windows (pywin32) Extensions](https://pypi.org/project/pywin32/#files) - is also needed in order to run the build process. -* [Node.js](https://nodejs.org/download/) +* [Node.js](https://nodejs.org/download/) >= 22.12.0 * [Git](https://git-scm.com) * Debugging Tools for Windows of Windows SDK 10.0.15063.468 if you plan on creating a full distribution since `symstore.exe` is used for creating a symbol store from `.pdb` files. * Different versions of the SDK can be installed side by side. To install the SDK, open Visual Studio Installer, select - `Change` → `Individual Components`, scroll down and select the appropriate + `Modify` → `Individual Components`, scroll down and select the appropriate Windows SDK to install. Another option would be to look at the - [Windows SDK and emulator archive](https://developer.microsoft.com/en-us/windows/downloads/sdk-archive) + [Windows SDK and emulator archive](https://developer.microsoft.com/en-us/windows/downloads/sdk-archive/) and download the standalone version of the SDK respectively. * The SDK Debugging Tools must also be installed. If the Windows 10 SDK was installed via the Visual Studio installer, then they can be installed by going to: @@ -33,15 +32,16 @@ store from `.pdb` files. Or, you can download the standalone SDK installer and use it to install the Debugging Tools. If you don't currently have a Windows installation, -[dev.microsoftedge.com](https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/) +[developer.microsoft.com](https://developer.microsoft.com/en-us/windows/downloads/virtual-machines/) has timebombed versions of Windows that you can use to build Electron. Building Electron is done entirely with command-line scripts and cannot be done with Visual Studio. You can develop Electron with any editor but support for building with Visual Studio will come in the future. -**Note:** Even though Visual Studio is not used for building, it's still -**required** because we need the build toolchains it provides. +> [!NOTE] +> Even though Visual Studio is not used for building, it's still +> **required** because we need the build toolchains it provides. ## Exclude source tree from Windows Security @@ -116,10 +116,6 @@ $ git config --system core.longpaths true This can happen during build, when Debugging Tools for Windows has been installed with Windows Driver Kit. Uninstall Windows Driver Kit and install Debugging Tools with steps described above. -### ImportError: No module named win32file - -Make sure you have installed `pywin32` with `pip install pywin32`. - ### Build Scripts Hang Until Keypress This bug is a "feature" of Windows' command prompt. It happens when clicking inside the prompt window with diff --git a/docs/development/build-system-overview.md b/docs/development/build-system-overview.md deleted file mode 100644 index bb5a0d60cc22c..0000000000000 --- a/docs/development/build-system-overview.md +++ /dev/null @@ -1,80 +0,0 @@ -# Build System Overview - -Electron uses [GN](https://gn.googlesource.com/gn) for project generation and -[ninja](https://ninja-build.org/) for building. Project configurations can -be found in the `.gn` and `.gni` files. - -## GN Files - -The following `gn` files contain the main rules for building Electron: - -* `BUILD.gn` defines how Electron itself is built and - includes the default configurations for linking with Chromium. -* `build/args/{debug,release,all}.gn` contain the default build arguments for - building Electron. - -## Component Build - -Since Chromium is quite a large project, the final linking stage can take -quite a few minutes, which makes it hard for development. In order to solve -this, Chromium introduced the "component build", which builds each component as -a separate shared library, making linking very quick but sacrificing file size -and performance. - -Electron inherits this build option from Chromium. In `Debug` builds, the -binary will be linked to a shared library version of Chromium's components to -achieve fast linking time; for `Release` builds, the binary will be linked to -the static library versions, so we can have the best possible binary size and -performance. - -## Tests - -**NB** _this section is out of date and contains information that is no longer -relevant to the GN-built electron._ - -Test your changes conform to the project coding style using: - -```sh -$ npm run lint -``` - -Test functionality using: - -```sh -$ npm test -``` - -Whenever you make changes to Electron source code, you'll need to re-run the -build before the tests: - -```sh -$ npm run build && npm test -``` - -You can make the test suite run faster by isolating the specific test or block -you're currently working on using Mocha's -[exclusive tests](https://mochajs.org/#exclusive-tests) feature. Append -`.only` to any `describe` or `it` function call: - -```js -describe.only('some feature', () => { - // ... only tests in this block will be run -}) -``` - -Alternatively, you can use mocha's `grep` option to only run tests matching the -given regular expression pattern: - -```sh -$ npm test -- --grep child_process -``` - -Tests that include native modules (e.g. `runas`) can't be executed with the -debug build (see [#2558](https://github.com/electron/electron/issues/2558) for -details), but they will work with the release build. - -To run the tests with the release build use: - -```sh -$ npm test -- -R -``` diff --git a/docs/development/chromium-development.md b/docs/development/chromium-development.md index 6b7b6d47b550c..fc427b5d22a79 100644 --- a/docs/development/chromium-development.md +++ b/docs/development/chromium-development.md @@ -1,13 +1,39 @@ # Chromium Development -> A collection of resources for learning about Chromium and tracking its development - -- [@ChromiumDev](https://twitter.com/ChromiumDev) on Twitter -- [@googlechrome](https://twitter.com/googlechrome) on Twitter -- [Blog](https://blog.chromium.org) -- [Code Search](https://cs.chromium.org/) -- [Source Code](https://cs.chromium.org/chromium/src/) -- [Development Calendar and Release Info](https://www.chromium.org/developers/calendar) -- [Discussion Groups](https://www.chromium.org/developers/discussion-groups) +> A collection of resources for learning about Chromium and tracking its development. See also [V8 Development](v8-development.md) + +## Contributing to Chromium + +- [Checking Out and Building](https://chromium.googlesource.com/chromium/src/+/main/docs/#checking-out-and-building) + - [Windows](https://chromium.googlesource.com/chromium/src/+/main/docs/windows_build_instructions.md) + - [macOS](https://chromium.googlesource.com/chromium/src/+/main/docs/mac_build_instructions.md) + - [Linux](https://chromium.googlesource.com/chromium/src/+/main/docs/linux/build_instructions.md) + +- [Contributing](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/contributing.md) - This document outlines the process of getting a code change merged to the Chromium source tree. + - Assumes a working Chromium checkout and build. + +## Resources for Chromium Development + +### Code Resources + +- [Code Search](https://source.chromium.org/chromium) - Indexed and searchable source code for Chromium and associated projects. +- [Source Code](https://source.chromium.org/chromium/chromium/src) - The source code for Chromium itself. +- [Chromium Review](https://chromium-review.googlesource.com) - The searchable code host which facilitates code reviews for Chromium and related projects. + +### Informational Resources + +- [Chromium Dash](https://chromiumdash.appspot.com/home) - Chromium Dash ties together multiple data sources in order to present a consolidated view of what's going on in Chromium and Chrome, plus related projects like V8, WebRTC & Skia. + - [Schedule](https://chromiumdash.appspot.com/schedule) - Review upcoming Chromium release schedule. + - [Branches](https://chromiumdash.appspot.com/branches) - Look up which branch corresponds to which milestone. + - [Releases](https://chromiumdash.appspot.com/releases) - See what version of Chromium is shipping to each release channel and look up changes between each version. + - [Commits](https://chromiumdash.appspot.com/commits) - See and search for commits to the Chromium source tree by commit SHA or committer username. +- [Discussion Groups](https://www.chromium.org/developers/discussion-groups) - Subscribe to the following groups to get project updates and discuss the Chromium projects, and to get help in developing for Chromium-based browsers. +- [Chromium Slack](https://www.chromium.org/developers/slack) - a virtual meeting place where Chromium ecosystem developers can foster community and coordinate work. + +## Social Links + +- [Blog](https://blog.chromium.org) - News and developments from Chromium. +- [@ChromiumDev](https://twitter.com/ChromiumDev) - Twitter account containing news & guidance for developers from the Google Chrome Developer Relations team. +- [@googlechrome](https://twitter.com/googlechrome) - Official Twitter account for the Google Chrome browser. diff --git a/docs/development/clang-format.md b/docs/development/clang-format.md deleted file mode 100644 index 410a721bd5a5f..0000000000000 --- a/docs/development/clang-format.md +++ /dev/null @@ -1,35 +0,0 @@ -# Using clang-format on C++ Code - -[`clang-format`](https://clang.llvm.org/docs/ClangFormat.html) is a tool to -automatically format C/C++/Objective-C code, so that developers don't need to -worry about style issues during code reviews. - -It is highly recommended to format your changed C++ code before opening pull -requests, which will save you and the reviewers' time. - -You can install `clang-format` and `git-clang-format` via -`npm install -g clang-format`. - -To automatically format a file according to Electron C++ code style, run -`clang-format -i path/to/electron/file.cc`. It should work on macOS/Linux/Windows. - -The workflow to format your changed code: - -1. Make codes changes in Electron repository. -2. Run `git add your_changed_file.cc`. -3. Run `git-clang-format`, and you will probably see modifications in - `your_changed_file.cc`, these modifications are generated from `clang-format`. -4. Run `git add your_changed_file.cc`, and commit your change. -5. Now the branch is ready to be opened as a pull request. - -If you want to format the changed code on your latest git commit (HEAD), you can -run `git-clang-format HEAD~1`. See `git-clang-format -h` for more details. - -## Editor Integration - -You can also integrate `clang-format` directly into your favorite editors. -For further guidance on setting up editor integration, see these pages: - -* [Atom](https://atom.io/packages/clang-format) -* [Vim & Emacs](https://clang.llvm.org/docs/ClangFormat.html#vim-integration) -* [Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=xaver.clang-format) diff --git a/docs/development/clang-tidy.md b/docs/development/clang-tidy.md index 21210b8f6c7b4..b529d91b889b1 100644 --- a/docs/development/clang-tidy.md +++ b/docs/development/clang-tidy.md @@ -10,12 +10,12 @@ files, you need to have built Electron so that it knows which compiler flags were used. There is one required option for the script `--output-dir`, which tells the script which build directory to pull the compilation information from. A typical usage would be: -`npm run lint:clang-tiy --out-dir ../out/Testing` +`npm run lint:clang-tidy --out-dir ../out/Testing` With no filenames provided, all C/C++/Objective-C files will be checked. You can provide a list of files to be checked by passing the filenames after the options: -`npm run lint:clang-tiy --out-dir ../out/Testing shell/browser/api/electron_api_app.cc` +`npm run lint:clang-tidy --out-dir ../out/Testing shell/browser/api/electron_api_app.cc` While `clang-tidy` has a [long list](https://clang.llvm.org/extra/clang-tidy/checks/list.html) diff --git a/docs/development/coding-style.md b/docs/development/coding-style.md index 2eb0eb3a796bb..d9f5b88d68137 100644 --- a/docs/development/coding-style.md +++ b/docs/development/coding-style.md @@ -3,7 +3,7 @@ These are the style guidelines for coding in Electron. You can run `npm run lint` to show any style issues detected by `cpplint` and -`eslint`. +`oxlint`. ## General Code @@ -24,12 +24,11 @@ You can run `npm run lint` to show any style issues detected by `cpplint` and ## C++ and Python -For C++ and Python, we follow Chromium's [Coding -Style](https://www.chromium.org/developers/coding-style). You can use -[clang-format](clang-format.md) to format the C++ code automatically. There is -also a script `script/cpplint.py` to check whether all files conform. +For C++ and Python, we follow Chromium's +[Coding Style](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/styleguide/styleguide.md). +There is also a script `script/cpplint.py` to check whether all files conform. -The Python version we are using now is Python 2.7. +The Python version we are using now is Python 3.9. The C++ code uses a lot of Chromium's abstractions and types, so it's recommended to get acquainted with them. A good place to start is @@ -40,9 +39,9 @@ etc. ## Documentation -* Write [remark](https://github.com/remarkjs/remark) markdown style. +* Write prose according to our [documentation style guide](./style-guide.md). -You can run `npm run lint-docs` to ensure that your documentation changes are +You can run `npm run lint:docs` to ensure that your documentation changes are formatted correctly. ## JavaScript @@ -50,7 +49,7 @@ formatted correctly. * Write [standard](https://www.npmjs.com/package/standard) JavaScript style. * File names should be concatenated with `-` instead of `_`, e.g. `file-name.js` rather than `file_name.js`, because in - [github/atom](https://github.com/github/atom) module names are usually in + [atom/atom](https://github.com/atom/atom) module names are usually in the `module-name` form. This rule only applies to `.js` files. * Use newer ES6/ES2015 syntax where appropriate * [`const`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const) @@ -66,11 +65,11 @@ formatted correctly. Electron APIs uses the same capitalization scheme as Node.js: -- When the module itself is a class like `BrowserWindow`, use `PascalCase`. -- When the module is a set of APIs, like `globalShortcut`, use `camelCase`. -- When the API is a property of object, and it is complex enough to be in a +* When the module itself is a class like `BrowserWindow`, use `PascalCase`. +* When the module is a set of APIs, like `globalShortcut`, use `camelCase`. +* When the API is a property of object, and it is complex enough to be in a separate chapter like `win.webContents`, use `mixedCase`. -- For other non-module APIs, use natural titles, like `<webview> Tag` or +* For other non-module APIs, use natural titles, like `<webview> Tag` or `Process Object`. When creating a new API, it is preferred to use getters and setters instead of diff --git a/docs/development/creating-api.md b/docs/development/creating-api.md new file mode 100644 index 0000000000000..8a89e31cc8215 --- /dev/null +++ b/docs/development/creating-api.md @@ -0,0 +1,174 @@ +# Creating a New Electron Browser Module + +Welcome to the Electron API guide! If you are unfamiliar with creating a new Electron API module within the [`browser`](https://github.com/electron/electron/tree/main/shell/browser) directory, this guide serves as a checklist for some of the necessary steps that you will need to implement. + +This is not a comprehensive end-all guide to creating an Electron Browser API, rather an outline documenting some of the more unintuitive steps. + +## Add your files to Electron's project configuration + +Electron uses [GN](https://gn.googlesource.com/gn) as a meta build system to generate files for its compiler, [Ninja](https://ninja-build.org/). This means that in order to tell Electron to compile your code, we have to add your API's code and header file names into [`filenames.gni`](../../filenames.gni). + +You will need to append your API file names alphabetically into the appropriate files like so: + +```cpp title='filenames.gni' +lib_sources = [ + "path/to/api/api_name.cc", + "path/to/api/api_name.h", +] + +lib_sources_mac = [ + "path/to/api/api_name_mac.h", + "path/to/api/api_name_mac.mm", +] + +lib_sources_win = [ + "path/to/api/api_name_win.cc", + "path/to/api/api_name_win.h", +] + +lib_sources_linux = [ + "path/to/api/api_name_linux.cc", + "path/to/api/api_name_linux.h", +] +``` + +Note that the Windows, macOS and Linux array additions are optional and should only be added if your API has specific platform implementations. + +## Create API documentation + +Type definitions are generated by Electron using [`@electron/docs-parser`](https://github.com/electron/docs-parser) and [`@electron/typescript-definitions`](https://github.com/electron/typescript-definitions). This step is necessary to ensure consistency across Electron's API documentation. This means that for your API type definition to appear in the `electron.d.ts` file, we must create a `.md` file. Examples can be found in [this folder](https://github.com/electron/electron/tree/main/docs/api). + +## Set up `ObjectTemplateBuilder` and `Wrappable` + +Electron constructs its modules using [`object_template_builder`](https://www.electronjs.org/blog/from-native-to-js#mateobjecttemplatebuilder). + +[`wrappable`](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/gin/wrappable.h) is a base class for C++ objects that have corresponding v8 wrapper objects. + +Here is a basic example of code that you may need to add, in order to incorporate `object_template_builder` and `wrappable` into your API. For further reference, you can find more implementations [here](https://github.com/electron/electron/tree/main/shell/browser/api). + +In your `api_name.h` file: + +```cpp title='api_name.h' + +#ifndef ELECTRON_SHELL_BROWSER_API_ELECTRON_API_{API_NAME}_H_ +#define ELECTRON_SHELL_BROWSER_API_ELECTRON_API_{API_NAME}_H_ + +#include "gin/handle.h" +#include "gin/wrappable.h" + +namespace electron { + +namespace api { + +class ApiName : public gin::DeprecatedWrappable<ApiName> { + public: + static gin::Handle<ApiName> Create(v8::Isolate* isolate); + + // gin::Wrappable + static gin::DeprecatedWrapperInfo kWrapperInfo; + gin::ObjectTemplateBuilder GetObjectTemplateBuilder( + v8::Isolate* isolate) override; + const char* GetTypeName() override; +} // namespace api +} // namespace electron +``` + +In your `api_name.cc` file: + +```cpp title='api_name.cc' +#include "shell/browser/api/electron_api_safe_storage.h" + +#include "shell/browser/browser.h" +#include "shell/common/gin_converters/base_converter.h" +#include "shell/common/gin_converters/callback_converter.h" +#include "shell/common/gin_helper/dictionary.h" +#include "shell/common/gin_helper/object_template_builder.h" +#include "shell/common/node_includes.h" +#include "shell/common/platform_util.h" + +namespace electron { + +namespace api { + +gin::DeprecatedWrapperInfo ApiName::kWrapperInfo = {gin::kEmbedderNativeGin}; + +gin::ObjectTemplateBuilder ApiName::GetObjectTemplateBuilder( + v8::Isolate* isolate) { + return gin::ObjectTemplateBuilder(isolate) + .SetMethod("methodName", &ApiName::methodName); +} + +const char* ApiName::GetTypeName() { + return "ApiName"; +} + +// static +gin::Handle<ApiName> ApiName::Create(v8::Isolate* isolate) { + return gin::CreateHandle(isolate, new ApiName()); +} + +} // namespace api + +} // namespace electron + +namespace { + +void Initialize(v8::Local<v8::Object> exports, + v8::Local<v8::Value> unused, + v8::Local<v8::Context> context, + void* priv) { + v8::Isolate* const isolate = v8::Isolate::GetCurrent(); + gin_helper::Dictionary dict(isolate, exports); + dict.Set("apiName", electron::api::ApiName::Create(isolate)); +} + +} // namespace +``` + +## Link your Electron API with Node + +In the [`typings/internal-ambient.d.ts`](../../typings/internal-ambient.d.ts) file, we need to append a new property onto the `Process` interface like so: + +```ts title='typings/internal-ambient.d.ts' @ts-nocheck +interface Process { + _linkedBinding(name: 'electron_browser_{api_name}'): Electron.ApiName; +} +``` + +At the very bottom of your `api_name.cc` file: + +```cpp title='api_name.cc' +NODE_LINKED_BINDING_CONTEXT_AWARE(electron_browser_{api_name},Initialize) +``` + +In your [`shell/common/node_bindings.cc`](../../shell/common/node_bindings.cc) file, add your node binding name to Electron's built-in modules. + +```cpp title='shell/common/node_bindings.cc' +#define ELECTRON_BROWSER_MODULES(V) \ + V(electron_browser_{api_name}) +``` + +> [!NOTE] +> More technical details on how Node links with Electron can be found on [our blog](https://www.electronjs.org/blog/electron-internals-using-node-as-a-library#link-node-with-electron). + +## Expose your API to TypeScript + +### Export your API as a module + +We will need to create a new TypeScript file in the path that follows: + +`"lib/browser/api/{electron_browser_{api_name}}.ts"` + +An example of the contents of this file can be found [here](../../lib/browser/api/native-theme.ts). + +### Expose your module to TypeScript + +Add your module to the module list found at `"lib/browser/api/module-list.ts"` like so: + +<!-- eslint-disable semi --> + +```ts title='lib/browser/api/module-list.ts' @ts-nocheck +export const browserModuleList: ElectronInternal.ModuleEntry[] = [ + { name: 'apiName', loader: () => require('./api-name') } +]; +``` diff --git a/docs/development/debug-instructions-windows.md b/docs/development/debug-instructions-windows.md deleted file mode 100644 index f53c34d47203f..0000000000000 --- a/docs/development/debug-instructions-windows.md +++ /dev/null @@ -1,92 +0,0 @@ -# Debugging on Windows - -If you experience crashes or issues in Electron that you believe are not caused -by your JavaScript application, but instead by Electron itself, debugging can -be a little bit tricky, especially for developers not used to native/C++ -debugging. However, using Visual Studio, Electron's hosted Symbol Server, -and the Electron source code, you can enable step-through debugging -with breakpoints inside Electron's source code. - -**See also**: There's a wealth of information on debugging Chromium, much of which also applies to Electron, on the Chromium developers site: [Debugging Chromium on Windows](https://www.chromium.org/developers/how-tos/debugging-on-windows). - -## Requirements - -* **A debug build of Electron**: The easiest way is usually building it - yourself, using the tools and prerequisites listed in the - [build instructions for Windows](build-instructions-windows.md). While you can - attach to and debug Electron as you can download it directly, you will - find that it is heavily optimized, making debugging substantially more - difficult: The debugger will not be able to show you the content of all - variables and the execution path can seem strange because of inlining, - tail calls, and other compiler optimizations. - -* **Visual Studio with C++ Tools**: The free community editions of Visual - Studio 2013 and Visual Studio 2015 both work. Once installed, - [configure Visual Studio to use Electron's Symbol server](setting-up-symbol-server.md). - It will enable Visual Studio to gain a better understanding of what happens - inside Electron, making it easier to present variables in a human-readable - format. - -* **ProcMon**: The [free SysInternals tool][sys-internals] allows you to inspect - a processes parameters, file handles, and registry operations. - -## Attaching to and Debugging Electron - -To start a debugging session, open up PowerShell/CMD and execute your debug -build of Electron, using the application to open as a parameter. - -```powershell -$ ./out/Testing/electron.exe ~/my-electron-app/ -``` - -### Setting Breakpoints - -Then, open up Visual Studio. Electron is not built with Visual Studio and hence -does not contain a project file - you can however open up the source code files -"As File", meaning that Visual Studio will open them up by themselves. You can -still set breakpoints - Visual Studio will automatically figure out that the -source code matches the code running in the attached process and break -accordingly. - -Relevant code files can be found in `./shell/`. - -### Attaching - -You can attach the Visual Studio debugger to a running process on a local or -remote computer. After the process is running, click Debug / Attach to Process -(or press `CTRL+ALT+P`) to open the "Attach to Process" dialog box. You can use -this capability to debug apps that are running on a local or remote computer, -debug multiple processes simultaneously. - -If Electron is running under a different user account, select the -`Show processes from all users` check box. Notice that depending on how many -BrowserWindows your app opened, you will see multiple processes. A typical -one-window app will result in Visual Studio presenting you with two -`Electron.exe` entries - one for the main process and one for the renderer -process. Since the list only gives you names, there's currently no reliable -way of figuring out which is which. - -### Which Process Should I Attach to? - -Code executed within the main process (that is, code found in or eventually run -by your main JavaScript file) will run inside the main process, while other -code will execute inside its respective renderer process. - -You can be attached to multiple programs when you are debugging, but only one -program is active in the debugger at any time. You can set the active program -in the `Debug Location` toolbar or the `Processes window`. - -## Using ProcMon to Observe a Process - -While Visual Studio is fantastic for inspecting specific code paths, ProcMon's -strength is really in observing everything your application is doing with the -operating system - it captures File, Registry, Network, Process, and Profiling -details of processes. It attempts to log **all** events occurring and can be -quite overwhelming, but if you seek to understand what and how your application -is doing to the operating system, it can be a valuable resource. - -For an introduction to ProcMon's basic and advanced debugging features, go check -out [this video tutorial][procmon-instructions] provided by Microsoft. - -[sys-internals]: https://technet.microsoft.com/en-us/sysinternals/processmonitor.aspx -[procmon-instructions]: https://channel9.msdn.com/shows/defrag-tools/defrag-tools-4-process-monitor diff --git a/docs/development/debugging-instructions-macos-xcode.md b/docs/development/debugging-instructions-macos-xcode.md deleted file mode 100644 index 7e88a92bba755..0000000000000 --- a/docs/development/debugging-instructions-macos-xcode.md +++ /dev/null @@ -1,30 +0,0 @@ -## Debugging with XCode - -### Generate xcode project for debugging sources (cannot build code from xcode) - -Run `gn gen` with the --ide=xcode argument. - -```sh -$ gn gen out/Testing --ide=xcode -``` - -This will generate the electron.ninja.xcworkspace. You will have to open this workspace -to set breakpoints and inspect. - -See `gn help gen` for more information on generating IDE projects with GN. - -### Debugging and breakpoints - -Launch Electron app after build. -You can now open the xcode workspace created above and attach to the Electron process -through the Debug > Attach To Process > Electron debug menu. [Note: If you want to debug -the renderer process, you need to attach to the Electron Helper as well.] - -You can now set breakpoints in any of the indexed files. However, you will not be able -to set breakpoints directly in the Chromium source. -To set break points in the Chromium source, you can choose Debug > Breakpoints > Create -Symbolic Breakpoint and set any function name as the symbol. This will set the breakpoint -for all functions with that name, from all the classes if there are more than one. -You can also do this step of setting break points prior to attaching the debugger, -however, actual breakpoints for symbolic breakpoint functions may not show up until the -debugger is attached to the app. diff --git a/docs/development/debugging-instructions-macos.md b/docs/development/debugging-instructions-macos.md deleted file mode 100644 index d3af2d2a1a28f..0000000000000 --- a/docs/development/debugging-instructions-macos.md +++ /dev/null @@ -1,134 +0,0 @@ -# Debugging on macOS - -If you experience crashes or issues in Electron that you believe are not caused -by your JavaScript application, but instead by Electron itself, debugging can -be a little bit tricky, especially for developers not used to native/C++ -debugging. However, using lldb, and the Electron source code, you can enable -step-through debugging with breakpoints inside Electron's source code. -You can also use [XCode for debugging](debugging-instructions-macos-xcode.md) if -you prefer a graphical interface. - -## Requirements - -* **A debug build of Electron**: The easiest way is usually building it - yourself, using the tools and prerequisites listed in the - [build instructions for macOS](build-instructions-macos.md). While you can - attach to and debug Electron as you can download it directly, you will - find that it is heavily optimized, making debugging substantially more - difficult: The debugger will not be able to show you the content of all - variables and the execution path can seem strange because of inlining, - tail calls, and other compiler optimizations. - -* **Xcode**: In addition to Xcode, also install the Xcode command line tools. - They include LLDB, the default debugger in Xcode on macOS. It supports - debugging C, Objective-C and C++ on the desktop and iOS devices and simulator. - -* **.lldbinit**: Create or edit `~/.lldbinit` to allow Chromium code to be properly source-mapped. - - ```text - command script import ~/electron/src/tools/lldb/lldbinit.py - ``` - -## Attaching to and Debugging Electron - -To start a debugging session, open up Terminal and start `lldb`, passing a non-release -build of Electron as a parameter. - -```sh -$ lldb ./out/Testing/Electron.app -(lldb) target create "./out/Testing/Electron.app" -Current executable set to './out/Testing/Electron.app' (x86_64). -``` - -### Setting Breakpoints - -LLDB is a powerful tool and supports multiple strategies for code inspection. For -this basic introduction, let's assume that you're calling a command from JavaScript -that isn't behaving correctly - so you'd like to break on that command's C++ -counterpart inside the Electron source. - -Relevant code files can be found in `./shell/`. - -Let's assume that you want to debug `app.setName()`, which is defined in `browser.cc` -as `Browser::SetName()`. Set the breakpoint using the `breakpoint` command, specifying -file and line to break on: - -```sh -(lldb) breakpoint set --file browser.cc --line 117 -Breakpoint 1: where = Electron Framework`atom::Browser::SetName(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) + 20 at browser.cc:118, address = 0x000000000015fdb4 -``` - -Then, start Electron: - -```sh -(lldb) run -``` - -The app will immediately be paused, since Electron sets the app's name on launch: - -```sh -(lldb) run -Process 25244 launched: '/Users/fr/Code/electron/out/Testing/Electron.app/Contents/MacOS/Electron' (x86_64) -Process 25244 stopped -* thread #1: tid = 0x839a4c, 0x0000000100162db4 Electron Framework`atom::Browser::SetName(this=0x0000000108b14f20, name="Electron") + 20 at browser.cc:118, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 - frame #0: 0x0000000100162db4 Electron Framework`atom::Browser::SetName(this=0x0000000108b14f20, name="Electron") + 20 at browser.cc:118 - 115 } - 116 - 117 void Browser::SetName(const std::string& name) { --> 118 name_override_ = name; - 119 } - 120 - 121 int Browser::GetBadgeCount() { -(lldb) -``` - -To show the arguments and local variables for the current frame, run `frame variable` (or `fr v`), -which will show you that the app is currently setting the name to "Electron". - -```sh -(lldb) frame variable -(atom::Browser *) this = 0x0000000108b14f20 -(const string &) name = "Electron": { - [...] -} -``` - -To do a source level single step in the currently selected thread, execute `step` (or `s`). -This would take you into `name_override_.empty()`. To proceed and do a step over, -run `next` (or `n`). - -```sh -(lldb) step -Process 25244 stopped -* thread #1: tid = 0x839a4c, 0x0000000100162dcc Electron Framework`atom::Browser::SetName(this=0x0000000108b14f20, name="Electron") + 44 at browser.cc:119, queue = 'com.apple.main-thread', stop reason = step in - frame #0: 0x0000000100162dcc Electron Framework`atom::Browser::SetName(this=0x0000000108b14f20, name="Electron") + 44 at browser.cc:119 - 116 - 117 void Browser::SetName(const std::string& name) { - 118 name_override_ = name; --> 119 } - 120 - 121 int Browser::GetBadgeCount() { - 122 return badge_count_; -``` - -**NOTE:** If you don't see source code when you think you should, you may not have added the `~/.lldbinit` file above. - -To finish debugging at this point, run `process continue`. You can also continue until a certain -line is hit in this thread (`thread until 100`). This command will run the thread in the current -frame till it reaches line 100 in this frame or stops if it leaves the current frame. - -Now, if you open up Electron's developer tools and call `setName`, you will once again hit the -breakpoint. - -### Further Reading - -LLDB is a powerful tool with a great documentation. To learn more about it, consider -Apple's debugging documentation, for instance the [LLDB Command Structure Reference][lldb-command-structure] -or the introduction to [Using LLDB as a Standalone Debugger][lldb-standalone]. - -You can also check out LLDB's fantastic [manual and tutorial][lldb-tutorial], which -will explain more complex debugging scenarios. - -[lldb-command-structure]: https://developer.apple.com/library/mac/documentation/IDEs/Conceptual/gdb_to_lldb_transition_guide/document/lldb-basics.html#//apple_ref/doc/uid/TP40012917-CH2-SW2 -[lldb-standalone]: https://developer.apple.com/library/mac/documentation/IDEs/Conceptual/gdb_to_lldb_transition_guide/document/lldb-terminal-workflow-tutorial.html -[lldb-tutorial]: https://lldb.llvm.org/tutorial.html diff --git a/docs/development/debugging-on-macos.md b/docs/development/debugging-on-macos.md new file mode 100644 index 0000000000000..163df8e5aaf3a --- /dev/null +++ b/docs/development/debugging-on-macos.md @@ -0,0 +1,133 @@ +# Debugging on macOS + +If you experience crashes or issues in Electron that you believe are not caused +by your JavaScript application, but instead by Electron itself, debugging can +be a little bit tricky especially for developers not used to native/C++ +debugging. However, using `lldb` and the Electron source code, you can enable +step-through debugging with breakpoints inside Electron's source code. +You can also use [XCode for debugging](debugging-with-xcode.md) if you prefer a graphical interface. + +## Requirements + +* **A testing build of Electron**: The easiest way is usually to build it from source, + which you can do by following the instructions in the [build instructions](./build-instructions-macos.md). While you can attach to and debug Electron as you can download it directly, you will + find that it is heavily optimized, making debugging substantially more difficult. + In this case the debugger will not be able to show you the content of all + variables and the execution path can seem strange because of inlining, + tail calls, and other compiler optimizations. + +* **Xcode**: In addition to Xcode, you should also install the Xcode command line tools. + They include [LLDB](https://lldb.llvm.org/), the default debugger in Xcode on macOS. It supports + debugging C, Objective-C and C++ on the desktop and iOS devices and simulator. + +* **.lldbinit**: Create or edit `~/.lldbinit` to allow Chromium code to be properly source-mapped. + + ```text + # e.g: ['~/electron/src/tools/lldb'] + script sys.path[:0] = ['<...path/to/electron/src/tools/lldb>'] + script import lldbinit + ``` + +## Attaching to and Debugging Electron + +To start a debugging session, open up Terminal and start `lldb`, passing a non-release +build of Electron as a parameter. + +```sh +$ lldb ./out/Testing/Electron.app +(lldb) target create "./out/Testing/Electron.app" +Current executable set to './out/Testing/Electron.app' (x86_64). +``` + +### Setting Breakpoints + +LLDB is a powerful tool and supports multiple strategies for code inspection. For +this basic introduction, let's assume that you're calling a command from JavaScript +that isn't behaving correctly - so you'd like to break on that command's C++ +counterpart inside the Electron source. + +Relevant code files can be found in `./shell/`. + +Let's assume that you want to debug `app.setName()`, which is defined in `browser.cc` +as `Browser::SetName()`. Set the breakpoint using the `breakpoint` command, specifying +file and line to break on: + +```sh +(lldb) breakpoint set --file browser.cc --line 117 +Breakpoint 1: where = Electron Framework`atom::Browser::SetName(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) + 20 at browser.cc:118, address = 0x000000000015fdb4 +``` + +Then, start Electron: + +```sh +(lldb) run +``` + +The app will immediately be paused, since Electron sets the app's name on launch: + +```sh +(lldb) run +Process 25244 launched: '/Users/fr/Code/electron/out/Testing/Electron.app/Contents/MacOS/Electron' (x86_64) +Process 25244 stopped +* thread #1: tid = 0x839a4c, 0x0000000100162db4 Electron Framework`atom::Browser::SetName(this=0x0000000108b14f20, name="Electron") + 20 at browser.cc:118, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 + frame #0: 0x0000000100162db4 Electron Framework`atom::Browser::SetName(this=0x0000000108b14f20, name="Electron") + 20 at browser.cc:118 + 115 } + 116 + 117 void Browser::SetName(const std::string& name) { +-> 118 name_override_ = name; + 119 } + 120 + 121 int Browser::GetBadgeCount() { +(lldb) +``` + +To show the arguments and local variables for the current frame, run `frame variable` (or `fr v`), +which will show you that the app is currently setting the name to "Electron". + +```sh +(lldb) frame variable +(atom::Browser *) this = 0x0000000108b14f20 +(const string &) name = "Electron": { + [...] +} +``` + +To do a source level single step in the currently selected thread, execute `step` (or `s`). +This would take you into `name_override_.empty()`. To proceed and do a step over, +run `next` (or `n`). + +```sh +(lldb) step +Process 25244 stopped +* thread #1: tid = 0x839a4c, 0x0000000100162dcc Electron Framework`atom::Browser::SetName(this=0x0000000108b14f20, name="Electron") + 44 at browser.cc:119, queue = 'com.apple.main-thread', stop reason = step in + frame #0: 0x0000000100162dcc Electron Framework`atom::Browser::SetName(this=0x0000000108b14f20, name="Electron") + 44 at browser.cc:119 + 116 + 117 void Browser::SetName(const std::string& name) { + 118 name_override_ = name; +-> 119 } + 120 + 121 int Browser::GetBadgeCount() { + 122 return badge_count_; +``` + +**NOTE:** If you don't see source code when you think you should, you may not have added the `~/.lldbinit` file above. + +To finish debugging at this point, run `process continue`. You can also continue until a certain +line is hit in this thread (`thread until 100`). This command will run the thread in the current +frame till it reaches line 100 in this frame or stops if it leaves the current frame. + +Now, if you open up Electron's developer tools and call `setName`, you will once again hit the +breakpoint. + +### Further Reading + +LLDB is a powerful tool with a great documentation. To learn more about it, consider +Apple's debugging documentation, for instance the [LLDB Command Structure Reference][lldb-command-structure] +or the introduction to [Using LLDB as a Standalone Debugger][lldb-standalone]. + +You can also check out LLDB's fantastic [manual and tutorial][lldb-tutorial], which +will explain more complex debugging scenarios. + +[lldb-command-structure]: https://developer.apple.com/library/mac/documentation/IDEs/Conceptual/gdb_to_lldb_transition_guide/document/lldb-basics.html#//apple_ref/doc/uid/TP40012917-CH2-SW2 +[lldb-standalone]: https://developer.apple.com/library/mac/documentation/IDEs/Conceptual/gdb_to_lldb_transition_guide/document/lldb-terminal-workflow-tutorial.html +[lldb-tutorial]: https://lldb.llvm.org/tutorial.html diff --git a/docs/development/debugging-on-windows.md b/docs/development/debugging-on-windows.md new file mode 100644 index 0000000000000..0c5eadc23341c --- /dev/null +++ b/docs/development/debugging-on-windows.md @@ -0,0 +1,109 @@ +# Debugging on Windows + +If you experience crashes or issues in Electron that you believe are not caused +by your JavaScript application, but instead by Electron itself, debugging can +be a little bit tricky, especially for developers not used to native/C++ +debugging. However, using Visual Studio, Electron's hosted Symbol Server, +and the Electron source code, you can enable step-through debugging +with breakpoints inside Electron's source code. + +**See also**: There's a wealth of information on debugging Chromium, much of which also applies to Electron, on the Chromium developers site: [Debugging Chromium on Windows](https://www.chromium.org/developers/how-tos/debugging-on-windows). + +## Requirements + +* **A debug build of Electron**: The easiest way is usually building it + yourself, using the tools and prerequisites listed in the + [build instructions for Windows](build-instructions-windows.md). While you can + attach to and debug Electron as you can download it directly, you will + find that it is heavily optimized, making debugging substantially more + difficult: The debugger will not be able to show you the content of all + variables and the execution path can seem strange because of inlining, + tail calls, and other compiler optimizations. + +* **Visual Studio with C++ Tools**: The free community editions of Visual + Studio 2013 and Visual Studio 2015 both work. Once installed, + [configure Visual Studio to use Electron's Symbol server](debugging-with-symbol-server.md). + It will enable Visual Studio to gain a better understanding of what happens + inside Electron, making it easier to present variables in a human-readable + format. + +* **ProcMon**: The [free SysInternals tool][sys-internals] allows you to inspect + a process's parameters, file handles, and registry operations. + +## Attaching to and Debugging Electron + +To start a debugging session, open up PowerShell/CMD and execute your debug +build of Electron, using the application to open as a parameter. + +```powershell +$ ./out/Testing/electron.exe ~/my-electron-app/ +``` + +### Setting Breakpoints + +Then, open up Visual Studio. Electron is not built with Visual Studio and hence +does not contain a project file - you can however open up the source code files +"As File", meaning that Visual Studio will open them up by themselves. You can +still set breakpoints - Visual Studio will automatically figure out that the +source code matches the code running in the attached process and break +accordingly. + +Relevant code files can be found in `./shell/`. + +### Attaching + +You can attach the Visual Studio debugger to a running process on a local or +remote computer. After the process is running, click Debug / Attach to Process +(or press `CTRL+ALT+P`) to open the "Attach to Process" dialog box. You can use +this capability to debug apps that are running on a local or remote computer, +debug multiple processes simultaneously. + +If Electron is running under a different user account, select the +`Show processes from all users` check box. Notice that depending on how many +BrowserWindows your app opened, you will see multiple processes. A typical +one-window app will result in Visual Studio presenting you with two +`Electron.exe` entries - one for the main process and one for the renderer +process. Since the list only gives you names, there's currently no reliable +way of figuring out which is which. + +### Which Process Should I Attach to? + +Code executed within the main process (that is, code found in or eventually run +by your main JavaScript file) will run inside the main process, while other +code will execute inside its respective renderer process. + +You can be attached to multiple programs when you are debugging, but only one +program is active in the debugger at any time. You can set the active program +in the `Debug Location` toolbar or the `Processes window`. + +## Using ProcMon to Observe a Process + +While Visual Studio is fantastic for inspecting specific code paths, ProcMon's +strength is really in observing everything your application is doing with the +operating system - it captures File, Registry, Network, Process, and Profiling +details of processes. It attempts to log **all** events occurring and can be +quite overwhelming, but if you seek to understand what and how your application +is doing to the operating system, it can be a valuable resource. + +For an introduction to ProcMon's basic and advanced debugging features, go check +out [this video tutorial][procmon-instructions] provided by Microsoft. + +[sys-internals]: https://learn.microsoft.com/en-us/sysinternals/downloads/procmon +[procmon-instructions]: https://learn.microsoft.com/en-us/shows/defrag-tools/4-process-monitor + +## Using WinDbg +<!-- TODO(@codebytere): add images and more information here? --> + +It's possible to debug crashes and issues in the Renderer process with [WinDbg](https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/getting-started-with-windbg). + +To attach to a debug a process with WinDbg: + +1. Add `--renderer-startup-dialog` as a command line flag to Electron. +2. Launch the app you are intending to debug. +3. A dialog box will appear with a pid: “Renderer starting with pid: 1234”. +4. Launch WinDbg and choose “File > Attach to process” in the application menu. +5. Enter in pid from the dialog box in Step 3. +6. See that the debugger will be in a paused state, and that there is a command line in the app to enter text into. +7. Type “g” into the above command line to start the debuggee. +8. Press the enter key to continue the program. +9. Go back to the dialog box and press “ok”. diff --git a/docs/development/debugging-with-symbol-server.md b/docs/development/debugging-with-symbol-server.md new file mode 100644 index 0000000000000..276490198cf4c --- /dev/null +++ b/docs/development/debugging-with-symbol-server.md @@ -0,0 +1,57 @@ +# Setting Up Symbol Server in Debugger + +Debug symbols allow you to have better debugging sessions. They have information +about the functions contained in executables and dynamic libraries and provide +you with information to get clean call stacks. A Symbol Server allows the +debugger to load the correct symbols, binaries and sources automatically without +forcing users to download large debugging files. The server functions like +[Microsoft's symbol server](https://support.microsoft.com/kb/311503) so the +documentation there can be useful. + +Note that because released Electron builds are heavily optimized, debugging is +not always easy. The debugger will not be able to show you the content of all +variables and the execution path can seem strange because of inlining, tail +calls, and other compiler optimizations. The only workaround is to build an +unoptimized local build. + +The official symbol server URL for Electron is +[https://symbols.electronjs.org](https://symbols.electronjs.org). +You cannot visit this URL directly, you must add it to the symbol path of your +debugging tool. In the examples below, a local cache directory is used to avoid +repeatedly fetching the PDB from the server. Replace `c:\code\symbols` with an +appropriate cache directory on your machine. + +## Using the Symbol Server in Windbg + +The Windbg symbol path is configured with a string value delimited with asterisk +characters. To use only the Electron symbol server, add the following entry to +your symbol path (**Note:** you can replace `c:\code\symbols` with any writable +directory on your computer, if you'd prefer a different location for downloaded +symbols): + +```powershell +SRV*c:\code\symbols\*https://symbols.electronjs.org +``` + +Set this string as `_NT_SYMBOL_PATH` in the environment, using the Windbg menus, +or by typing the `.sympath` command. If you would like to get symbols from +Microsoft's symbol server as well, you should list that first: + +```powershell +SRV*c:\code\symbols\*https://msdl.microsoft.com/download/symbols;SRV*c:\code\symbols\*https://symbols.electronjs.org +``` + +## Using the symbol server in Visual Studio + +![Tools -> Options](../images/vs-tools-options.png) + +![Symbols Settings](../images/vs-options-debugging-symbols.png) + +## Troubleshooting: Symbols will not load + +Type the following commands in Windbg to print why symbols are not loading: + +```powershell +> !sym noisy +> .reload /f electron.exe +``` diff --git a/docs/development/debugging-with-xcode.md b/docs/development/debugging-with-xcode.md new file mode 100644 index 0000000000000..ded8328be4086 --- /dev/null +++ b/docs/development/debugging-with-xcode.md @@ -0,0 +1,30 @@ +## Debugging with XCode + +### Generate xcode project for debugging sources (cannot build code from xcode) + +Run `gn gen` with the --ide=xcode argument. + +```sh +$ gn gen out/Testing --ide=xcode +``` + +This will generate the electron.ninja.xcworkspace. You will have to open this workspace +to set breakpoints and inspect. + +See `gn help gen` for more information on generating IDE projects with GN. + +### Debugging and breakpoints + +Launch Electron app after build. +You can now open the xcode workspace created above and attach to the Electron process +through the Debug > Attach To Process > Electron debug menu. \[Note: If you want to debug +the renderer process, you need to attach to the Electron Helper as well.] + +You can now set breakpoints in any of the indexed files. However, you will not be able +to set breakpoints directly in the Chromium source. +To set break points in the Chromium source, you can choose Debug > Breakpoints > Create +Symbolic Breakpoint and set any function name as the symbol. This will set the breakpoint +for all functions with that name, from all the classes if there are more than one. +You can also do this step of setting break points prior to attaching the debugger, +however, actual breakpoints for symbolic breakpoint functions may not show up until the +debugger is attached to the app. diff --git a/docs/development/debugging.md b/docs/development/debugging.md new file mode 100644 index 0000000000000..7fc7c0bc13eaf --- /dev/null +++ b/docs/development/debugging.md @@ -0,0 +1,71 @@ +# Electron Debugging + +There are many different approaches to debugging issues and bugs in Electron, many of which +are platform specific. + +Some of the more common approaches are outlined below. + +## Generic Debugging + +Chromium contains logging macros which can aid debugging by printing information to console in C++ and Objective-C++. + +You might use this to print out variable values, function names, and line numbers, amongst other things. + +Some examples: + +```cpp +LOG(INFO) << "bitmap.width(): " << bitmap.width(); + +LOG(INFO, bitmap.width() > 10) << "bitmap.width() is greater than 10!"; +``` + +There are also different levels of logging severity: `INFO`, `WARN`, and `ERROR`. + +See [logging.h](https://chromium.googlesource.com/chromium/src/base/+/refs/heads/main/logging.h) in Chromium's source tree for more information and examples. + +## Printing Stacktraces + +Chromium contains a helper to print stack traces to console without interrupting the program. + +```cpp +#include "base/debug/stack_trace.h" +... +base::debug::StackTrace().Print(); +``` + +This will allow you to observe call chains and identify potential issue areas. + +## Breakpoint Debugging + +> Note that this will increase the size of the build significantly, taking up around 50G of disk space + +Write the following file to `electron/.git/info/exclude/debug.gn` + +```gn +import("//electron/build/args/testing.gn") +is_debug = true +symbol_level = 2 +forbid_non_component_debug_builds = false +``` + +Then execute: + +```sh +$ gn gen out/Debug --args="import(\"//electron/.git/info/exclude/debug.gn\") $GN_EXTRA_ARGS" +$ ninja -C out/Debug electron +``` + +Now you can use `LLDB` for breakpoint debugging. + +## Platform-Specific Debugging +<!-- TODO(@codebytere): add debugging file for Linux--> + +- [macOS Debugging](debugging-on-macos.md) + - [Debugging with Xcode](debugging-with-xcode.md) +- [Windows Debugging](debugging-on-windows.md) + +## Debugging with the Symbol Server + +Debug symbols allow you to have better debugging sessions. They have information about the functions contained in executables and dynamic libraries and provide you with information to get clean call stacks. A Symbol Server allows the debugger to load the correct symbols, binaries and sources automatically without forcing users to download large debugging files. + +For more information about how to set up a symbol server for Electron, see [debugging with a symbol server](debugging-with-symbol-server.md). diff --git a/docs/development/electron-vs-nwjs.md b/docs/development/electron-vs-nwjs.md deleted file mode 100644 index cb5ffcea8e376..0000000000000 --- a/docs/development/electron-vs-nwjs.md +++ /dev/null @@ -1,75 +0,0 @@ -# Technical Differences Between Electron and NW.js - -Like [NW.js][nwjs], Electron provides a platform to write desktop applications with web -technologies. Both platforms enable developers to utilize HTML, JavaScript, and -Node.js. On the surface, they seem very similar. - -There are however fundamental differences between the two projects that make -Electron a completely separate product from NW.js. - -## 1) Entry of Application - -In NW.js, the main entry point of an application can be an HTML web page. In -that case, NW.js will open the given entry point in a browser window. - -In Electron, the entry point is always a JavaScript script. Instead of providing a -URL directly, you manually create a browser window and load an HTML file using -the API. You also need to listen to window events to decide when to quit the -application. - -Electron works more like the Node.js runtime. Electron's APIs are lower level so -you can use it for browser testing in place of -[PhantomJS](https://phantomjs.org/). - -## 2) Node Integration - -In NW.js, the Node integration in web pages requires patching Chromium to work, -while in Electron we chose a different way to integrate the `libuv` loop with -each platform's message loop to avoid hacking Chromium. See the -[`node_bindings`][node-bindings] code for how that was done. - -## 3) JavaScript Contexts - -If you are an experienced NW.js user, you should be familiar with the concept of -Node context and web context. These concepts were invented because of how NW.js -was implemented. - -By using the -[multi-context](https://github.com/nodejs/node-v0.x-archive/commit/756b622) -feature of Node, Electron doesn't introduce a new JavaScript context in web -pages. - -Note: NW.js has optionally supported multi-context since 0.13. - -## 4) Legacy Support - -NW.js still offers a "legacy release" that supports Windows XP. It doesn't -receive security updates. - -Given that hardware manufacturers, Microsoft, Chromium, and Node.js haven't -released even critical security updates for that system, we have to warn you -that using Windows XP is wildly insecure and outright irresponsible. - -However, we understand that requirements outside our wildest imagination may -exist, so if you're looking for something like Electron that runs on Windows XP, -the NW.js legacy release might be the right fit for you. - -## 5) Features - -There are numerous differences in the amount of supported features. Electron has -a bigger community, more production apps using it, and [a large amount of -userland modules available on npm][electron-modules]. - -As an example, Electron has built-in support for automatic updates and countless -tools that make the creation of installers easier. As an example in favor of -NW.js, NW.js supports more `Chrome.*` APIs for the development of Chrome Apps. - -Naturally, we believe that Electron is the better platform for polished -production applications built with web technologies (like Visual Studio Code, -Slack, or Facebook Messenger); however, we want to be fair to our web technology -friends. If you have feature needs that Electron does not meet, you might want -to try NW.js. - -[nwjs]: https://nwjs.io/ -[electron-modules]: https://www.npmjs.com/search?q=electron -[node-bindings]: https://github.com/electron/electron/tree/master/lib/common diff --git a/docs/development/goma.md b/docs/development/goma.md deleted file mode 100644 index 1ba7962c4d2bb..0000000000000 --- a/docs/development/goma.md +++ /dev/null @@ -1,58 +0,0 @@ -# Goma - -> Goma is a distributed compiler service for open-source projects such as -> Chromium and Android. - -Electron has a deployment of a custom Goma Backend that we make available to -all Electron Maintainers. See the [Access](#access) section below for details -on authentication. There is also a `cache-only` Goma endpoint that will be -used by default if you do not have credentials. Requests to the cache-only -Goma will not hit our cluster, but will read from our cache and should result -in significantly faster build times. - -## Enabling Goma - -Currently the only supported way to use Goma is to use our [Build Tools](https://github.com/electron/build-tools). -Goma configuration is automatically included when you set up `build-tools`. - -If you are a maintainer and have access to our cluster, please ensure that you run -`e init` with `--goma=cluster` in order to configure `build-tools` to use -the Goma cluster. If you have an existing config, you can just set `"goma": "cluster"` -in your config file. - -## Building with Goma - -When you are using Goma you can run `ninja` with a substantially higher `j` -value than would normally be supported by your machine. - -Please do not set a value higher than **200** on Windows or Linux and -**50** on macOS. We monitor Goma system usage, and users found to be abusing -it with unreasonable concurrency will be de-activated. - -```bash -ninja -C out/Testing electron -j 200 -``` - -If you're using `build-tools`, appropriate `-j` values will automatically -be used for you. - -## Monitoring Goma - -If you access [http://localhost:8088](http://localhost:8088) on your local -machine you can monitor compile jobs as they flow through the goma system. - -## Access - -For security and cost reasons, access to Electron's Goma cluster is currently restricted -to Electron Maintainers. If you want access please head to `#access-requests` in -Slack and ping `@goma-squad` to ask for access. Please be aware that being a -maintainer does not *automatically* grant access and access is determined on a -case by case basis. - -## Uptime / Support - -We have automated monitoring of our Goma cluster and cache at https://status.notgoma.com - -We do not provide support for usage of Goma and any issues raised asking for help / having -issues will _probably_ be closed without much reason, we do not have the capacity to handle -that kind of support. diff --git a/docs/development/issues.md b/docs/development/issues.md index 7478433cdd53a..76b126bf07550 100644 --- a/docs/development/issues.md +++ b/docs/development/issues.md @@ -24,7 +24,7 @@ contribute: ## Asking for General Help -["Finding Support"](../tutorial/support.md#finding-support) has a +[The Electron website](https://www.electronjs.org/community) has a list of resources for getting programming help, reporting security issues, contributing, and more. Please use the issue tracker for bugs only! @@ -33,8 +33,7 @@ contributing, and more. Please use the issue tracker for bugs only! To submit a bug report: When opening a new issue in the [`electron/electron` issue tracker](https://github.com/electron/electron/issues/new/choose), users -will be presented with [a template](https://github.com/electron/electron/blob/master/.github/ISSUE_TEMPLATE/Bug_report.md) -that should be filled in. +will be presented with a template that should be filled in. If you believe that you have found a bug in Electron, please fill out the template to the best of your ability. @@ -58,7 +57,7 @@ unfriendly. Contributors are encouraged to solve issues collaboratively and help one another make progress. If you encounter an issue that you feel is invalid, or -which contains incorrect information, explain *why* you feel that way with +which contains incorrect information, explain _why_ you feel that way with additional supporting context, and be willing to be convinced that you may be wrong. By doing so, we can often reach the correct outcome faster. diff --git a/docs/development/patches.md b/docs/development/patches.md index 634a35c355a87..8f03da90b25ef 100644 --- a/docs/development/patches.md +++ b/docs/development/patches.md @@ -49,7 +49,8 @@ $ git commit $ ../../electron/script/git-export-patches -o ../../electron/patches/node ``` -> **NOTE**: `git-export-patches` ignores any uncommitted files, so you must create a commit if you want your changes to be exported. The subject line of the commit message will be used to derive the patch file name, and the body of the commit message should include the reason for the patch's existence. +> [!NOTE] +> `git-export-patches` ignores any uncommitted files, so you must create a commit if you want your changes to be exported. The subject line of the commit message will be used to derive the patch file name, and the body of the commit message should include the reason for the patch's existence. Re-exporting patches will sometimes cause shasums in unrelated patches to change. This is generally harmless and can be ignored (but go ahead and add those changes to your PR, it'll stop them from showing up for other people). @@ -65,6 +66,8 @@ $ git rebase --autosquash -i [COMMIT_SHA]^ $ ../electron/script/git-export-patches -o ../electron/patches/v8 ``` +Note that the `^` symbol [can cause trouble on Windows](https://stackoverflow.com/questions/14203952/git-reset-asks-more/14204318#14204318). The workaround is to either quote it `"[COMMIT_SHA]^"` or avoid it `[COMMIT_SHA]~1`. + #### Removing a patch ```bash @@ -76,7 +79,7 @@ $ ../../electron/script/git-import-patches ../../electron/patches/node $ ../../electron/script/git-export-patches -o ../../electron/patches/node ``` -Note that `git-import-patches` will mark the commit that was `HEAD` when it was run as `refs/patches/upstream-head`. This lets you keep track of which commits are from Electron patches (those that come after `refs/patches/upstream-head`) and which commits are in upstream (those before `refs/patches/upstream-head`). +Note that `git-import-patches` will mark the commit that was `HEAD` when it was run as `refs/patches/upstream-head` (and a checkout-specific `refs/patches/upstream-head-<hash>` so that gclient worktrees sharing a `.git/refs` directory don't clobber each other). This lets you keep track of which commits are from Electron patches (those that come after `refs/patches/upstream-head`) and which commits are in upstream (those before `refs/patches/upstream-head`). #### Resolving conflicts diff --git a/docs/development/pull-requests.md b/docs/development/pull-requests.md index b3f8350ead9a4..45db386808bc8 100644 --- a/docs/development/pull-requests.md +++ b/docs/development/pull-requests.md @@ -21,34 +21,43 @@ ### Step 1: Fork -Fork the project [on GitHub](https://github.com/electron/electron) and clone your fork -locally. +Fork Electron's [GitHub repository](https://github.com/electron/electron). + +### Step 2: Build + +We recommend using [`@electron/build-tools`](https://github.com/electron/build-tools) to build +Electron itself. ```sh -$ git clone git@github.com:username/electron.git -$ cd electron -$ git remote add upstream https://github.com/electron/electron.git -$ git fetch upstream +# Install build-tools package globally: +npm install -g @electron/build-tools +# Run the init script where you want to clone the project and point it to your fork: +e init --fork my-org/electron --bootstrap testing ``` -### Step 2: Build +This will create a new `electron` folder in your working directory and initialize the project. +Once the build completes, navigate to `electron/src/electron`, where your fork is actually cloned. + +> [!IMPORTANT] +> Your Electron project has a complex folder structure with nested repositories. +> See the [Build Instructions](./build-instructions-gn.md) docs for detailed Build Tools +> usage instructions (e.g. how to sync dependencies or how to recompile the binary) +> and platform-specific notices. -Build steps and dependencies differ slightly depending on your operating system. -See these detailed guides on building Electron locally: +There, you should have two `remote` URLs in git: -* [Building on macOS](https://electronjs.org/docs/development/build-instructions-macos) -* [Building on Linux](https://electronjs.org/docs/development/build-instructions-linux) -* [Building on Windows](https://electronjs.org/docs/development/build-instructions-windows) +* `origin` will point to `electron/electron` +* `fork` will point to your fork (`my-org/electron`) Once you've built the project locally, you're ready to start making changes! ### Step 3: Branch To keep your development environment organized, create local branches to -hold your work. These should be branched directly off of the `master` branch. +hold your work. These should be branched directly off of the `main` branch. ```sh -$ git checkout -b my-branch -t upstream/master +git checkout -b my-branch ``` ## Making Changes @@ -60,10 +69,10 @@ changes to either the C/C++ code in the `shell/` folder, the JavaScript code in the `lib/` folder, the documentation in `docs/api/` or tests in the `spec/` folder. -Please be sure to run `npm run lint` from time to time on any code changes +Please be sure to run `yarn lint` from time to time on any code changes to ensure that they follow the project's code style. -See [coding style](https://electronjs.org/docs/development/coding-style) for +See [coding style](coding-style.md) for more information about best practice when modifying code in different parts of the project. @@ -75,11 +84,16 @@ across multiple commits. There is no limit to the number of commits in a pull request. ```sh -$ git add my/changed/files -$ git commit +git add my/changed/files +git commit ``` -Note that multiple commits often get squashed when they are landed. +Note that multiple commits get squashed when they are landed. + +#### Commit signing + +The `electron/electron` repo enforces [commit signatures](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits) for all incoming PRs. +To sign your commits, see GitHub's documentation on [Telling Git about your signing key](https://docs.github.com/en/authentication/managing-commit-signature-verification/telling-git-about-your-signing-key). #### Commit message guidelines @@ -91,29 +105,28 @@ Before a pull request can be merged, it **must** have a pull request title with Examples of commit messages with semantic prefixes: -- `fix: don't overwrite prevent_default if default wasn't prevented` -- `feat: add app.isPackaged() method` -- `docs: app.isDefaultProtocolClient is now available on Linux` +* `fix: don't overwrite prevent_default if default wasn't prevented` +* `feat: add app.isPackaged() method` +* `docs: app.isDefaultProtocolClient is now available on Linux` Common prefixes: -- fix: A bug fix -- feat: A new feature -- docs: Documentation changes -- test: Adding missing tests or correcting existing tests -- build: Changes that affect the build system -- ci: Changes to our CI configuration files and scripts -- perf: A code change that improves performance -- refactor: A code change that neither fixes a bug nor adds a feature -- style: Changes that do not affect the meaning of the code (linting) -- vendor: Bumping a dependency like libchromiumcontent or node +* fix: A bug fix +* feat: A new feature +* docs: Documentation changes +* test: Adding missing tests or correcting existing tests +* build: Changes that affect the build system +* ci: Changes to our CI configuration files and scripts +* perf: A code change that improves performance +* refactor: A code change that neither fixes a bug nor adds a feature +* style: Changes that do not affect the meaning of the code (linting) Other things to keep in mind when writing a commit message: 1. The first line should: - - contain a short description of the change (preferably 50 characters or less, + * contain a short description of the change (preferably 50 characters or less, and no more than 72 characters) - - be entirely in lowercase with the exception of proper nouns, acronyms, and + * be entirely in lowercase with the exception of proper nouns, acronyms, and the words that refer to code, like function/variable names 2. Keep the second line blank. 3. Wrap all other lines at 72 columns. @@ -134,17 +147,17 @@ Once you have committed your changes, it is a good idea to use `git rebase` (not `git merge`) to synchronize your work with the main repository. ```sh -$ git fetch upstream -$ git rebase upstream/master +git fetch origin +git rebase origin/main ``` This ensures that your working branch has the latest changes from `electron/electron` -master. +main. ### Step 7: Test Bug fixes and features should always come with tests. A -[testing guide](https://electronjs.org/docs/development/testing) has been +[testing guide](testing.md) has been provided to make the process easier. Looking at other tests to see how they should be structured can also help. @@ -152,7 +165,7 @@ Before submitting your changes in a pull request, always run the full test suite. To run the tests: ```sh -$ npm run test +yarn test ``` Make sure the linter does not report any issues and that all tests pass. @@ -161,7 +174,7 @@ Please do not submit patches that fail either check. If you are updating tests and want to run a single spec to check it: ```sh -$ npm run test -match=menu +yarn test -match=menu ``` The above would only run spec modules matching `menu`, which is useful for @@ -175,24 +188,16 @@ begin the process of opening a pull request by pushing your working branch to your fork on GitHub. ```sh -$ git push origin my-branch +git push fork my-branch ``` ### Step 9: Opening the Pull Request From within GitHub, opening a new pull request will present you with a template -that should be filled out: - -```markdown -<!-- -Thank you for your pull request. Please provide a description above and review -the requirements below. +that should be filled out. It can be found [here](../../.github/PULL_REQUEST_TEMPLATE.md). -Bug fixes and new features should include tests and possibly benchmarks. - -Contributors guide: https://github.com/electron/electron/blob/master/CONTRIBUTING.md ---> -``` +If you do not adequately complete this template, your PR may be delayed in being merged as maintainers +seek more information or clarify ambiguities. ### Step 10: Discuss and update @@ -207,9 +212,9 @@ branch, add a new commit with those changes, and push those to your fork. GitHub will automatically update the pull request. ```sh -$ git add my/changed/files -$ git commit -$ git push origin my-branch +git add my/changed/files +git commit +git push fork my-branch ``` There are a number of more advanced mechanisms for managing commits using @@ -217,18 +222,17 @@ There are a number of more advanced mechanisms for managing commits using Feel free to post a comment in the pull request to ping reviewers if you are awaiting an answer on something. If you encounter words or acronyms that -seem unfamiliar, refer to this -[glossary](https://sites.google.com/a/chromium.org/dev/glossary). +seem unfamiliar, refer to the +[Chromium glossary](https://sites.google.com/a/chromium.org/dev/glossary). #### Approval and Request Changes Workflow -All pull requests require approval from a -[Code Owner](https://github.com/electron/electron/blob/master/.github/CODEOWNERS) +All pull requests require approval from a [Code Owner](../../.github/CODEOWNERS) of the area you modified in order to land. Whenever a maintainer reviews a pull request they may request changes. These may be small, such as fixing a typo, or may involve substantive changes. Such requests are intended to be helpful, but at times may come across as abrupt or unhelpful, especially if they do not include -concrete suggestions on *how* to change them. +concrete suggestions on _how_ to change them. Try not to be discouraged. If you feel that a review is unfair, say so or seek the input of another project contributor. Often such comments are the result of diff --git a/docs/development/reclient.md b/docs/development/reclient.md new file mode 100644 index 0000000000000..f84b0515e01dd --- /dev/null +++ b/docs/development/reclient.md @@ -0,0 +1,46 @@ +# Reclient + +> Reclient integrates with an existing build system to enable remote execution and caching of build actions. + +Electron has a deployment of a [reclient](https://github.com/bazelbuild/reclient) +compatible RBE Backend that is available to all Electron Maintainers. +See the [Access](#access) section below for details on authentication. Non-maintainers +will not have access to the cluster, but can sign in to receive a `Cache Only` token +that gives access to the cache-only CAS backend. Using this should result in +significantly faster build times . + +## Enabling Reclient + +Currently the only supported way to use Reclient is to use our [Build Tools](https://github.com/electron/build-tools). +Reclient configuration is automatically included when you set up `build-tools`. + +If you have an existing config, you can just set `"reclient": "remote_exec"` +in your config file. + +## Building with Reclient + +When you are using Reclient, you can run `autoninja` with a substantially higher `j` +value than would normally be supported by your machine. + +Please do not set a value higher than **200**. The RBE system is monitored. +Users found to be abusing it with unreasonable concurrency will be deactivated. + +```bash +autoninja -C out/Testing electron -j 200 +``` + +If you're using `build-tools`, appropriate `-j` values will automatically be used for you. + +## Access + +For security and cost reasons, access to Electron's RBE backend is currently restricted +to Electron Maintainers. If you want access, please head to `#access-requests` in +Slack and ping `@infra-wg` to ask for it. Please be aware that being a +maintainer does not _automatically_ grant access. Access is determined on a +case-by-case basis. + +## Support + +We do not provide support for usage of Reclient. Issues raised asking for help / having +issues will _probably_ be closed without much reason. We do not have the capacity to handle +that kind of support. diff --git a/docs/development/setting-up-symbol-server.md b/docs/development/setting-up-symbol-server.md deleted file mode 100644 index 8bcde9c16dcb6..0000000000000 --- a/docs/development/setting-up-symbol-server.md +++ /dev/null @@ -1,56 +0,0 @@ -# Setting Up Symbol Server in Debugger - -Debug symbols allow you to have better debugging sessions. They have information -about the functions contained in executables and dynamic libraries and provide -you with information to get clean call stacks. A Symbol Server allows the -debugger to load the correct symbols, binaries and sources automatically without -forcing users to download large debugging files. The server functions like -[Microsoft's symbol server](https://support.microsoft.com/kb/311503) so the -documentation there can be useful. - -Note that because released Electron builds are heavily optimized, debugging is -not always easy. The debugger will not be able to show you the content of all -variables and the execution path can seem strange because of inlining, tail -calls, and other compiler optimizations. The only workaround is to build an -unoptimized local build. - -The official symbol server URL for Electron is -https://symbols.electronjs.org. -You cannot visit this URL directly, you must add it to the symbol path of your -debugging tool. In the examples below, a local cache directory is used to avoid -repeatedly fetching the PDB from the server. Replace `c:\code\symbols` with an -appropriate cache directory on your machine. - -## Using the Symbol Server in Windbg - -The Windbg symbol path is configured with a string value delimited with asterisk -characters. To use only the Electron symbol server, add the following entry to -your symbol path (**Note:** you can replace `c:\code\symbols` with any writable -directory on your computer, if you'd prefer a different location for downloaded -symbols): - -```powershell -SRV*c:\code\symbols\*https://symbols.electronjs.org -``` - -Set this string as `_NT_SYMBOL_PATH` in the environment, using the Windbg menus, -or by typing the `.sympath` command. If you would like to get symbols from -Microsoft's symbol server as well, you should list that first: - -```powershell -SRV*c:\code\symbols\*https://msdl.microsoft.com/download/symbols;SRV*c:\code\symbols\*https://symbols.electronjs.org -``` - -## Using the symbol server in Visual Studio - -![Tools -> Options](https://mdn.mozillademos.org/files/733/symbol-server-vc8express-menu.jpg) -![Symbols Settings](https://mdn.mozillademos.org/files/2497/2005_options.gif) - -## Troubleshooting: Symbols will not load - -Type the following commands in Windbg to print why symbols are not loading: - -```powershell -> !sym noisy -> .reload /f electron.exe -``` diff --git a/docs/development/source-code-directory-structure.md b/docs/development/source-code-directory-structure.md index fffab3d525c10..18cbfc83ad215 100644 --- a/docs/development/source-code-directory-structure.md +++ b/docs/development/source-code-directory-structure.md @@ -3,13 +3,41 @@ The source code of Electron is separated into a few parts, mostly following Chromium on the separation conventions. -You may need to become familiar with [Chromium's multi-process -architecture](https://dev.chromium.org/developers/design-documents/multi-process-architecture) +You may need to become familiar with +[Chromium's multi-process architecture](https://www.chromium.org/developers/design-documents/multi-process-architecture/) to understand the source code better. -## Structure of Source Code +## Project structure -```diff +Electron is a complex project containing multiple upstream dependencies, which are tracked in source +control via the [`DEPS`](../../DEPS) file. When +[initializing a local Electron checkout](./build-instructions-gn.md), Electron's source code is just one +of many nested folders within the project root. + +The project contains a single `src` folder that corresponds to a specific git checkout of +[Chromium's `src` folder](https://source.chromium.org/chromium/chromium/src). In addition, Electron's +repository code is contained in `src/electron` (with its own nested git repository), and other +Electron-specific third-party dependencies (e.g. [nan](https://github.com/nodejs/nan) or +[node](https://github.com/nodejs/node)) are located in `src/third_party` (along with all other +Chromium third-party dependencies, such as WebRTC or ANGLE). + +For all code outside of `src/electron`, Electron-specific code changes are maintained via git patches. +See the [Patches](./patches.md) development guide for more information. + +```plaintext +Project Root +└── src + ├── electron + ├── third_party + │   ├── nan + │   ├── electron_node + │   └── ...other third party deps + └── ...other folders +``` + +## Structure of Electron source code + +```plaintext Electron ├── build/ - Build configuration files needed to build with GN. ├── buildflags/ - Determines the set of features that can be conditionally built. @@ -25,24 +53,23 @@ Electron ├── lib/ - JavaScript/TypeScript source code. | ├── browser/ - Main process initialization code. | | ├── api/ - API implementation for main process modules. -| | └── remote/ - Code related to the remote module as it is -| | used in the main process. | ├── common/ - Relating to logic needed by both main and renderer processes. | | └── api/ - API implementation for modules that can be used in | | both the main and renderer processes | ├── isolated_renderer/ - Handles creation of isolated renderer processes when | | contextIsolation is enabled. +| ├── node/ - Initialization code for Node.js in the main process. +│   ├── preload_realm/ - Initialization code for sandboxed renderer preload scripts. +│   │   └── api/ - API implementation for preload scripts. | ├── renderer/ - Renderer process initialization code. | | ├── api/ - API implementation for renderer process modules. -| | ├── extension/ - Code related to use of Chrome Extensions -| | | in Electron's renderer process. -| | ├── remote/ - Logic that handles use of the remote module in -| | | the main process. | | └── web-view/ - Logic that handles the use of webviews in the | | renderer process. | ├── sandboxed_renderer/ - Logic that handles creation of sandboxed renderer | | | processes. | | └── api/ - API implementation for sandboxed renderer processes. +│   ├── utility/ - Utility process initialization code. +│   │   └── api/ - API implementation for utility process modules. | └── worker/ - Logic that handles proper functionality of Node.js | environments in Web Workers. ├── patches/ - Patches applied on top of Electron's core dependencies @@ -67,31 +94,30 @@ Electron | | └── resources/ - Icons, platform-dependent files, etc. | ├── renderer/ - Code that runs in renderer process. | | └── api/ - The implementation of renderer process APIs. -| └── common/ - Code that used by both the main and renderer processes, -| | including some utility functions and code to integrate node's -| | message loop into Chromium's message loop. -| └── api/ - The implementation of common APIs, and foundations of -| Electron's built-in modules. -├── spec/ - Components of Electron's test suite run in the renderer process. -├── spec-main/ - Components of Electron's test suite run in the main process. +| ├── common/ - Code that used by both the main and renderer processes, +| | | including some helper functions and code to integrate node's +| | | message loop into Chromium's message loop. +| | └── api/ - The implementation of common APIs, and foundations of +| | Electron's built-in modules. +│   ├── services/node/ - Provides a Node.js runtime to utility processes. +│   └── utility - Code that runs in the utility process. +├── spec/ - Components of Electron's test suite run in the main process. +├── typings/ - Internal TypeScript types that aren't exported in electron.d.ts. └── BUILD.gn - Building rules of Electron. ``` -## Structure of Other Directories +## Structure of other Electron directories -* **.circleci** - Config file for CI with CircleCI. -* **.github** - GitHub-specific config files including issues templates and CODEOWNERS. +* **.github** - GitHub-specific config files including issues templates, CI with GitHub Actions and CODEOWNERS. * **dist** - Temporary directory created by `script/create-dist.py` script when creating a distribution. -* **external_binaries** - Downloaded binaries of third-party frameworks which - do not support building with `gn`. * **node_modules** - Third party node modules used for building. * **npm** - Logic for installation of Electron via npm. -* **out** - Temporary output directory of `ninja`. +* **out** - Temporary output directory for `siso`. * **script** - Scripts used for development purpose like building, packaging, testing, etc. -```diff +```plaintext script/ - The set of all scripts Electron runs for a variety of purposes. ├── codesign/ - Fakes codesigning for Electron apps; used for testing. ├── lib/ - Miscellaneous python utility scripts. @@ -100,7 +126,4 @@ script/ - The set of all scripts Electron runs for a variety of purposes. └── uploaders/ - Uploads various release-related files during release. ``` -* **tools** - Helper scripts used by GN files. - * Scripts put here should never be invoked by users directly, unlike those in `script`. * **typings** - TypeScript typings for Electron's internal code. -* **vendor** - Source code for some third party dependencies. diff --git a/docs/development/style-guide.md b/docs/development/style-guide.md new file mode 100644 index 0000000000000..e7cce2b7e7963 --- /dev/null +++ b/docs/development/style-guide.md @@ -0,0 +1,415 @@ +# Electron Documentation Style Guide + +These are the guidelines for writing Electron documentation. + +## Headings + +* Each page must have a single `#`-level title at the top. +* Chapters in the same page must have `##`-level headings. +* Sub-chapters need to increase the number of `#` in the heading according to + their nesting depth. +* The page's title must follow [APA title case][title-case]. +* All chapters must follow [APA sentence case][sentence-case]. + +Using `Quick Start` as example: + +```markdown +# Quick Start + +... + +## Main process + +... + +## Renderer process + +... + +## Run your app + +... + +### Run as a distribution + +... + +### Manually downloaded Electron binary + +... +``` + +For API references, there are exceptions to this rule. + +## Markdown rules + +This repository uses the [`markdownlint`][markdownlint] package to enforce consistent +Markdown styling. For the exact rules, see the `.markdownlint.json` file in the root +folder. + +There are a few style guidelines that aren't covered by the linter rules: + +<!--TODO(erickzhao): make sure this matches with the lint:markdownlint task--> +* Use `sh` instead of `cmd` in code blocks (due to the syntax highlighter). +* Keep line lengths between 80 and 100 characters if possible for readability + purposes. +* No nesting lists more than 2 levels (due to the markdown renderer). +* All `js` and `javascript` code blocks are linted with +[standard-markdown](https://www.npmjs.com/package/standard-markdown). +* For unordered lists, use asterisks instead of dashes. + +## Picking words + +* Use "will" over "would" when describing outcomes. +* Prefer "in the ___ process" over "on". + +## API references + +The following rules only apply to the documentation of APIs. + +### Title and description + +Each module's API doc must use the actual object name returned by `require('electron')` +as its title (such as `BrowserWindow`, `autoUpdater`, and `session`). + +Directly under the page title, add a one-line description of the module +as a markdown quote (beginning with `>`). + +Using the `session` module as an example: + +```markdown +# session + +> Manage browser sessions, cookies, cache, proxy settings, etc. +``` + +### Module methods and events + +For modules that are not classes, their methods and events must be listed under +the `## Methods` and `## Events` chapters. + +Using `autoUpdater` as an example: + +```markdown +# autoUpdater + +## Events + +### Event: 'error' + +## Methods + +### `autoUpdater.setFeedURL(options)` +``` + +### Classes + +* API classes or classes that are part of modules must be listed under a + `## Class: TheClassName` chapter. +* One page can have multiple classes. +* Constructors must be listed with `###`-level headings. +* [Static Methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/static) + must be listed under a `### Static Methods` chapter. +* [Instance Methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#Prototype_methods) + must be listed under an `### Instance Methods` chapter. +* All methods that have a return value must start their description with + "Returns `[TYPE]` - \[Return description]" + * If the method returns an `Object`, its structure can be specified using a colon + followed by a newline then an unordered list of properties in the same style as + function parameters. +* Instance Events must be listed under an `### Instance Events` chapter. +* Instance Properties must be listed under an `### Instance Properties` chapter. + * Instance Properties must start with "A \[Property Type] ..." + +Using the `Session` and `Cookies` classes as an example: + +```markdown +# session + +## Methods + +### session.fromPartition(partition) + +## Static Properties + +### session.defaultSession + +## Class: Session + +### Instance Events + +#### Event: 'will-download' + +### Instance Methods + +#### `ses.getCacheSize()` + +### Instance Properties + +#### `ses.cookies` + +## Class: Cookies + +### Instance Methods + +#### `cookies.get(filter, callback)` +``` + +### Methods and their arguments + +The methods chapter must be in the following form: + +```markdown +### `objectName.methodName(required[, optional]))` + +* `required` string - A parameter description. +* `optional` Integer (optional) - Another parameter description. + +... +``` + +#### Heading level + +The heading can be `###` or `####`-levels depending on whether the method +belongs to a module or a class. + +#### Function signature + +For modules, the `objectName` is the module's name. For classes, it must be the +name of the instance of the class, and must not be the same as the module's +name. + +For example, the methods of the `Session` class under the `session` module must +use `ses` as the `objectName`. + +Optional arguments are notated by square brackets `[]` surrounding the optional +argument as well as the comma required if this optional argument follows another +argument: + +```markdown +required[, optional] +``` + +#### Argument descriptions + +More detailed information on each of the arguments is noted in an unordered list +below the method. The type of argument is notated by either JavaScript primitives +(e.g. `string`, `Promise`, or `Object`), a custom API structure like Electron's +[`Cookie`](../api/structures/cookie.md), or the wildcard `any`. + +If the argument is of type `Array`, use `[]` shorthand with the type of value +inside the array (for example,`any[]` or `string[]`). + +If the argument is of type `Promise`, parametrize the type with what the promise +resolves to (for example, `Promise<void>` or `Promise<string>`). + +If an argument can be of multiple types, separate the types with `|`. + +The description for `Function` type arguments should make it clear how it may be +called and list the types of the parameters that will be passed to it. + +#### Platform-specific functionality + +If an argument or a method is unique to certain platforms, those platforms are +denoted using a space-delimited italicized list following the datatype. Values +can be `macOS`, `Windows` or `Linux`. + +```markdown +* `animate` boolean (optional) _macOS_ _Windows_ - Animate the thing. +``` + +### Events + +The events chapter must be in following form: + +```markdown +### Event: 'wake-up' + +Returns: + +* `time` string + +... +``` + +The heading can be `###` or `####`-levels depending on whether the event +belongs to a module or a class. + +The arguments of an event follow the same rules as methods. + +### Properties + +The properties chapter must be in following form: + +```markdown +### session.defaultSession + +... +``` + +The heading can be `###` or `####`-levels depending on whether the property +belongs to a module or a class. + +## API History + +An "API History" block is a YAML code block encapsulated by an HTML comment that +should be placed directly after the Markdown header for a class or method, like so: + +`````markdown +#### `win.setTrafficLightPosition(position)` _macOS_ + +<!-- +```YAML history +added: + - pr-url: https://github.com/electron/electron/pull/22533 +changes: + - pr-url: https://github.com/electron/electron/pull/26789 + description: "Made `trafficLightPosition` option work for `customButtonOnHover` window." +deprecated: + - pr-url: https://github.com/electron/electron/pull/37094 + breaking-changes-header: deprecated-browserwindowsettrafficlightpositionposition +``` +--> + +* `position` [Point](structures/point.md) + +Set a custom position for the traffic light buttons. Can only be used with `titleBarStyle` set to `hidden`. +````` + +It should adhere to the API History [JSON Schema](https://json-schema.org/) +(`api-history.schema.json`) which you can find in the `docs` folder. +The [API History Schema RFC][api-history-schema-rfc] includes example usage and detailed +explanations for each aspect of the schema. + +The purpose of the API History block is to describe when/where/how/why an API was: + +* Added +* Changed (usually breaking changes) +* Deprecated + +Each API change listed in the block should include a link to the +PR where that change was made along with an optional short description of the +change. If applicable, include the [heading id](https://gist.github.com/asabaylus/3071099) +for that change from the [breaking changes documentation](../breaking-changes.md). + +The [API History linting script][api-history-linting-script] (`lint:api-history`) +validates API History blocks in the Electron documentation against the schema and +performs some other checks. You can look at its [tests][api-history-tests] for more +details. + +There are a few style guidelines that aren't covered by the linting script: + +### Format + +Always adhere to this format: + + ```markdown + API HEADER | #### `win.flashFrame(flag)` + BLANK LINE | + HTML COMMENT OPENING TAG | <!-- + API HISTORY OPENING TAG | ```YAML history + API HISTORY | added: + | - pr-url: https://github.com/electron/electron/pull/22533 + API HISTORY CLOSING TAG | ``` + HTML COMMENT CLOSING TAG | --> + BLANK LINE | + ``` + +### YAML + +* Use two spaces for indentation. +* Do not use comments. + +### Descriptions + +* Always wrap descriptions with double quotation marks (i.e. "example"). + * [Certain special characters (e.g. `[`, `]`) can break YAML parsing](https:/stackoverflow.com/a/37015689/19020549). +* Describe the change in a way relevant to app developers and make it + capitalized, punctuated, and past tense. + * Refer to [Clerk](https://github.com/electron/clerk/blob/main/README.md#examples) + for examples. +* Keep descriptions concise. + * Ideally, a description will match its corresponding header in the + breaking changes document. + * Favor using the release notes from the associated PR whenever possible. + * Developers can always view the breaking changes document or linked + pull request for more details. + +### Placement + +Generally, you should place the API History block directly after the Markdown header +for a class or method that was changed. However, there are some instances where this +is ambiguous: + +#### Chromium bump + +* [chore: bump chromium to 122.0.6194.0 (main)](https://github.com/electron/electron/pull/40750) + * [Behavior Changed: cross-origin iframes now use Permission Policy to access features][api-history-cross-origin] + +Sometimes a breaking change doesn't relate to any of the existing APIs. In this +case, it is ok not to add API History anywhere. + +#### Change affecting multiple APIs + +* [refactor: ensure IpcRenderer is not bridgable](https://github.com/electron/electron/pull/40330) + * [Behavior Changed: ipcRenderer can no longer be sent over the contextBridge][api-history-ipc-renderer] + +Sometimes a breaking change involves multiple APIs. In this case, place the +API History block under the top-level Markdown header for each of the +involved APIs. + +`````markdown +# contextBridge + +<!-- +```YAML history +changes: + - pr-url: https://github.com/electron/electron/pull/40330 + description: "`ipcRenderer` can no longer be sent over the `contextBridge`" + breaking-changes-header: behavior-changed-ipcrenderer-can-no-longer-be-sent-over-the-contextbridge +``` +--> + +> Create a safe, bi-directional, synchronous bridge across isolated contexts +````` + +`````markdown +# ipcRenderer + +<!-- +```YAML history +changes: + - pr-url: https://github.com/electron/electron/pull/40330 + description: "`ipcRenderer` can no longer be sent over the `contextBridge`" + breaking-changes-header: behavior-changed-ipcrenderer-can-no-longer-be-sent-over-the-contextbridge +``` +--> + +Process: [Renderer](../glossary.md#renderer-process) +````` + +Notice how an API History block wasn't added under: + +* `contextBridge.exposeInMainWorld(apiKey, api)` + +since that function wasn't changed, only how it may be used: + +```patch + contextBridge.exposeInMainWorld('app', { +- ipcRenderer, ++ onEvent: (cb) => ipcRenderer.on('foo', (e, ...args) => cb(args)) + }) +``` + +## Documentation translations + +See [electron/i18n](https://github.com/electron/i18n#readme) + +[title-case]: https://apastyle.apa.org/style-grammar-guidelines/capitalization/title-case +[sentence-case]: https://apastyle.apa.org/style-grammar-guidelines/capitalization/sentence-case +[markdownlint]: https://github.com/DavidAnson/markdownlint +[api-history-schema-rfc]: https://github.com/electron/rfcs/blob/f36e0a8483e1ea844710890a8a7a1bd58ecbac05/text/0004-api-history-schema.md +[api-history-linting-script]: https://github.com/electron/lint-roller/blob/3030970136ec6b41028ef973f944d3e5cad68e1c/bin/lint-markdown-api-history.ts +[api-history-tests]: https://github.com/electron/lint-roller/blob/main/tests/lint-roller-markdown-api-history.spec.ts +[api-history-cross-origin]: https://github.com/electron/electron/blob/f508f6b6b570481a2b61d8c4f8c1951f492e4309/docs/breaking-changes.md#behavior-changed-cross-origin-iframes-now-use-permission-policy-to-access-features +[api-history-ipc-renderer]: https://github.com/electron/electron/blob/f508f6b6b570481a2b61d8c4f8c1951f492e4309/docs/breaking-changes.md#behavior-changed-ipcrenderer-can-no-longer-be-sent-over-the-contextbridge diff --git a/docs/development/testing.md b/docs/development/testing.md index aae9f9c76f2b7..2c99dbd122d4b 100644 --- a/docs/development/testing.md +++ b/docs/development/testing.md @@ -12,29 +12,18 @@ coding style, please see the [coding-style](coding-style.md) document. ## Linting -To ensure that your JavaScript is in compliance with the Electron coding -style, run `npm run lint-js`, which will run `standard` against both -Electron itself as well as the unit tests. If you are using an editor -with a plugin/addon system, you might want to use one of the many -[StandardJS addons][standard-addons] to be informed of coding style -violations before you ever commit them. +To ensure that your changes are in compliance with the Electron coding +style, run `npm run lint`, which will run a variety of linting checks +against your changes depending on which areas of the code they touch. -To run `standard` with parameters, run `npm run lint-js --` followed by -arguments you want passed to `standard`. - -To ensure that your C++ is in compliance with the Electron coding style, -run `npm run lint-cpp`, which runs a `cpplint` script. We recommend that -you use `clang-format` and prepared [a short tutorial](clang-format.md). - -There is not a lot of Python in this repository, but it too is governed -by coding style rules. `npm run lint-py` will check all Python, using -`pylint` to do so. +Many of these checks are included as precommit hooks, so it's likely +your error would be caught at commit time. ## Unit Tests If you are not using [build-tools](https://github.com/electron/build-tools), -ensure that that name you have configured for your -local build of Electron is one of `Testing`, `Release`, `Default`, `Debug`, or +ensure that the name you have configured for your +local build of Electron is one of `Testing`, `Release`, `Default`, or you have set `process.env.ELECTRON_OUT_DIR`. Without these set, Electron will fail to perform some pre-testing steps. @@ -48,7 +37,26 @@ To run only specific tests matching a pattern, run `npm run test -- you would like to run. As an example: If you want to run only IPC tests, you would run `npm run test -- -g ipc`. -[standard-addons]: https://standardjs.com/#are-there-text-editor-plugins +## Node.js Smoke Tests + +If you've made changes that might affect the way Node.js is embedded into Electron, +we have a test runner that runs all of the tests from Node.js, using Electron's custom fork +of Node.js. + +To run all of the Node.js tests: + +```bash +$ node script/node-spec-runner.js +``` + +To run a single Node.js test: + +```bash +$ node script/node-spec-runner.js parallel/test-crypto-keygen +``` + +where the argument passed to the runner is the path to the test in +the Node.js source tree. ### Testing on Windows 10 devices @@ -58,7 +66,7 @@ would run `npm run test -- -g ipc`. 2. Node headers have to be compiled for your configuration. ```powershell - ninja -C out\Testing third_party\electron_node:headers + ninja -C out\Testing electron:node_headers ``` 3. The electron.lib has to be copied as node.lib. @@ -71,7 +79,7 @@ would run `npm run test -- -g ipc`. #### Missing fonts -[Some Windows 10 devices](https://docs.microsoft.com/en-us/typography/fonts/windows_10_font_list) do not ship with the Meiryo font installed, which may cause a font fallback test to fail. To install Meiryo: +[Some Windows 10 devices](https://learn.microsoft.com/en-us/typography/fonts/windows_10_font_list) do not ship with the Meiryo font installed, which may cause a font fallback test to fail. To install Meiryo: 1. Push the Windows key and search for _Manage optional features_. 2. Click _Add a feature_. diff --git a/docs/experimental.md b/docs/experimental.md index b9bc620ea83a8..4d35388e2bfb2 100644 --- a/docs/experimental.md +++ b/docs/experimental.md @@ -1,6 +1,6 @@ # Experimental APIs -Some of Electrons APIs are tagged with `_Experimental_` in the documentation. +Some of Electron's APIs are tagged with `_Experimental_` in the documentation. This tag indicates that the API may not be considered stable and the API may be removed or modified more frequently than other APIs with less warning. @@ -20,4 +20,4 @@ happen at an API WG meeting. Things to consider when discussing / nominating: * During that time no major bugs / issues should have been caused by the adoption of this feature * The API is stable enough and hasn't been heavily impacted by Chromium upgrades * Is anyone using the API? -* Is the API fulfilling the original proposed usecases, does it have any gaps? +* Is the API fulfilling the original proposed use cases, does it have any gaps? diff --git a/docs/faq.md b/docs/faq.md index 174104aee9b0c..34aa74b04ab0e 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -12,19 +12,28 @@ network problems. The best resolution is to try switching networks, or wait a bit and try installing again. You can also attempt to download Electron directly from -[electron/electron/releases](https://github.com/electron/electron/releases) +[GitHub Releases](https://github.com/electron/electron/releases) if installing via `npm` is failing. -## When will Electron upgrade to latest Chrome? +If you need to install Electron through a custom mirror or proxy, see +the [Advanced Installation](./tutorial/installation.md) documentation for more details. -The Chrome version of Electron is usually bumped within one or two weeks after -a new stable Chrome version gets released. This estimate is not guaranteed and -depends on the amount of work involved with upgrading. +## How are Electron binaries downloaded? -Only the stable channel of Chrome is used. If an important fix is in beta or dev -channel, we will back-port it. +When you run `npm install electron`, the Electron binary for the corresponding version is downloaded +into your project's `node_modules` folder via npm's `postinstall` lifecycle script. -For more information, please see the [security introduction](tutorial/security.md). +This logic is handled by the [`@electron/get`](https://github.com/electron/get) utility package +under the hood. + +## When will Electron upgrade to latest Chromium? + +Every new major version of Electron releases with a Chromium major version upgrade. By releasing every +8 weeks, Electron is able to pull in every other major Chromium release on the very same day that it +releases upstream. Security fixes will be backported to stable release channels ahead of time. + +See the [Electron Releases](./tutorial/electron-timelines.md) documentation for more details or +[releases.electronjs.org](https://releases.electronjs.org) to see our Release Status dashboard. ## When will Electron upgrade to latest Node.js? @@ -60,13 +69,14 @@ garbage collected. If you encounter this problem, the following articles may prove helpful: * [Memory Management][memory-management] -* [Variable Scope][variable-scope] +* [Closures][closures] If you want a quick fix, you can make the variables global by changing your code from this: -```javascript +```js const { app, Tray } = require('electron') + app.whenReady().then(() => { const tray = new Tray('/path/to/icon.png') tray.setTitle('hello world') @@ -75,8 +85,9 @@ app.whenReady().then(() => { to this: -```javascript +```js const { app, Tray } = require('electron') + let tray = null app.whenReady().then(() => { tray = new Tray('/path/to/icon.png') @@ -92,9 +103,10 @@ for some libraries since they want to insert the symbols with the same names. To solve this, you can turn off node integration in Electron: -```javascript +```js // In the main process. const { BrowserWindow } = require('electron') + const win = new BrowserWindow({ webPreferences: { nodeIntegration: false @@ -135,14 +147,15 @@ is only available in renderer processes. If [sub-pixel anti-aliasing](https://alienryderflex.com/sub_pixel/) is deactivated, then fonts on LCD screens can look blurry. Example: -![subpixel rendering example] +![Subpixel rendering example](images/subpixel-rendering-screenshot.gif) Sub-pixel anti-aliasing needs a non-transparent background of the layer containing the font glyphs. (See [this issue](https://github.com/electron/electron/issues/6344#issuecomment-420371918) for more info). To achieve this goal, set the background in the constructor for [BrowserWindow][browser-window]: -```javascript +```js const { BrowserWindow } = require('electron') + const win = new BrowserWindow({ backgroundColor: '#fff' }) @@ -152,13 +165,19 @@ The effect is visible only on (some?) LCD screens. Even if you don't see a diffe Notice that just setting the background in the CSS does not have the desired effect. +## Class inheritance does not work with Electron built-in modules + +Electron classes cannot be subclassed with the [`extends`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/extends) +keyword (also known as class inheritance). This feature was never implemented in Electron due +to the added complexity it would add to C++/JavaScript interop in Electron's internals. + +For more information, see [electron/electron#23](https://github.com/electron/electron/issues/23). + [memory-management]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management -[variable-scope]: https://msdn.microsoft.com/library/bzt2dkta(v=vs.94).aspx -[electron-module]: https://www.npmjs.com/package/electron +[closures]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures [storage]: https://developer.mozilla.org/en-US/docs/Web/API/Storage [local-storage]: https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage [session-storage]: https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage [indexed-db]: https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API [message-port]: https://developer.mozilla.org/en-US/docs/Web/API/MessagePort [browser-window]: api/browser-window.md -[subpixel rendering example]: images/subpixel-rendering-screenshot.gif diff --git a/docs/fiddles/.eslintrc.json b/docs/fiddles/.eslintrc.json new file mode 100644 index 0000000000000..d08c95eee921e --- /dev/null +++ b/docs/fiddles/.eslintrc.json @@ -0,0 +1,6 @@ +{ + "extends": "standard", + "rules": { + "import/order": "off" + } +} diff --git a/docs/fiddles/communication/two-processes/asynchronous-messages/index.html b/docs/fiddles/communication/two-processes/asynchronous-messages/index.html deleted file mode 100644 index 43d23a29087f2..0000000000000 --- a/docs/fiddles/communication/two-processes/asynchronous-messages/index.html +++ /dev/null @@ -1,27 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <meta charset="UTF-8"> - </head> - <body> - <div> - <div> - <h1>Asynchronous messages</h1> - <i>Supports: Win, macOS, Linux <span>|</span> Process: Both</i> - <div> - <div> - <button id="async-msg">Ping</button> - <span id="async-reply"></span> - </div> - <p>Using <code>ipc</code> to send messages between processes asynchronously is the preferred method since it will return when finished without blocking other operations in the same process.</p> - - <p>This example sends a "ping" from this process (renderer) to the main process. The main process then replies with "pong".</p> - </div> - </div> - </div> - <script> - // You can also require other files to run in this process - require('./renderer.js') - </script> - </body> -</html> diff --git a/docs/fiddles/communication/two-processes/asynchronous-messages/main.js b/docs/fiddles/communication/two-processes/asynchronous-messages/main.js deleted file mode 100644 index 942f7022f8590..0000000000000 --- a/docs/fiddles/communication/two-processes/asynchronous-messages/main.js +++ /dev/null @@ -1,29 +0,0 @@ -const { app, BrowserWindow, ipcMain } = require('electron') - -let mainWindow = null - -function createWindow () { - const windowOptions = { - width: 600, - height: 400, - title: 'Asynchronous messages', - webPreferences: { - nodeIntegration: true - } - } - - mainWindow = new BrowserWindow(windowOptions) - mainWindow.loadFile('index.html') - - mainWindow.on('closed', () => { - mainWindow = null - }) -} - -app.whenReady().then(() => { - createWindow() -}) - -ipcMain.on('asynchronous-message', (event, arg) => { - event.sender.send('asynchronous-reply', 'pong') -}) diff --git a/docs/fiddles/communication/two-processes/asynchronous-messages/renderer.js b/docs/fiddles/communication/two-processes/asynchronous-messages/renderer.js deleted file mode 100644 index 40ed596201ad2..0000000000000 --- a/docs/fiddles/communication/two-processes/asynchronous-messages/renderer.js +++ /dev/null @@ -1,12 +0,0 @@ -const { ipcRenderer } = require('electron') - -const asyncMsgBtn = document.getElementById('async-msg') - -asyncMsgBtn.addEventListener('click', () => { - ipcRenderer.send('asynchronous-message', 'ping') -}) - -ipcRenderer.on('asynchronous-reply', (event, arg) => { - const message = `Asynchronous message reply: ${arg}` - document.getElementById('async-reply').innerHTML = message -}) diff --git a/docs/fiddles/communication/two-processes/synchronous-messages/index.html b/docs/fiddles/communication/two-processes/synchronous-messages/index.html deleted file mode 100644 index 055fcf3473ce1..0000000000000 --- a/docs/fiddles/communication/two-processes/synchronous-messages/index.html +++ /dev/null @@ -1,27 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <meta charset="UTF-8"> - </head> - <body> - <div> - <div> - <h1>Synchronous messages</h1> - <i>Supports: Win, macOS, Linux <span>|</span> Process: Both</i> - <div> - <div> - <button id="sync-msg">Ping</button> - <span id="sync-reply"></span> - </div> - <p>You can use the <code>ipc</code> module to send synchronous messages between processes as well, but note that the synchronous nature of this method means that it <b>will block</b> other operations while completing its task.</p> - - <p>This example sends a synchronous message, "ping", from this process (renderer) to the main process. The main process then replies with "pong".</p> - </div> - </div> - </div> - <script> - // You can also require other files to run in this process - require('./renderer.js') - </script> - </body> -</html> \ No newline at end of file diff --git a/docs/fiddles/communication/two-processes/synchronous-messages/main.js b/docs/fiddles/communication/two-processes/synchronous-messages/main.js deleted file mode 100644 index 1adb7c02c9f11..0000000000000 --- a/docs/fiddles/communication/two-processes/synchronous-messages/main.js +++ /dev/null @@ -1,29 +0,0 @@ -const { app, BrowserWindow, ipcMain } = require('electron') - -let mainWindow = null - -function createWindow () { - const windowOptions = { - width: 600, - height: 400, - title: 'Synchronous Messages', - webPreferences: { - nodeIntegration: true - } - } - - mainWindow = new BrowserWindow(windowOptions) - mainWindow.loadFile('index.html') - - mainWindow.on('closed', () => { - mainWindow = null - }) -} - -app.whenReady().then(() => { - createWindow() -}) - -ipcMain.on('synchronous-message', (event, arg) => { - event.returnValue = 'pong' -}) \ No newline at end of file diff --git a/docs/fiddles/communication/two-processes/synchronous-messages/renderer.js b/docs/fiddles/communication/two-processes/synchronous-messages/renderer.js deleted file mode 100644 index 4769b6f97f714..0000000000000 --- a/docs/fiddles/communication/two-processes/synchronous-messages/renderer.js +++ /dev/null @@ -1,9 +0,0 @@ -const { ipcRenderer } = require('electron') - -const syncMsgBtn = document.getElementById('sync-msg') - -syncMsgBtn.addEventListener('click', () => { - const reply = ipcRenderer.sendSync('synchronous-message', 'ping') - const message = `Synchronous message reply: ${reply}` - document.getElementById('sync-reply').innerHTML = message -}) \ No newline at end of file diff --git a/docs/fiddles/features/dark-mode/index.html b/docs/fiddles/features/dark-mode/index.html new file mode 100644 index 0000000000000..85fd15ada5b28 --- /dev/null +++ b/docs/fiddles/features/dark-mode/index.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="UTF-8"> + <title>Hello World! + + + + +

Hello World!

+

Current theme source: System

+ + + + + + + diff --git a/docs/fiddles/features/dark-mode/main.js b/docs/fiddles/features/dark-mode/main.js new file mode 100644 index 0000000000000..00a343c8ac182 --- /dev/null +++ b/docs/fiddles/features/dark-mode/main.js @@ -0,0 +1,43 @@ +const { app, BrowserWindow, ipcMain, nativeTheme } = require('electron/main') +const path = require('node:path') + +function createWindow () { + const win = new BrowserWindow({ + width: 800, + height: 600, + webPreferences: { + preload: path.join(__dirname, 'preload.js') + } + }) + + win.loadFile('index.html') +} + +ipcMain.handle('dark-mode:toggle', () => { + if (nativeTheme.shouldUseDarkColors) { + nativeTheme.themeSource = 'light' + } else { + nativeTheme.themeSource = 'dark' + } + return nativeTheme.shouldUseDarkColors +}) + +ipcMain.handle('dark-mode:system', () => { + nativeTheme.themeSource = 'system' +}) + +app.whenReady().then(() => { + createWindow() + + app.on('activate', () => { + if (BrowserWindow.getAllWindows().length === 0) { + createWindow() + } + }) +}) + +app.on('window-all-closed', () => { + if (process.platform !== 'darwin') { + app.quit() + } +}) diff --git a/docs/fiddles/features/dark-mode/preload.js b/docs/fiddles/features/dark-mode/preload.js new file mode 100644 index 0000000000000..752d9d71a0a57 --- /dev/null +++ b/docs/fiddles/features/dark-mode/preload.js @@ -0,0 +1,6 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('darkMode', { + toggle: () => ipcRenderer.invoke('dark-mode:toggle'), + system: () => ipcRenderer.invoke('dark-mode:system') +}) diff --git a/docs/fiddles/features/dark-mode/renderer.js b/docs/fiddles/features/dark-mode/renderer.js new file mode 100644 index 0000000000000..637f714c22406 --- /dev/null +++ b/docs/fiddles/features/dark-mode/renderer.js @@ -0,0 +1,9 @@ +document.getElementById('toggle-dark-mode').addEventListener('click', async () => { + const isDarkMode = await window.darkMode.toggle() + document.getElementById('theme-source').innerHTML = isDarkMode ? 'Dark' : 'Light' +}) + +document.getElementById('reset-to-system').addEventListener('click', async () => { + await window.darkMode.system() + document.getElementById('theme-source').innerHTML = 'System' +}) diff --git a/docs/fiddles/features/dark-mode/styles.css b/docs/fiddles/features/dark-mode/styles.css new file mode 100644 index 0000000000000..8f9ad8f04d39e --- /dev/null +++ b/docs/fiddles/features/dark-mode/styles.css @@ -0,0 +1,11 @@ +:root { + color-scheme: light dark; +} + +@media (prefers-color-scheme: dark) { + body { background: #333; color: white; } +} + +@media (prefers-color-scheme: light) { + body { background: #ddd; color: black; } +} diff --git a/docs/fiddles/features/drag-and-drop/index.html b/docs/fiddles/features/drag-and-drop/index.html new file mode 100644 index 0000000000000..7541c174b86fd --- /dev/null +++ b/docs/fiddles/features/drag-and-drop/index.html @@ -0,0 +1,15 @@ + + + + + Hello World! + + + +

Hello World!

+

Drag the boxes below to somewhere in your OS (Finder/Explorer, Desktop, etc.) to copy an example markdown file.

+
Drag me - File 1
+
Drag me - File 2
+ + + diff --git a/docs/fiddles/features/drag-and-drop/main.js b/docs/fiddles/features/drag-and-drop/main.js new file mode 100644 index 0000000000000..0cf045a7c9b82 --- /dev/null +++ b/docs/fiddles/features/drag-and-drop/main.js @@ -0,0 +1,48 @@ +const { app, BrowserWindow, ipcMain } = require('electron/main') +const path = require('node:path') +const fs = require('node:fs') +const https = require('node:https') + +function createWindow () { + const win = new BrowserWindow({ + width: 800, + height: 600, + webPreferences: { + preload: path.join(__dirname, 'preload.js') + } + }) + + win.loadFile('index.html') +} + +const iconName = path.join(__dirname, 'iconForDragAndDrop.png') +const icon = fs.createWriteStream(iconName) + +// Create a new file to copy - you can also copy existing files. +fs.writeFileSync(path.join(__dirname, 'drag-and-drop-1.md'), '# First file to test drag and drop') +fs.writeFileSync(path.join(__dirname, 'drag-and-drop-2.md'), '# Second file to test drag and drop') + +https.get('https://img.icons8.com/ios/452/drag-and-drop.png', (response) => { + response.pipe(icon) +}) + +app.whenReady().then(createWindow) + +ipcMain.on('ondragstart', (event, filePath) => { + event.sender.startDrag({ + file: path.join(__dirname, filePath), + icon: iconName + }) +}) + +app.on('window-all-closed', () => { + if (process.platform !== 'darwin') { + app.quit() + } +}) + +app.on('activate', () => { + if (BrowserWindow.getAllWindows().length === 0) { + createWindow() + } +}) diff --git a/docs/fiddles/features/drag-and-drop/preload.js b/docs/fiddles/features/drag-and-drop/preload.js new file mode 100644 index 0000000000000..3c02ab61c1eb5 --- /dev/null +++ b/docs/fiddles/features/drag-and-drop/preload.js @@ -0,0 +1,5 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electron', { + startDrag: (fileName) => ipcRenderer.send('ondragstart', fileName) +}) diff --git a/docs/fiddles/features/drag-and-drop/renderer.js b/docs/fiddles/features/drag-and-drop/renderer.js new file mode 100644 index 0000000000000..b402fa3929258 --- /dev/null +++ b/docs/fiddles/features/drag-and-drop/renderer.js @@ -0,0 +1,9 @@ +document.getElementById('drag1').ondragstart = (event) => { + event.preventDefault() + window.electron.startDrag('drag-and-drop-1.md') +} + +document.getElementById('drag2').ondragstart = (event) => { + event.preventDefault() + window.electron.startDrag('drag-and-drop-2.md') +} diff --git a/docs/fiddles/features/keyboard-shortcuts/interception-from-main/index.html b/docs/fiddles/features/keyboard-shortcuts/interception-from-main/index.html new file mode 100644 index 0000000000000..ff4540a3c9b2e --- /dev/null +++ b/docs/fiddles/features/keyboard-shortcuts/interception-from-main/index.html @@ -0,0 +1,12 @@ + + + + + Hello World! + + + +

Hello World!

+

Hit Ctrl+I to see a message printed to the console.

+ + diff --git a/docs/fiddles/features/keyboard-shortcuts/interception-from-main/main.js b/docs/fiddles/features/keyboard-shortcuts/interception-from-main/main.js new file mode 100644 index 0000000000000..62df976ea79e3 --- /dev/null +++ b/docs/fiddles/features/keyboard-shortcuts/interception-from-main/main.js @@ -0,0 +1,13 @@ +const { app, BrowserWindow } = require('electron/main') + +app.whenReady().then(() => { + const win = new BrowserWindow({ width: 800, height: 600 }) + + win.loadFile('index.html') + win.webContents.on('before-input-event', (event, input) => { + if (input.control && input.key.toLowerCase() === 'i') { + console.log('Pressed Control+I') + event.preventDefault() + } + }) +}) diff --git a/docs/fiddles/features/keyboard-shortcuts/web-apis/index.html b/docs/fiddles/features/keyboard-shortcuts/web-apis/index.html new file mode 100644 index 0000000000000..4effa03fc9f21 --- /dev/null +++ b/docs/fiddles/features/keyboard-shortcuts/web-apis/index.html @@ -0,0 +1,17 @@ + + + + + + + + Hello World! + + +

Hello World!

+ +

Hit any key with this window focused to see it captured here.

+
Last Key Pressed:
+ + + diff --git a/docs/fiddles/features/keyboard-shortcuts/web-apis/main.js b/docs/fiddles/features/keyboard-shortcuts/web-apis/main.js new file mode 100644 index 0000000000000..cf335b4a8433f --- /dev/null +++ b/docs/fiddles/features/keyboard-shortcuts/web-apis/main.js @@ -0,0 +1,33 @@ +// Modules to control application life and create native browser window +const { app, BrowserWindow } = require('electron/main') + +function createWindow () { + // Create the browser window. + const mainWindow = new BrowserWindow({ + width: 800, + height: 600 + }) + + // and load the index.html of the app. + mainWindow.loadFile('index.html') +} + +// This method will be called when Electron has finished +// initialization and is ready to create browser windows. +// Some APIs can only be used after this event occurs. +app.whenReady().then(() => { + createWindow() + + app.on('activate', function () { + // On macOS it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) +}) + +// Quit when all windows are closed, except on macOS. There, it's common +// for applications and their menu bar to stay active until the user quits +// explicitly with Cmd + Q. +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit() +}) diff --git a/docs/fiddles/features/keyboard-shortcuts/web-apis/renderer.js b/docs/fiddles/features/keyboard-shortcuts/web-apis/renderer.js new file mode 100644 index 0000000000000..e3e05209207dc --- /dev/null +++ b/docs/fiddles/features/keyboard-shortcuts/web-apis/renderer.js @@ -0,0 +1,7 @@ +function handleKeyPress (event) { + // You can put code here to handle the keypress. + document.getElementById('last-keypress').innerText = event.key + console.log(`You pressed ${event.key}`) +} + +window.addEventListener('keyup', handleKeyPress, true) diff --git a/docs/fiddles/features/navigation-history/index.html b/docs/fiddles/features/navigation-history/index.html new file mode 100644 index 0000000000000..584e04a26389d --- /dev/null +++ b/docs/fiddles/features/navigation-history/index.html @@ -0,0 +1,32 @@ + + + + + Enhanced Browser with Navigation History + + + + + +
+ + + + + + +
+ +
+ +
+

Navigation History Demo

+

This demo showcases Electron's NavigationHistory API functionality.

+

Back/Forward: Navigate through your browsing history.

+

Back History/Forward History: View and select from your browsing history.

+

URL Bar: Enter a URL and click 'Go' or press Enter to navigate.

+
+ + + + diff --git a/docs/fiddles/features/navigation-history/main.js b/docs/fiddles/features/navigation-history/main.js new file mode 100644 index 0000000000000..61f240f29fc67 --- /dev/null +++ b/docs/fiddles/features/navigation-history/main.js @@ -0,0 +1,58 @@ +const { app, BrowserWindow, BrowserView, ipcMain } = require('electron') +const path = require('path') + +function createWindow () { + const mainWindow = new BrowserWindow({ + width: 1000, + height: 800, + webPreferences: { + preload: path.join(__dirname, 'preload.js'), + nodeIntegration: false, + contextIsolation: true + } + }) + + mainWindow.loadFile('index.html') + + const view = new BrowserView() + mainWindow.setBrowserView(view) + view.setBounds({ x: 0, y: 100, width: 1000, height: 800 }) + view.setAutoResize({ width: true, height: true }) + + const navigationHistory = view.webContents.navigationHistory + ipcMain.handle('nav:back', () => + navigationHistory.goBack() + ) + + ipcMain.handle('nav:forward', () => { + navigationHistory.goForward() + }) + + ipcMain.handle('nav:canGoBack', () => navigationHistory.canGoBack()) + ipcMain.handle('nav:canGoForward', () => navigationHistory.canGoForward()) + ipcMain.handle('nav:loadURL', (_, url) => + view.webContents.loadURL(url) + ) + ipcMain.handle('nav:getCurrentURL', () => view.webContents.getURL()) + ipcMain.handle('nav:getHistory', () => { + return navigationHistory.getAllEntries() + }) + + view.webContents.on('did-navigate', () => { + mainWindow.webContents.send('nav:updated') + }) + + view.webContents.on('did-navigate-in-page', () => { + mainWindow.webContents.send('nav:updated') + }) +} + +app.whenReady().then(createWindow) + +app.on('window-all-closed', () => { + if (process.platform !== 'darwin') app.quit() +}) + +app.on('activate', () => { + if (BrowserWindow.getAllWindows().length === 0) createWindow() +}) diff --git a/docs/fiddles/features/navigation-history/preload.js b/docs/fiddles/features/navigation-history/preload.js new file mode 100644 index 0000000000000..6d5c38976cc91 --- /dev/null +++ b/docs/fiddles/features/navigation-history/preload.js @@ -0,0 +1,12 @@ +const { contextBridge, ipcRenderer } = require('electron') + +contextBridge.exposeInMainWorld('electronAPI', { + goBack: () => ipcRenderer.invoke('nav:back'), + goForward: () => ipcRenderer.invoke('nav:forward'), + canGoBack: () => ipcRenderer.invoke('nav:canGoBack'), + canGoForward: () => ipcRenderer.invoke('nav:canGoForward'), + loadURL: (url) => ipcRenderer.invoke('nav:loadURL', url), + getCurrentURL: () => ipcRenderer.invoke('nav:getCurrentURL'), + getHistory: () => ipcRenderer.invoke('nav:getHistory'), + onNavigationUpdate: (callback) => ipcRenderer.on('nav:updated', callback) +}) diff --git a/docs/fiddles/features/navigation-history/renderer.js b/docs/fiddles/features/navigation-history/renderer.js new file mode 100644 index 0000000000000..741cc80933079 --- /dev/null +++ b/docs/fiddles/features/navigation-history/renderer.js @@ -0,0 +1,84 @@ +const backBtn = document.getElementById('backBtn') +const forwardBtn = document.getElementById('forwardBtn') +const backHistoryBtn = document.getElementById('backHistoryBtn') +const forwardHistoryBtn = document.getElementById('forwardHistoryBtn') +const urlInput = document.getElementById('urlInput') +const goBtn = document.getElementById('goBtn') +const historyPanel = document.getElementById('historyPanel') + +async function updateButtons () { + const canGoBack = await window.electronAPI.canGoBack() + const canGoForward = await window.electronAPI.canGoForward() + backBtn.disabled = !canGoBack + backHistoryBtn.disabled = !canGoBack + + forwardBtn.disabled = !canGoForward + forwardHistoryBtn.disabled = !canGoForward +} + +async function updateURL () { + urlInput.value = await window.electronAPI.getCurrentURL() +} + +function transformURL (url) { + if (!url.startsWith('http://') && !url.startsWith('https://')) { + const updatedUrl = 'https://' + url + return updatedUrl + } + return url +} + +async function navigate (url) { + const urlInput = transformURL(url) + + await window.electronAPI.loadURL(urlInput) +} + +async function showHistory (forward = false) { + const history = await window.electronAPI.getHistory() + const currentIndex = history.findIndex(entry => entry.url === transformURL(urlInput.value)) + + if (!currentIndex) { + return + } + + const relevantHistory = forward + ? history.slice(currentIndex + 1) + : history.slice(0, currentIndex).reverse() + + historyPanel.innerHTML = '' + relevantHistory.forEach(entry => { + const div = document.createElement('div') + div.textContent = `Title: ${entry.title}, URL: ${entry.url}` + div.onclick = () => navigate(entry.url) + historyPanel.appendChild(div) + }) + + historyPanel.style.display = 'block' +} + +backBtn.addEventListener('click', () => window.electronAPI.goBack()) +forwardBtn.addEventListener('click', () => window.electronAPI.goForward()) +backHistoryBtn.addEventListener('click', () => showHistory(false)) +forwardHistoryBtn.addEventListener('click', () => showHistory(true)) +goBtn.addEventListener('click', () => navigate(urlInput.value)) + +urlInput.addEventListener('keypress', (e) => { + if (e.key === 'Enter') { + navigate(urlInput.value) + } +}) + +document.addEventListener('click', (e) => { + if (e.target !== historyPanel && !historyPanel.contains(e.target) && + e.target !== backHistoryBtn && e.target !== forwardHistoryBtn) { + historyPanel.style.display = 'none' + } +}) + +window.electronAPI.onNavigationUpdate(() => { + updateButtons() + updateURL() +}) + +updateButtons() diff --git a/docs/fiddles/features/navigation-history/style.css b/docs/fiddles/features/navigation-history/style.css new file mode 100644 index 0000000000000..955e8482eaea4 --- /dev/null +++ b/docs/fiddles/features/navigation-history/style.css @@ -0,0 +1,58 @@ +body { + margin: 0; + font-family: Arial, sans-serif; + background-color: #f0f0f0; +} +#controls { + display: flex; + align-items: center; + padding: 10px; + background-color: #ffffff; + border-bottom: 1px solid #ccc; +} +button { + margin-right: 10px; + padding: 8px 12px; + font-size: 14px; + background-color: #4CAF50; + color: white; + border: none; + cursor: pointer; + transition: background-color 0.3s; +} +button:hover { + background-color: #45a049; +} +button:disabled { + background-color: #cccccc; + cursor: not-allowed; +} +#urlInput { + flex-grow: 1; + margin: 0 10px; + padding: 8px; + font-size: 14px; +} + +#historyPanel { + display: none; + position: absolute; + top: 60px; + left: 10px; + background: white; + border: 1px solid #ccc; + padding: 10px; + max-height: 300px; + overflow-y: auto; + z-index: 1000; +} + #historyPanel div { + cursor: pointer; + padding: 5px; +} + +#description { + background-color: #f0f0f0; + padding: 10px; + margin-top: 150px; +} diff --git a/docs/fiddles/features/notifications/main/index.html b/docs/fiddles/features/notifications/main/index.html new file mode 100644 index 0000000000000..3c23f9066d9c1 --- /dev/null +++ b/docs/fiddles/features/notifications/main/index.html @@ -0,0 +1,12 @@ + + + + + Hello World! + + + +

Hello World!

+

After launching this application, you should see the system notification.

+ + diff --git a/docs/fiddles/features/notifications/main/main.js b/docs/fiddles/features/notifications/main/main.js new file mode 100644 index 0000000000000..b092c9a6ef4e8 --- /dev/null +++ b/docs/fiddles/features/notifications/main/main.js @@ -0,0 +1,31 @@ +const { app, BrowserWindow, Notification } = require('electron/main') + +function createWindow () { + const win = new BrowserWindow({ + width: 800, + height: 600 + }) + + win.loadFile('index.html') +} + +const NOTIFICATION_TITLE = 'Basic Notification' +const NOTIFICATION_BODY = 'Notification from the Main process' + +function showNotification () { + new Notification({ title: NOTIFICATION_TITLE, body: NOTIFICATION_BODY }).show() +} + +app.whenReady().then(createWindow).then(showNotification) + +app.on('window-all-closed', () => { + if (process.platform !== 'darwin') { + app.quit() + } +}) + +app.on('activate', () => { + if (BrowserWindow.getAllWindows().length === 0) { + createWindow() + } +}) diff --git a/docs/fiddles/features/notifications/renderer/index.html b/docs/fiddles/features/notifications/renderer/index.html new file mode 100644 index 0000000000000..206eadb3a3dd6 --- /dev/null +++ b/docs/fiddles/features/notifications/renderer/index.html @@ -0,0 +1,15 @@ + + + + + Hello World! + + + +

Hello World!

+

After launching this application, you should see the system notification.

+

Click it to see the effect in this interface.

+ + + + diff --git a/docs/fiddles/features/notifications/renderer/main.js b/docs/fiddles/features/notifications/renderer/main.js new file mode 100644 index 0000000000000..9f26d370c6ef3 --- /dev/null +++ b/docs/fiddles/features/notifications/renderer/main.js @@ -0,0 +1,24 @@ +const { app, BrowserWindow } = require('electron/main') + +function createWindow () { + const win = new BrowserWindow({ + width: 800, + height: 600 + }) + + win.loadFile('index.html') +} + +app.whenReady().then(createWindow) + +app.on('window-all-closed', () => { + if (process.platform !== 'darwin') { + app.quit() + } +}) + +app.on('activate', () => { + if (BrowserWindow.getAllWindows().length === 0) { + createWindow() + } +}) diff --git a/docs/fiddles/features/notifications/renderer/renderer.js b/docs/fiddles/features/notifications/renderer/renderer.js new file mode 100644 index 0000000000000..09099326b0849 --- /dev/null +++ b/docs/fiddles/features/notifications/renderer/renderer.js @@ -0,0 +1,6 @@ +const NOTIFICATION_TITLE = 'Title' +const NOTIFICATION_BODY = 'Notification from the Renderer process. Click to log to console.' +const CLICK_MESSAGE = 'Notification clicked!' + +new window.Notification(NOTIFICATION_TITLE, { body: NOTIFICATION_BODY }) + .onclick = () => { document.getElementById('output').innerText = CLICK_MESSAGE } diff --git a/docs/fiddles/features/offscreen-rendering/main.js b/docs/fiddles/features/offscreen-rendering/main.js new file mode 100644 index 0000000000000..6c64afb10f654 --- /dev/null +++ b/docs/fiddles/features/offscreen-rendering/main.js @@ -0,0 +1,38 @@ +const { app, BrowserWindow } = require('electron/main') +const fs = require('node:fs') +const path = require('node:path') + +app.disableHardwareAcceleration() + +function createWindow () { + const win = new BrowserWindow({ + width: 800, + height: 600, + webPreferences: { + offscreen: true + } + }) + + win.loadURL('https://github.com') + win.webContents.on('paint', (event, dirty, image) => { + fs.writeFileSync('ex.png', image.toPNG()) + }) + win.webContents.setFrameRate(60) + console.log(`The screenshot has been successfully saved to ${path.join(process.cwd(), 'ex.png')}`) +} + +app.whenReady().then(() => { + createWindow() + + app.on('activate', () => { + if (BrowserWindow.getAllWindows().length === 0) { + createWindow() + } + }) +}) + +app.on('window-all-closed', () => { + if (process.platform !== 'darwin') { + app.quit() + } +}) diff --git a/docs/fiddles/features/online-detection/index.html b/docs/fiddles/features/online-detection/index.html new file mode 100644 index 0000000000000..2ff4b4f3633e8 --- /dev/null +++ b/docs/fiddles/features/online-detection/index.html @@ -0,0 +1,13 @@ + + + + + Hello World! + + + +

Connection status:

+ + + + diff --git a/docs/fiddles/features/online-detection/main.js b/docs/fiddles/features/online-detection/main.js new file mode 100644 index 0000000000000..4e9a092cb13f2 --- /dev/null +++ b/docs/fiddles/features/online-detection/main.js @@ -0,0 +1,26 @@ +const { app, BrowserWindow } = require('electron/main') + +function createWindow () { + const onlineStatusWindow = new BrowserWindow({ + width: 300, + height: 200 + }) + + onlineStatusWindow.loadFile('index.html') +} + +app.whenReady().then(() => { + createWindow() + + app.on('activate', () => { + if (BrowserWindow.getAllWindows().length === 0) { + createWindow() + } + }) +}) + +app.on('window-all-closed', () => { + if (process.platform !== 'darwin') { + app.quit() + } +}) diff --git a/docs/fiddles/features/online-detection/renderer.js b/docs/fiddles/features/online-detection/renderer.js new file mode 100644 index 0000000000000..223a517ae1677 --- /dev/null +++ b/docs/fiddles/features/online-detection/renderer.js @@ -0,0 +1,8 @@ +function onlineStatusIndicator () { + document.getElementById('status').innerHTML = navigator.onLine ? 'online' : 'offline' +} + +window.addEventListener('online', onlineStatusIndicator) +window.addEventListener('offline', onlineStatusIndicator) + +onlineStatusIndicator() diff --git a/docs/fiddles/features/progress-bar/index.html b/docs/fiddles/features/progress-bar/index.html new file mode 100644 index 0000000000000..d68c5129a6c2b --- /dev/null +++ b/docs/fiddles/features/progress-bar/index.html @@ -0,0 +1,15 @@ + + + + + Hello World! + + + +

Hello World!

+

Keep an eye on the dock (Mac) or taskbar (Windows, Unity) for this application!

+

It should indicate a progress that advances from 0 to 100%.

+

It should then show indeterminate (Windows) or pin at 100% (other operating systems) + briefly and then loop.

+ + diff --git a/docs/fiddles/features/progress-bar/main.js b/docs/fiddles/features/progress-bar/main.js new file mode 100644 index 0000000000000..4bcc1f55361f9 --- /dev/null +++ b/docs/fiddles/features/progress-bar/main.js @@ -0,0 +1,48 @@ +const { app, BrowserWindow } = require('electron/main') + +let progressInterval + +function createWindow () { + const win = new BrowserWindow({ + width: 800, + height: 600 + }) + + win.loadFile('index.html') + + const INCREMENT = 0.03 + const INTERVAL_DELAY = 100 // ms + + let c = 0 + progressInterval = setInterval(() => { + // update progress bar to next value + // values between 0 and 1 will show progress, >1 will show indeterminate or stick at 100% + win.setProgressBar(c) + + // increment or reset progress bar + if (c < 2) { + c += INCREMENT + } else { + c = (-INCREMENT * 5) // reset to a bit less than 0 to show reset state + } + }, INTERVAL_DELAY) +} + +app.whenReady().then(createWindow) + +// before the app is terminated, clear both timers +app.on('before-quit', () => { + clearInterval(progressInterval) +}) + +app.on('window-all-closed', () => { + if (process.platform !== 'darwin') { + app.quit() + } +}) + +app.on('activate', () => { + if (BrowserWindow.getAllWindows().length === 0) { + createWindow() + } +}) diff --git a/docs/fiddles/features/recent-documents/index.html b/docs/fiddles/features/recent-documents/index.html new file mode 100644 index 0000000000000..62aae8f8a25c3 --- /dev/null +++ b/docs/fiddles/features/recent-documents/index.html @@ -0,0 +1,15 @@ + + + + + Recent Documents + + + +

Recent Documents

+

+ Right click on the app icon to see recent documents. + You should see `recently-used.md` added to the list of recent files +

+ + diff --git a/docs/fiddles/features/recent-documents/main.js b/docs/fiddles/features/recent-documents/main.js new file mode 100644 index 0000000000000..c4a399a78cdcd --- /dev/null +++ b/docs/fiddles/features/recent-documents/main.js @@ -0,0 +1,32 @@ +const { app, BrowserWindow } = require('electron/main') +const fs = require('node:fs') +const path = require('node:path') + +function createWindow () { + const win = new BrowserWindow({ + width: 800, + height: 600 + }) + + win.loadFile('index.html') +} + +const fileName = 'recently-used.md' +fs.writeFile(fileName, 'Lorem Ipsum', () => { + app.addRecentDocument(path.join(__dirname, fileName)) +}) + +app.whenReady().then(createWindow) + +app.on('window-all-closed', () => { + app.clearRecentDocuments() + if (process.platform !== 'darwin') { + app.quit() + } +}) + +app.on('activate', () => { + if (BrowserWindow.getAllWindows().length === 0) { + createWindow() + } +}) diff --git a/docs/fiddles/features/represented-file/index.html b/docs/fiddles/features/represented-file/index.html new file mode 100644 index 0000000000000..67583b9d9ddd0 --- /dev/null +++ b/docs/fiddles/features/represented-file/index.html @@ -0,0 +1,17 @@ + + + + + Hello World! + + + + +

Hello World!

+

+ Click on the title with the

Command
or
Control
key pressed. + You should see a popup with the represented file at the top. +

+ + + diff --git a/docs/fiddles/features/represented-file/main.js b/docs/fiddles/features/represented-file/main.js new file mode 100644 index 0000000000000..6898a110f97b8 --- /dev/null +++ b/docs/fiddles/features/represented-file/main.js @@ -0,0 +1,30 @@ +const { app, BrowserWindow } = require('electron/main') +const os = require('node:os') + +function createWindow () { + const win = new BrowserWindow({ + width: 800, + height: 600 + }) + + win.setRepresentedFilename(os.homedir()) + win.setDocumentEdited(true) + + win.loadFile('index.html') +} + +app.whenReady().then(() => { + createWindow() + + app.on('activate', () => { + if (BrowserWindow.getAllWindows().length === 0) { + createWindow() + } + }) +}) + +app.on('window-all-closed', () => { + if (process.platform !== 'darwin') { + app.quit() + } +}) diff --git a/docs/fiddles/features/web-bluetooth/index.html b/docs/fiddles/features/web-bluetooth/index.html new file mode 100644 index 0000000000000..f31c883b0d5df --- /dev/null +++ b/docs/fiddles/features/web-bluetooth/index.html @@ -0,0 +1,18 @@ + + + + + + Web Bluetooth API + + +

Web Bluetooth API

+ + + + +

Currently selected bluetooth device:

+ + + + diff --git a/docs/fiddles/features/web-bluetooth/main.js b/docs/fiddles/features/web-bluetooth/main.js new file mode 100644 index 0000000000000..103c9891ba9e5 --- /dev/null +++ b/docs/fiddles/features/web-bluetooth/main.js @@ -0,0 +1,58 @@ +const { app, BrowserWindow, ipcMain } = require('electron/main') +const path = require('node:path') + +let bluetoothPinCallback +let selectBluetoothCallback + +function createWindow () { + const mainWindow = new BrowserWindow({ + width: 800, + height: 600, + webPreferences: { + preload: path.join(__dirname, 'preload.js') + } + }) + + mainWindow.webContents.on('select-bluetooth-device', (event, deviceList, callback) => { + event.preventDefault() + selectBluetoothCallback = callback + const result = deviceList.find((device) => { + return device.deviceName === 'test' + }) + if (result) { + callback(result.deviceId) + } else { + // The device wasn't found so we need to either wait longer (eg until the + // device is turned on) or until the user cancels the request + } + }) + + ipcMain.on('cancel-bluetooth-request', (event) => { + selectBluetoothCallback('') + }) + + // Listen for a message from the renderer to get the response for the Bluetooth pairing. + ipcMain.on('bluetooth-pairing-response', (event, response) => { + bluetoothPinCallback(response) + }) + + mainWindow.webContents.session.setBluetoothPairingHandler((details, callback) => { + bluetoothPinCallback = callback + // Send a message to the renderer to prompt the user to confirm the pairing. + mainWindow.webContents.send('bluetooth-pairing-request', details) + }) + + mainWindow.loadFile('index.html') +} + +app.whenReady().then(() => { + createWindow() + + app.on('activate', function () { + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) +}) + +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit() +}) diff --git a/docs/fiddles/features/web-bluetooth/preload.js b/docs/fiddles/features/web-bluetooth/preload.js new file mode 100644 index 0000000000000..1b1c6367256ef --- /dev/null +++ b/docs/fiddles/features/web-bluetooth/preload.js @@ -0,0 +1,7 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electronAPI', { + cancelBluetoothRequest: () => ipcRenderer.send('cancel-bluetooth-request'), + bluetoothPairingRequest: (callback) => ipcRenderer.on('bluetooth-pairing-request', () => callback()), + bluetoothPairingResponse: (response) => ipcRenderer.send('bluetooth-pairing-response', response) +}) diff --git a/docs/fiddles/features/web-bluetooth/renderer.js b/docs/fiddles/features/web-bluetooth/renderer.js new file mode 100644 index 0000000000000..ca14ef9723872 --- /dev/null +++ b/docs/fiddles/features/web-bluetooth/renderer.js @@ -0,0 +1,40 @@ +async function testIt () { + const device = await navigator.bluetooth.requestDevice({ + acceptAllDevices: true + }) + document.getElementById('device-name').innerHTML = device.name || `ID: ${device.id}` +} + +document.getElementById('clickme').addEventListener('click', testIt) + +function cancelRequest () { + window.electronAPI.cancelBluetoothRequest() +} + +document.getElementById('cancel').addEventListener('click', cancelRequest) + +window.electronAPI.bluetoothPairingRequest((event, details) => { + const response = {} + + switch (details.pairingKind) { + case 'confirm': { + response.confirmed = window.confirm(`Do you want to connect to device ${details.deviceId}?`) + break + } + case 'confirmPin': { + response.confirmed = window.confirm(`Does the pin ${details.pin} match the pin displayed on device ${details.deviceId}?`) + break + } + case 'providePin': { + const pin = window.prompt(`Please provide a pin for ${details.deviceId}.`) + if (pin) { + response.pin = pin + response.confirmed = true + } else { + response.confirmed = false + } + } + } + + window.electronAPI.bluetoothPairingResponse(response) +}) diff --git a/docs/fiddles/features/web-hid/index.html b/docs/fiddles/features/web-hid/index.html new file mode 100644 index 0000000000000..8b4243e325751 --- /dev/null +++ b/docs/fiddles/features/web-hid/index.html @@ -0,0 +1,21 @@ + + + + + + WebHID API + + +

WebHID API

+ + + +

HID devices automatically granted access via setDevicePermissionHandler

+
+ +

HID devices automatically granted access via select-hid-device

+
+ + + + diff --git a/docs/fiddles/features/web-hid/main.js b/docs/fiddles/features/web-hid/main.js new file mode 100644 index 0000000000000..315c39da37d0c --- /dev/null +++ b/docs/fiddles/features/web-hid/main.js @@ -0,0 +1,53 @@ +const { app, BrowserWindow } = require('electron/main') + +function createWindow () { + const mainWindow = new BrowserWindow({ + width: 800, + height: 600 + }) + + mainWindow.webContents.session.on('select-hid-device', (event, details, callback) => { + // Add events to handle devices being added or removed before the callback on + // `select-hid-device` is called. + mainWindow.webContents.session.on('hid-device-added', (event, device) => { + console.log('hid-device-added FIRED WITH', device) + // Optionally update details.deviceList + }) + + mainWindow.webContents.session.on('hid-device-removed', (event, device) => { + console.log('hid-device-removed FIRED WITH', device) + // Optionally update details.deviceList + }) + + event.preventDefault() + if (details.deviceList && details.deviceList.length > 0) { + callback(details.deviceList[0].deviceId) + } + }) + + mainWindow.webContents.session.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => { + if (permission === 'hid' && details.securityOrigin === 'file:///') { + return true + } + }) + + mainWindow.webContents.session.setDevicePermissionHandler((details) => { + if (details.deviceType === 'hid' && details.origin === 'file://') { + return true + } + }) + + mainWindow.loadFile('index.html') +} + +app.whenReady().then(() => { + createWindow() + + app.on('activate', function () { + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) +}) + +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit() +}) diff --git a/docs/fiddles/features/web-hid/renderer.js b/docs/fiddles/features/web-hid/renderer.js new file mode 100644 index 0000000000000..133beb520cddc --- /dev/null +++ b/docs/fiddles/features/web-hid/renderer.js @@ -0,0 +1,10 @@ +function formatDevices (devices) { + return devices.map(device => device.productName).join('
') +} + +async function testIt () { + document.getElementById('granted-devices').innerHTML = formatDevices(await navigator.hid.getDevices()) + document.getElementById('granted-devices2').innerHTML = formatDevices(await navigator.hid.requestDevice({ filters: [] })) +} + +document.getElementById('clickme').addEventListener('click', testIt) diff --git a/docs/fiddles/features/web-serial/index.html b/docs/fiddles/features/web-serial/index.html new file mode 100644 index 0000000000000..013718c2931fd --- /dev/null +++ b/docs/fiddles/features/web-serial/index.html @@ -0,0 +1,16 @@ + + + + + + Web Serial API + +

Web Serial API

+ + + +

Matching Arduino Uno device:

+ + + + \ No newline at end of file diff --git a/docs/fiddles/features/web-serial/main.js b/docs/fiddles/features/web-serial/main.js new file mode 100644 index 0000000000000..1839f4f425446 --- /dev/null +++ b/docs/fiddles/features/web-serial/main.js @@ -0,0 +1,62 @@ +const { app, BrowserWindow } = require('electron/main') + +function createWindow () { + const mainWindow = new BrowserWindow({ + width: 800, + height: 600 + }) + + mainWindow.webContents.session.on('select-serial-port', (event, portList, webContents, callback) => { + // Add listeners to handle ports being added or removed before the callback for `select-serial-port` + // is called. + mainWindow.webContents.session.on('serial-port-added', (event, port) => { + console.log('serial-port-added FIRED WITH', port) + // Optionally update portList to add the new port + }) + + mainWindow.webContents.session.on('serial-port-removed', (event, port) => { + console.log('serial-port-removed FIRED WITH', port) + // Optionally update portList to remove the port + }) + + event.preventDefault() + if (portList && portList.length > 0) { + callback(portList[0].portId) + } else { + // eslint-disable-next-line n/no-callback-literal + callback('') // Could not find any matching devices + } + }) + + mainWindow.webContents.session.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => { + if (permission === 'serial' && details.securityOrigin === 'file:///') { + return true + } + + return false + }) + + mainWindow.webContents.session.setDevicePermissionHandler((details) => { + if (details.deviceType === 'serial' && details.origin === 'file://') { + return true + } + + return false + }) + + mainWindow.loadFile('index.html') + + mainWindow.webContents.openDevTools() +} + +app.whenReady().then(() => { + createWindow() + + app.on('activate', function () { + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) +}) + +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit() +}) diff --git a/docs/fiddles/features/web-serial/renderer.js b/docs/fiddles/features/web-serial/renderer.js new file mode 100644 index 0000000000000..2c5eb369804c8 --- /dev/null +++ b/docs/fiddles/features/web-serial/renderer.js @@ -0,0 +1,19 @@ +async function testIt () { + const filters = [ + { usbVendorId: 0x2341, usbProductId: 0x0043 }, + { usbVendorId: 0x2341, usbProductId: 0x0001 } + ] + try { + const port = await navigator.serial.requestPort({ filters }) + const portInfo = port.getInfo() + document.getElementById('device-name').innerHTML = `vendorId: ${portInfo.usbVendorId} | productId: ${portInfo.usbProductId} ` + } catch (ex) { + if (ex.name === 'NotFoundError') { + document.getElementById('device-name').innerHTML = 'Device NOT found' + } else { + document.getElementById('device-name').innerHTML = ex + } + } +} + +document.getElementById('clickme').addEventListener('click', testIt) diff --git a/docs/fiddles/features/web-usb/index.html b/docs/fiddles/features/web-usb/index.html new file mode 100644 index 0000000000000..59c0cb9264dc6 --- /dev/null +++ b/docs/fiddles/features/web-usb/index.html @@ -0,0 +1,21 @@ + + + + + + WebUSB API + + +

WebUSB API

+ + + +

USB devices automatically granted access via setDevicePermissionHandler

+
+ +

USB devices automatically granted access via select-usb-device

+
+ + + + diff --git a/docs/fiddles/features/web-usb/main.js b/docs/fiddles/features/web-usb/main.js new file mode 100644 index 0000000000000..a60de9182ada9 --- /dev/null +++ b/docs/fiddles/features/web-usb/main.js @@ -0,0 +1,74 @@ +const { app, BrowserWindow } = require('electron/main') + +function createWindow () { + const mainWindow = new BrowserWindow({ + width: 800, + height: 600 + }) + + let grantedDeviceThroughPermHandler + + mainWindow.webContents.session.on('select-usb-device', (event, details, callback) => { + // Add events to handle devices being added or removed before the callback on + // `select-usb-device` is called. + mainWindow.webContents.session.on('usb-device-added', (event, device) => { + console.log('usb-device-added FIRED WITH', device) + // Optionally update details.deviceList + }) + + mainWindow.webContents.session.on('usb-device-removed', (event, device) => { + console.log('usb-device-removed FIRED WITH', device) + // Optionally update details.deviceList + }) + + event.preventDefault() + if (details.deviceList && details.deviceList.length > 0) { + const deviceToReturn = details.deviceList.find((device) => { + return !grantedDeviceThroughPermHandler || (device.deviceId !== grantedDeviceThroughPermHandler.deviceId) + }) + if (deviceToReturn) { + callback(deviceToReturn.deviceId) + } else { + callback() + } + } + }) + + mainWindow.webContents.session.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => { + if (permission === 'usb' && details.securityOrigin === 'file:///') { + return true + } + }) + + mainWindow.webContents.session.setDevicePermissionHandler((details) => { + if (details.deviceType === 'usb' && details.origin === 'file://') { + if (!grantedDeviceThroughPermHandler) { + grantedDeviceThroughPermHandler = details.device + return true + } else { + return false + } + } + }) + + mainWindow.webContents.session.setUSBProtectedClassesHandler((details) => { + return details.protectedClasses.filter((usbClass) => { + // Exclude classes except for audio classes + return usbClass.indexOf('audio') === -1 + }) + }) + + mainWindow.loadFile('index.html') +} + +app.whenReady().then(() => { + createWindow() + + app.on('activate', function () { + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) +}) + +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit() +}) diff --git a/docs/fiddles/features/web-usb/renderer.js b/docs/fiddles/features/web-usb/renderer.js new file mode 100644 index 0000000000000..1c217d957d213 --- /dev/null +++ b/docs/fiddles/features/web-usb/renderer.js @@ -0,0 +1,32 @@ +function getDeviceDetails (device) { + return device.productName || `Unknown device ${device.deviceId}` +} + +async function testIt () { + const noDevicesFoundMsg = 'No devices found' + const grantedDevices = await navigator.usb.getDevices() + let grantedDeviceList = '' + if (grantedDevices.length > 0) { + for (const device of grantedDevices) { + grantedDeviceList += `
${getDeviceDetails(device)}` + } + } else { + grantedDeviceList = noDevicesFoundMsg + } + document.getElementById('granted-devices').innerHTML = grantedDeviceList + + grantedDeviceList = '' + try { + const grantedDevice = await navigator.usb.requestDevice({ + filters: [] + }) + grantedDeviceList += `
${getDeviceDetails(grantedDevice)}` + } catch (ex) { + if (ex.name === 'NotFoundError') { + grantedDeviceList = noDevicesFoundMsg + } + } + document.getElementById('granted-devices2').innerHTML = grantedDeviceList +} + +document.getElementById('clickme').addEventListener('click', testIt) diff --git a/docs/fiddles/features/window-customization/custom-title-bar/custom-drag-region/index.html b/docs/fiddles/features/window-customization/custom-title-bar/custom-drag-region/index.html new file mode 100644 index 0000000000000..389fd9e760622 --- /dev/null +++ b/docs/fiddles/features/window-customization/custom-title-bar/custom-drag-region/index.html @@ -0,0 +1,14 @@ + + + + + + + + Custom Titlebar App + + + +
Cool titlebar
+ + \ No newline at end of file diff --git a/docs/fiddles/features/window-customization/custom-title-bar/custom-drag-region/main.js b/docs/fiddles/features/window-customization/custom-title-bar/custom-drag-region/main.js new file mode 100644 index 0000000000000..e389551db7fd7 --- /dev/null +++ b/docs/fiddles/features/window-customization/custom-title-bar/custom-drag-region/main.js @@ -0,0 +1,16 @@ +const { app, BrowserWindow } = require('electron') + +function createWindow () { + const win = new BrowserWindow({ + // remove the default titlebar + titleBarStyle: 'hidden', + // expose window controls in Windows/Linux + ...(process.platform !== 'darwin' ? { titleBarOverlay: true } : {}) + }) + + win.loadFile('index.html') +} + +app.whenReady().then(() => { + createWindow() +}) diff --git a/docs/fiddles/features/window-customization/custom-title-bar/custom-drag-region/styles.css b/docs/fiddles/features/window-customization/custom-title-bar/custom-drag-region/styles.css new file mode 100644 index 0000000000000..b5a046efdba67 --- /dev/null +++ b/docs/fiddles/features/window-customization/custom-title-bar/custom-drag-region/styles.css @@ -0,0 +1,12 @@ +body { + margin: 0; +} +.titlebar { + height: 30px; + background: blue; + color: white; + display: flex; + justify-content: center; + align-items: center; + app-region: drag; +} \ No newline at end of file diff --git a/docs/fiddles/features/window-customization/custom-title-bar/custom-title-bar/index.html b/docs/fiddles/features/window-customization/custom-title-bar/custom-title-bar/index.html new file mode 100644 index 0000000000000..389fd9e760622 --- /dev/null +++ b/docs/fiddles/features/window-customization/custom-title-bar/custom-title-bar/index.html @@ -0,0 +1,14 @@ + + + + + + + + Custom Titlebar App + + + +
Cool titlebar
+ + \ No newline at end of file diff --git a/docs/fiddles/features/window-customization/custom-title-bar/custom-title-bar/main.js b/docs/fiddles/features/window-customization/custom-title-bar/custom-title-bar/main.js new file mode 100644 index 0000000000000..e389551db7fd7 --- /dev/null +++ b/docs/fiddles/features/window-customization/custom-title-bar/custom-title-bar/main.js @@ -0,0 +1,16 @@ +const { app, BrowserWindow } = require('electron') + +function createWindow () { + const win = new BrowserWindow({ + // remove the default titlebar + titleBarStyle: 'hidden', + // expose window controls in Windows/Linux + ...(process.platform !== 'darwin' ? { titleBarOverlay: true } : {}) + }) + + win.loadFile('index.html') +} + +app.whenReady().then(() => { + createWindow() +}) diff --git a/docs/fiddles/features/window-customization/custom-title-bar/custom-title-bar/styles.css b/docs/fiddles/features/window-customization/custom-title-bar/custom-title-bar/styles.css new file mode 100644 index 0000000000000..1f61248a977db --- /dev/null +++ b/docs/fiddles/features/window-customization/custom-title-bar/custom-title-bar/styles.css @@ -0,0 +1,12 @@ +body { + margin: 0; +} + +.titlebar { + height: 30px; + background: blue; + color: white; + display: flex; + justify-content: center; + align-items: center; +} \ No newline at end of file diff --git a/docs/fiddles/features/window-customization/custom-title-bar/native-window-controls/main.js b/docs/fiddles/features/window-customization/custom-title-bar/native-window-controls/main.js new file mode 100644 index 0000000000000..9fb18cb4816a1 --- /dev/null +++ b/docs/fiddles/features/window-customization/custom-title-bar/native-window-controls/main.js @@ -0,0 +1,15 @@ +const { app, BrowserWindow } = require('electron') + +function createWindow () { + const win = new BrowserWindow({ + // remove the default titlebar + titleBarStyle: 'hidden', + // expose window controls in Windows/Linux + ...(process.platform !== 'darwin' ? { titleBarOverlay: true } : {}) + }) + win.loadURL('https://example.com') +} + +app.whenReady().then(() => { + createWindow() +}) diff --git a/docs/fiddles/features/window-customization/custom-title-bar/remove-title-bar/main.js b/docs/fiddles/features/window-customization/custom-title-bar/remove-title-bar/main.js new file mode 100644 index 0000000000000..f85ee63f59319 --- /dev/null +++ b/docs/fiddles/features/window-customization/custom-title-bar/remove-title-bar/main.js @@ -0,0 +1,13 @@ +const { app, BrowserWindow } = require('electron') + +function createWindow () { + const win = new BrowserWindow({ + // remove the default titlebar + titleBarStyle: 'hidden' + }) + win.loadURL('https://example.com') +} + +app.whenReady().then(() => { + createWindow() +}) diff --git a/docs/fiddles/features/window-customization/custom-title-bar/starter-code/main.js b/docs/fiddles/features/window-customization/custom-title-bar/starter-code/main.js new file mode 100644 index 0000000000000..314899176a6f8 --- /dev/null +++ b/docs/fiddles/features/window-customization/custom-title-bar/starter-code/main.js @@ -0,0 +1,10 @@ +const { app, BrowserWindow } = require('electron') + +function createWindow () { + const win = new BrowserWindow({}) + win.loadURL('https://example.com') +} + +app.whenReady().then(() => { + createWindow() +}) diff --git a/docs/fiddles/features/window-customization/custom-window-styles/frameless-windows/main.js b/docs/fiddles/features/window-customization/custom-window-styles/frameless-windows/main.js new file mode 100644 index 0000000000000..86e486b1ee3d7 --- /dev/null +++ b/docs/fiddles/features/window-customization/custom-window-styles/frameless-windows/main.js @@ -0,0 +1,14 @@ +const { app, BrowserWindow } = require('electron') + +function createWindow () { + const win = new BrowserWindow({ + width: 300, + height: 200, + frame: false + }) + win.loadURL('https://example.com') +} + +app.whenReady().then(() => { + createWindow() +}) diff --git a/docs/fiddles/features/window-customization/custom-window-styles/transparent-windows/index.html b/docs/fiddles/features/window-customization/custom-window-styles/transparent-windows/index.html new file mode 100644 index 0000000000000..7c3dc93bddeec --- /dev/null +++ b/docs/fiddles/features/window-customization/custom-window-styles/transparent-windows/index.html @@ -0,0 +1,15 @@ + + + + + + + + Transparent Hello World + + +
+
Hello World!
+
+ + \ No newline at end of file diff --git a/docs/fiddles/features/window-customization/custom-window-styles/transparent-windows/main.js b/docs/fiddles/features/window-customization/custom-window-styles/transparent-windows/main.js new file mode 100644 index 0000000000000..42e63cf4d2868 --- /dev/null +++ b/docs/fiddles/features/window-customization/custom-window-styles/transparent-windows/main.js @@ -0,0 +1,16 @@ +const { app, BrowserWindow } = require('electron') + +function createWindow () { + const win = new BrowserWindow({ + width: 100, + height: 100, + resizable: false, + frame: false, + transparent: true + }) + win.loadFile('index.html') +} + +app.whenReady().then(() => { + createWindow() +}) diff --git a/docs/fiddles/features/window-customization/custom-window-styles/transparent-windows/styles.css b/docs/fiddles/features/window-customization/custom-window-styles/transparent-windows/styles.css new file mode 100644 index 0000000000000..361a8d87982d2 --- /dev/null +++ b/docs/fiddles/features/window-customization/custom-window-styles/transparent-windows/styles.css @@ -0,0 +1,16 @@ +body { + margin: 0; + padding: 0; + background-color: rgba(0, 0, 0, 0); /* Transparent background */ +} +.white-circle { + width: 100px; + height: 100px; + background-color: white; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + app-region: drag; + user-select: none; +} \ No newline at end of file diff --git a/docs/fiddles/ipc/pattern-1/index.html b/docs/fiddles/ipc/pattern-1/index.html new file mode 100644 index 0000000000000..28c1e42cd8b17 --- /dev/null +++ b/docs/fiddles/ipc/pattern-1/index.html @@ -0,0 +1,14 @@ + + + + + + + Hello World! + + + Title: + + + + diff --git a/docs/fiddles/ipc/pattern-1/main.js b/docs/fiddles/ipc/pattern-1/main.js new file mode 100644 index 0000000000000..824ab951ad569 --- /dev/null +++ b/docs/fiddles/ipc/pattern-1/main.js @@ -0,0 +1,31 @@ +const { app, BrowserWindow, ipcMain } = require('electron/main') +const path = require('node:path') + +function handleSetTitle (event, title) { + const webContents = event.sender + const win = BrowserWindow.fromWebContents(webContents) + win.setTitle(title) +} + +function createWindow () { + const mainWindow = new BrowserWindow({ + webPreferences: { + preload: path.join(__dirname, 'preload.js') + } + }) + + mainWindow.loadFile('index.html') +} + +app.whenReady().then(() => { + ipcMain.on('set-title', handleSetTitle) + createWindow() + + app.on('activate', function () { + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) +}) + +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit() +}) diff --git a/docs/fiddles/ipc/pattern-1/preload.js b/docs/fiddles/ipc/pattern-1/preload.js new file mode 100644 index 0000000000000..ce23688245237 --- /dev/null +++ b/docs/fiddles/ipc/pattern-1/preload.js @@ -0,0 +1,5 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electronAPI', { + setTitle: (title) => ipcRenderer.send('set-title', title) +}) diff --git a/docs/fiddles/ipc/pattern-1/renderer.js b/docs/fiddles/ipc/pattern-1/renderer.js new file mode 100644 index 0000000000000..67b775fa53945 --- /dev/null +++ b/docs/fiddles/ipc/pattern-1/renderer.js @@ -0,0 +1,6 @@ +const setButton = document.getElementById('btn') +const titleInput = document.getElementById('title') +setButton.addEventListener('click', () => { + const title = titleInput.value + window.electronAPI.setTitle(title) +}) diff --git a/docs/fiddles/ipc/pattern-2/index.html b/docs/fiddles/ipc/pattern-2/index.html new file mode 100644 index 0000000000000..06e928c8ef13d --- /dev/null +++ b/docs/fiddles/ipc/pattern-2/index.html @@ -0,0 +1,14 @@ + + + + + + + Dialog + + + + File path: + + + diff --git a/docs/fiddles/ipc/pattern-2/main.js b/docs/fiddles/ipc/pattern-2/main.js new file mode 100644 index 0000000000000..369ddf655787d --- /dev/null +++ b/docs/fiddles/ipc/pattern-2/main.js @@ -0,0 +1,30 @@ +const { app, BrowserWindow, ipcMain, dialog } = require('electron/main') +const path = require('node:path') + +async function handleFileOpen () { + const { canceled, filePaths } = await dialog.showOpenDialog() + if (!canceled) { + return filePaths[0] + } +} + +function createWindow () { + const mainWindow = new BrowserWindow({ + webPreferences: { + preload: path.join(__dirname, 'preload.js') + } + }) + mainWindow.loadFile('index.html') +} + +app.whenReady().then(() => { + ipcMain.handle('dialog:openFile', handleFileOpen) + createWindow() + app.on('activate', function () { + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) +}) + +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit() +}) diff --git a/docs/fiddles/ipc/pattern-2/preload.js b/docs/fiddles/ipc/pattern-2/preload.js new file mode 100644 index 0000000000000..32f4acd9da499 --- /dev/null +++ b/docs/fiddles/ipc/pattern-2/preload.js @@ -0,0 +1,5 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electronAPI', { + openFile: () => ipcRenderer.invoke('dialog:openFile') +}) diff --git a/docs/fiddles/ipc/pattern-2/renderer.js b/docs/fiddles/ipc/pattern-2/renderer.js new file mode 100644 index 0000000000000..47712eefe7df1 --- /dev/null +++ b/docs/fiddles/ipc/pattern-2/renderer.js @@ -0,0 +1,7 @@ +const btn = document.getElementById('btn') +const filePathElement = document.getElementById('filePath') + +btn.addEventListener('click', async () => { + const filePath = await window.electronAPI.openFile() + filePathElement.innerText = filePath +}) diff --git a/docs/fiddles/ipc/pattern-3/index.html b/docs/fiddles/ipc/pattern-3/index.html new file mode 100644 index 0000000000000..18d2598986271 --- /dev/null +++ b/docs/fiddles/ipc/pattern-3/index.html @@ -0,0 +1,13 @@ + + + + + + + Menu Counter + + + Current value: 0 + + + diff --git a/docs/fiddles/ipc/pattern-3/main.js b/docs/fiddles/ipc/pattern-3/main.js new file mode 100644 index 0000000000000..60e08ba80d443 --- /dev/null +++ b/docs/fiddles/ipc/pattern-3/main.js @@ -0,0 +1,48 @@ +const { app, BrowserWindow, Menu, ipcMain } = require('electron/main') +const path = require('node:path') + +function createWindow () { + const mainWindow = new BrowserWindow({ + webPreferences: { + preload: path.join(__dirname, 'preload.js') + } + }) + + const menu = Menu.buildFromTemplate([ + { + label: app.name, + submenu: [ + { + click: () => mainWindow.webContents.send('update-counter', 1), + label: 'Increment' + }, + { + click: () => mainWindow.webContents.send('update-counter', -1), + label: 'Decrement' + } + ] + } + + ]) + + Menu.setApplicationMenu(menu) + mainWindow.loadFile('index.html') + + // Open the DevTools. + mainWindow.webContents.openDevTools() +} + +app.whenReady().then(() => { + ipcMain.on('counter-value', (_event, value) => { + console.log(value) // will print value to Node console + }) + createWindow() + + app.on('activate', function () { + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) +}) + +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit() +}) diff --git a/docs/fiddles/ipc/pattern-3/preload.js b/docs/fiddles/ipc/pattern-3/preload.js new file mode 100644 index 0000000000000..b8d275650735e --- /dev/null +++ b/docs/fiddles/ipc/pattern-3/preload.js @@ -0,0 +1,6 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electronAPI', { + onUpdateCounter: (callback) => ipcRenderer.on('update-counter', (_event, value) => callback(value)), + counterValue: (value) => ipcRenderer.send('counter-value', value) +}) diff --git a/docs/fiddles/ipc/pattern-3/renderer.js b/docs/fiddles/ipc/pattern-3/renderer.js new file mode 100644 index 0000000000000..c1d97a8483319 --- /dev/null +++ b/docs/fiddles/ipc/pattern-3/renderer.js @@ -0,0 +1,8 @@ +const counter = document.getElementById('counter') + +window.electronAPI.onUpdateCounter((value) => { + const oldValue = Number(counter.innerText) + const newValue = oldValue + value + counter.innerText = newValue.toString() + window.electronAPI.counterValue(newValue) +}) diff --git a/docs/fiddles/ipc/webview-new-window/child.html b/docs/fiddles/ipc/webview-new-window/child.html new file mode 100644 index 0000000000000..90c94376c284b --- /dev/null +++ b/docs/fiddles/ipc/webview-new-window/child.html @@ -0,0 +1,3 @@ + + new window + diff --git a/docs/fiddles/ipc/webview-new-window/index.html b/docs/fiddles/ipc/webview-new-window/index.html new file mode 100644 index 0000000000000..8b461bd15f83a --- /dev/null +++ b/docs/fiddles/ipc/webview-new-window/index.html @@ -0,0 +1,4 @@ + + + + diff --git a/docs/fiddles/ipc/webview-new-window/main.js b/docs/fiddles/ipc/webview-new-window/main.js new file mode 100644 index 0000000000000..8b6aa41883c8a --- /dev/null +++ b/docs/fiddles/ipc/webview-new-window/main.js @@ -0,0 +1,51 @@ +// Modules to control application life and create native browser window +const { app, BrowserWindow } = require('electron/main') +const path = require('node:path') + +function createWindow () { + // Create the browser window. + const mainWindow = new BrowserWindow({ + width: 800, + height: 600, + webPreferences: { + preload: path.join(__dirname, 'preload.js'), + webviewTag: true + } + }) + + mainWindow.webContents.on('did-attach-webview', (event, wc) => { + wc.setWindowOpenHandler((details) => { + mainWindow.webContents.send('webview-new-window', wc.id, details) + return { action: 'deny' } + }) + }) + + // and load the index.html of the app. + mainWindow.loadFile('index.html') + + // Open the DevTools. + // mainWindow.webContents.openDevTools() +} + +// This method will be called when Electron has finished +// initialization and is ready to create browser windows. +// Some APIs can only be used after this event occurs. +app.whenReady().then(() => { + createWindow() + + app.on('activate', function () { + // On macOS it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) +}) + +// Quit when all windows are closed, except on macOS. There, it's common +// for applications and their menu bar to stay active until the user quits +// explicitly with Cmd + Q. +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit() +}) + +// In this file you can include the rest of your app's specific main process +// code. You can also put them in separate files and require them here. diff --git a/docs/fiddles/ipc/webview-new-window/preload.js b/docs/fiddles/ipc/webview-new-window/preload.js new file mode 100644 index 0000000000000..99f3e6bc60f49 --- /dev/null +++ b/docs/fiddles/ipc/webview-new-window/preload.js @@ -0,0 +1,6 @@ +const { ipcRenderer } = require('electron/renderer') +const webview = document.getElementById('webview') +ipcRenderer.on('webview-new-window', (e, webContentsId, details) => { + console.log('webview-new-window', webContentsId, details) + webview.dispatchEvent(new Event('new-window')) +}) diff --git a/docs/fiddles/ipc/webview-new-window/renderer.js b/docs/fiddles/ipc/webview-new-window/renderer.js new file mode 100644 index 0000000000000..e62d0b4d17bc3 --- /dev/null +++ b/docs/fiddles/ipc/webview-new-window/renderer.js @@ -0,0 +1,4 @@ +const webview = document.getElementById('webview') +webview.addEventListener('new-window', () => { + console.log('got new-window event') +}) diff --git a/docs/fiddles/media/screenshot/take-screenshot/index.html b/docs/fiddles/media/screenshot/take-screenshot/index.html index 264899abddeac..ca05880ef4f98 100644 --- a/docs/fiddles/media/screenshot/take-screenshot/index.html +++ b/docs/fiddles/media/screenshot/take-screenshot/index.html @@ -17,9 +17,6 @@

Take a Screenshot

Clicking the demo button will take a screenshot of your current screen and open it in your default viewer.

- + diff --git a/docs/fiddles/media/screenshot/take-screenshot/main.js b/docs/fiddles/media/screenshot/take-screenshot/main.js index be8ed98328b8d..2ce55cd94a37c 100644 --- a/docs/fiddles/media/screenshot/take-screenshot/main.js +++ b/docs/fiddles/media/screenshot/take-screenshot/main.js @@ -1,10 +1,38 @@ -const { BrowserWindow, app, screen, ipcMain } = require('electron') +const { BrowserWindow, app, screen, ipcMain, desktopCapturer, shell } = require('electron/main') +const fs = require('node:fs').promises +const os = require('node:os') +const path = require('node:path') let mainWindow = null -ipcMain.handle('get-screen-size', () => { - return screen.getPrimaryDisplay().workAreaSize -}) +function determineScreenShotSize (devicePixelRatio) { + const screenSize = screen.getPrimaryDisplay().workAreaSize + const maxDimension = Math.max(screenSize.width, screenSize.height) + return { + width: maxDimension * devicePixelRatio, + height: maxDimension * devicePixelRatio + } +} + +async function takeScreenshot (devicePixelRatio) { + const thumbSize = determineScreenShotSize(devicePixelRatio) + const options = { types: ['screen'], thumbnailSize: thumbSize } + + const sources = await desktopCapturer.getSources(options) + for (const source of sources) { + const sourceName = source.name.toLowerCase() + if (sourceName === 'entire screen' || sourceName === 'screen 1') { + const screenshotPath = path.join(os.tmpdir(), 'screenshot.png') + + await fs.writeFile(screenshotPath, source.thumbnail.toPNG()) + shell.openExternal(`file://${screenshotPath}`) + + return `Saved screenshot to: ${screenshotPath}` + } + } +} + +ipcMain.handle('take-screenshot', (event, devicePixelRatio) => takeScreenshot(devicePixelRatio)) function createWindow () { const windowOptions = { @@ -12,7 +40,7 @@ function createWindow () { height: 300, title: 'Take a Screenshot', webPreferences: { - nodeIntegration: true + preload: path.join(__dirname, 'preload.js') } } diff --git a/docs/fiddles/media/screenshot/take-screenshot/preload.js b/docs/fiddles/media/screenshot/take-screenshot/preload.js new file mode 100644 index 0000000000000..9af9f2faacf19 --- /dev/null +++ b/docs/fiddles/media/screenshot/take-screenshot/preload.js @@ -0,0 +1,5 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electronAPI', { + takeScreenshot: () => ipcRenderer.invoke('take-screenshot', window.devicePixelRatio) +}) diff --git a/docs/fiddles/media/screenshot/take-screenshot/renderer.js b/docs/fiddles/media/screenshot/take-screenshot/renderer.js index e7988f5067d18..6b4329e7df419 100644 --- a/docs/fiddles/media/screenshot/take-screenshot/renderer.js +++ b/docs/fiddles/media/screenshot/take-screenshot/renderer.js @@ -1,42 +1,7 @@ -const { desktopCapturer, shell, ipcRenderer } = require('electron') - -const fs = require('fs') -const os = require('os') -const path = require('path') - const screenshot = document.getElementById('screen-shot') const screenshotMsg = document.getElementById('screenshot-path') screenshot.addEventListener('click', async (event) => { screenshotMsg.textContent = 'Gathering screens...' - const thumbSize = await determineScreenShotSize() - const options = { types: ['screen'], thumbnailSize: thumbSize } - - desktopCapturer.getSources(options, (error, sources) => { - if (error) return console.log(error) - - sources.forEach((source) => { - const sourceName = source.name.toLowerCase() - if (sourceName === 'entire screen' || sourceName === 'screen 1') { - const screenshotPath = path.join(os.tmpdir(), 'screenshot.png') - - fs.writeFile(screenshotPath, source.thumbnail.toPNG(), (error) => { - if (error) return console.log(error) - shell.openExternal(`file://${screenshotPath}`) - - const message = `Saved screenshot to: ${screenshotPath}` - screenshotMsg.textContent = message - }) - } - }) - }) + screenshotMsg.textContent = await window.electronAPI.takeScreenshot() }) - -async function determineScreenShotSize () { - const screenSize = await ipcRenderer.invoke('get-screen-size') - const maxDimension = Math.max(screenSize.width, screenSize.height) - return { - width: maxDimension * window.devicePixelRatio, - height: maxDimension * window.devicePixelRatio - } -} diff --git a/docs/fiddles/menus/context-menu/dom/index.html b/docs/fiddles/menus/context-menu/dom/index.html new file mode 100644 index 0000000000000..a715fb9cb614d --- /dev/null +++ b/docs/fiddles/menus/context-menu/dom/index.html @@ -0,0 +1,14 @@ + + + + + + + Context Menu Demo + + +

Context Menu Demo

+ + + + diff --git a/docs/fiddles/menus/context-menu/dom/main.js b/docs/fiddles/menus/context-menu/dom/main.js new file mode 100644 index 0000000000000..6a67caad46213 --- /dev/null +++ b/docs/fiddles/menus/context-menu/dom/main.js @@ -0,0 +1,39 @@ +// Modules to control application life and create native browser window +const { app, BrowserWindow, ipcMain, Menu } = require('electron/main') +const path = require('node:path') + +function createWindow () { + const mainWindow = new BrowserWindow({ + webPreferences: { + preload: path.join(__dirname, 'preload.js') + } + }) + + mainWindow.loadFile('index.html') + const menu = Menu.buildFromTemplate([ + { role: 'copy' }, + { role: 'cut' }, + { role: 'paste' }, + { role: 'selectall' } + ]) + + // highlight-start + ipcMain.on('context-menu', (event) => { + menu.popup({ + window: BrowserWindow.fromWebContents(event.sender) + }) + }) + // highlight-end +} + +app.whenReady().then(() => { + createWindow() + + app.on('activate', function () { + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) +}) + +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit() +}) diff --git a/docs/fiddles/menus/context-menu/dom/preload.js b/docs/fiddles/menus/context-menu/dom/preload.js new file mode 100644 index 0000000000000..fd932ebf3cb0c --- /dev/null +++ b/docs/fiddles/menus/context-menu/dom/preload.js @@ -0,0 +1,11 @@ +const { ipcRenderer } = require('electron/renderer') + +document.addEventListener('DOMContentLoaded', () => { + const textarea = document.getElementById('editable') + // highlight-start + textarea.addEventListener('contextmenu', (event) => { + event.preventDefault() + ipcRenderer.send('context-menu') + }) + // highlight-end +}) diff --git a/docs/fiddles/menus/context-menu/web-contents/index.html b/docs/fiddles/menus/context-menu/web-contents/index.html new file mode 100644 index 0000000000000..8994ed2bbdc81 --- /dev/null +++ b/docs/fiddles/menus/context-menu/web-contents/index.html @@ -0,0 +1,14 @@ + + + + + + + Context Menu Demo + + +

Context Menu Demo

+ + + + diff --git a/docs/fiddles/menus/context-menu/web-contents/main.js b/docs/fiddles/menus/context-menu/web-contents/main.js new file mode 100644 index 0000000000000..cc77315b6c991 --- /dev/null +++ b/docs/fiddles/menus/context-menu/web-contents/main.js @@ -0,0 +1,32 @@ +const { app, BrowserWindow, Menu } = require('electron/main') + +function createWindow () { + const win = new BrowserWindow() + // highlight-start + const menu = Menu.buildFromTemplate([ + { role: 'copy' }, + { role: 'cut' }, + { role: 'paste' }, + { role: 'selectall' } + ]) + win.webContents.on('context-menu', (_event, params) => { + // only show the context menu if the element is editable + if (params.isEditable) { + menu.popup() + } + }) + // highlight-end + win.loadFile('index.html') +} + +app.whenReady().then(() => { + createWindow() + + app.on('activate', function () { + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) +}) + +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit() +}) diff --git a/docs/fiddles/menus/customize-menus/index.html b/docs/fiddles/menus/customize-menus/index.html deleted file mode 100644 index e8b354f2a1865..0000000000000 --- a/docs/fiddles/menus/customize-menus/index.html +++ /dev/null @@ -1,128 +0,0 @@ - - - - - Customize Menus - - - -
-

Customize Menus

- -

- The Menu and MenuItem modules can be used to - create custom native menus. -

- -

- There are two kinds of menus: the application (top) menu and context - (right-click) menu. -

- -

- Open the - full API documentation(opens in new window) - in your browser. -

-
- -
-

Create an application menu

-
-
-

- The Menu and MenuItem modules allow you to - customize your application menu. If you don't set any menu, Electron - will generate a minimal menu for your app by default. -

- -

- If you click the 'View' option in the application menu and then the - 'App Menu Demo', you'll see an information box displayed. -

- -
-

ProTip

- Know operating system menu differences. -

- When designing an app for multiple operating systems it's - important to be mindful of the ways application menu conventions - differ on each operating system. -

-

- For instance, on Windows, accelerators are set with an - &. Naming conventions also vary, like between - "Settings" or "Preferences". Below are resources for learning - operating system specific standards. -

- -
-
-
-
- -
-

Create a context menu

-
-
-
- -
-

- A context, or right-click, menu can be created with the - Menu and MenuItem modules as well. You can - right-click anywhere in this app or click the demo button to see an - example context menu. -

- -

- In this demo we use the ipcRenderer module to show the - context menu when explicitly calling it from the renderer process. -

-

- See the full - context-menu event documentation - for all the available properties. -

-
-
-
- - - - diff --git a/docs/fiddles/menus/customize-menus/main.js b/docs/fiddles/menus/customize-menus/main.js deleted file mode 100644 index db56e3f5fb519..0000000000000 --- a/docs/fiddles/menus/customize-menus/main.js +++ /dev/null @@ -1,360 +0,0 @@ -// Modules to control application life and create native browser window -const { - BrowserWindow, - Menu, - MenuItem, - ipcMain, - app, - shell, - dialog -} = require('electron') - -const menu = new Menu() -menu.append(new MenuItem({ label: 'Hello' })) -menu.append(new MenuItem({ type: 'separator' })) -menu.append( - new MenuItem({ label: 'Electron', type: 'checkbox', checked: true }) -) - -const template = [ - { - label: 'Edit', - submenu: [ - { - label: 'Undo', - accelerator: 'CmdOrCtrl+Z', - role: 'undo' - }, - { - label: 'Redo', - accelerator: 'Shift+CmdOrCtrl+Z', - role: 'redo' - }, - { - type: 'separator' - }, - { - label: 'Cut', - accelerator: 'CmdOrCtrl+X', - role: 'cut' - }, - { - label: 'Copy', - accelerator: 'CmdOrCtrl+C', - role: 'copy' - }, - { - label: 'Paste', - accelerator: 'CmdOrCtrl+V', - role: 'paste' - }, - { - label: 'Select All', - accelerator: 'CmdOrCtrl+A', - role: 'selectall' - } - ] - }, - { - label: 'View', - submenu: [ - { - label: 'Reload', - accelerator: 'CmdOrCtrl+R', - click: (item, focusedWindow) => { - if (focusedWindow) { - // on reload, start fresh and close any old - // open secondary windows - if (focusedWindow.id === 1) { - BrowserWindow.getAllWindows().forEach(win => { - if (win.id > 1) win.close() - }) - } - focusedWindow.reload() - } - } - }, - { - label: 'Toggle Full Screen', - accelerator: (() => { - if (process.platform === 'darwin') { - return 'Ctrl+Command+F' - } else { - return 'F11' - } - })(), - click: (item, focusedWindow) => { - if (focusedWindow) { - focusedWindow.setFullScreen(!focusedWindow.isFullScreen()) - } - } - }, - { - label: 'Toggle Developer Tools', - accelerator: (() => { - if (process.platform === 'darwin') { - return 'Alt+Command+I' - } else { - return 'Ctrl+Shift+I' - } - })(), - click: (item, focusedWindow) => { - if (focusedWindow) { - focusedWindow.toggleDevTools() - } - } - }, - { - type: 'separator' - }, - { - label: 'App Menu Demo', - click: function (item, focusedWindow) { - if (focusedWindow) { - const options = { - type: 'info', - title: 'Application Menu Demo', - buttons: ['Ok'], - message: - 'This demo is for the Menu section, showing how to create a clickable menu item in the application menu.' - } - dialog.showMessageBox(focusedWindow, options, function () {}) - } - } - } - ] - }, - { - label: 'Window', - role: 'window', - submenu: [ - { - label: 'Minimize', - accelerator: 'CmdOrCtrl+M', - role: 'minimize' - }, - { - label: 'Close', - accelerator: 'CmdOrCtrl+W', - role: 'close' - }, - { - type: 'separator' - }, - { - label: 'Reopen Window', - accelerator: 'CmdOrCtrl+Shift+T', - enabled: false, - key: 'reopenMenuItem', - click: () => { - app.emit('activate') - } - } - ] - }, - { - label: 'Help', - role: 'help', - submenu: [ - { - label: 'Learn More', - click: () => { - shell.openExternal('https://electronjs.org') - } - } - ] - } -] - -function addUpdateMenuItems (items, position) { - if (process.mas) return - - const version = app.getVersion() - const updateItems = [ - { - label: `Version ${version}`, - enabled: false - }, - { - label: 'Checking for Update', - enabled: false, - key: 'checkingForUpdate' - }, - { - label: 'Check for Update', - visible: false, - key: 'checkForUpdate', - click: () => { - require('electron').autoUpdater.checkForUpdates() - } - }, - { - label: 'Restart and Install Update', - enabled: true, - visible: false, - key: 'restartToUpdate', - click: () => { - require('electron').autoUpdater.quitAndInstall() - } - } - ] - - items.splice.apply(items, [position, 0].concat(updateItems)) -} - -function findReopenMenuItem () { - const menu = Menu.getApplicationMenu() - if (!menu) return - - let reopenMenuItem - menu.items.forEach(item => { - if (item.submenu) { - item.submenu.items.forEach(item => { - if (item.key === 'reopenMenuItem') { - reopenMenuItem = item - } - }) - } - }) - return reopenMenuItem -} - -if (process.platform === 'darwin') { - const name = app.getName() - template.unshift({ - label: name, - submenu: [ - { - label: `About ${name}`, - role: 'about' - }, - { - type: 'separator' - }, - { - label: 'Services', - role: 'services', - submenu: [] - }, - { - type: 'separator' - }, - { - label: `Hide ${name}`, - accelerator: 'Command+H', - role: 'hide' - }, - { - label: 'Hide Others', - accelerator: 'Command+Alt+H', - role: 'hideothers' - }, - { - label: 'Show All', - role: 'unhide' - }, - { - type: 'separator' - }, - { - label: 'Quit', - accelerator: 'Command+Q', - click: () => { - app.quit() - } - } - ] - }) - - // Window menu. - template[3].submenu.push( - { - type: 'separator' - }, - { - label: 'Bring All to Front', - role: 'front' - } - ) - - addUpdateMenuItems(template[0].submenu, 1) -} - -if (process.platform === 'win32') { - const helpMenu = template[template.length - 1].submenu - addUpdateMenuItems(helpMenu, 0) -} -// Keep a global reference of the window object, if you don't, the window will -// be closed automatically when the JavaScript object is garbage collected. -let mainWindow - -function createWindow () { - // Create the browser window. - mainWindow = new BrowserWindow({ - width: 800, - height: 600, - webPreferences: { - nodeIntegration: true - } - }) - - // and load the index.html of the app. - mainWindow.loadFile('index.html') - - // Open the DevTools. - // mainWindow.webContents.openDevTools() - - // Emitted when the window is closed. - mainWindow.on('closed', function () { - // Dereference the window object, usually you would store windows - // in an array if your app supports multi windows, this is the time - // when you should delete the corresponding element. - mainWindow = null - }) -} - -// This method will be called when Electron has finished -// initialization and is ready to create browser windows. -// Some APIs can only be used after this event occurs. -app.whenReady().then(() => { - createWindow() - const menu = Menu.buildFromTemplate(template) - Menu.setApplicationMenu(menu) -}) - -// Quit when all windows are closed. -app.on('window-all-closed', function () { - // On macOS it is common for applications and their menu bar - // to stay active until the user quits explicitly with Cmd + Q - const reopenMenuItem = findReopenMenuItem() - if (reopenMenuItem) reopenMenuItem.enabled = true - - if (process.platform !== 'darwin') { - app.quit() - } -}) - -app.on('activate', function () { - // On macOS it is common to re-create a window in the app when the - // dock icon is clicked and there are no other windows open. - if (mainWindow === null) { - createWindow() - } -}) - -app.on('browser-window-created', (event, win) => { - const reopenMenuItem = findReopenMenuItem() - if (reopenMenuItem) reopenMenuItem.enabled = false - - win.webContents.on('context-menu', (e, params) => { - menu.popup(win, params.x, params.y) - }) -}) - -ipcMain.on('show-context-menu', event => { - const win = BrowserWindow.fromWebContents(event.sender) - menu.popup(win) -}) - -// In this file you can include the rest of your app's specific main process -// code. You can also put them in separate files and require them here. diff --git a/docs/fiddles/menus/customize-menus/renderer.js b/docs/fiddles/menus/customize-menus/renderer.js deleted file mode 100644 index 5527e1f20008d..0000000000000 --- a/docs/fiddles/menus/customize-menus/renderer.js +++ /dev/null @@ -1,8 +0,0 @@ -const { ipcRenderer } = require('electron') - -// Tell main process to show the menu when demo button is clicked -const contextMenuBtn = document.getElementById('context-menu') - -contextMenuBtn.addEventListener('click', () => { - ipcRenderer.send('show-context-menu') -}) diff --git a/docs/fiddles/menus/dock-menu/index.html b/docs/fiddles/menus/dock-menu/index.html new file mode 100644 index 0000000000000..e52e1c2cd66c2 --- /dev/null +++ b/docs/fiddles/menus/dock-menu/index.html @@ -0,0 +1,18 @@ + + + + + + + Dock Menu Demo + + +

Dock Menu Demo

+
    +
  • Create new BrowserWindow instances via the "New Window" option
  • +
  • Close all BrowserWindow instances via the "Close All Windows" option
  • +
  • Read the docs via the "Show Electron Docs" option
  • +
+ + + diff --git a/docs/fiddles/menus/dock-menu/main.js b/docs/fiddles/menus/dock-menu/main.js new file mode 100644 index 0000000000000..b88744f8c6449 --- /dev/null +++ b/docs/fiddles/menus/dock-menu/main.js @@ -0,0 +1,46 @@ +const { app, BrowserWindow, Menu } = require('electron/main') +const { shell } = require('electron/common') + +function createWindow () { + const win = new BrowserWindow() + win.loadFile('index.html') +} + +function closeAllWindows () { + const wins = BrowserWindow.getAllWindows() + for (const win of wins) { + win.close() + } +} + +app.whenReady().then(() => { + createWindow() + + const dockMenu = Menu.buildFromTemplate([ + { + label: 'New Window', + click: () => { createWindow() } + }, + { + label: 'Close All Windows', + click: () => { closeAllWindows() } + }, + { + label: 'Open Electron Docs', + click: () => { + shell.openExternal('https://electronjs.org/docs') + } + } + // add more menu options to the array + ]) + + app.dock.setMenu(dockMenu) + + app.on('activate', function () { + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) +}) + +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit() +}) diff --git a/docs/fiddles/menus/dock-menu/renderer.js b/docs/fiddles/menus/dock-menu/renderer.js new file mode 100644 index 0000000000000..c6c1ab2714682 --- /dev/null +++ b/docs/fiddles/menus/dock-menu/renderer.js @@ -0,0 +1 @@ +document.title = `${document.title} - ${new Date()}` diff --git a/docs/fiddles/menus/shortcuts/index.html b/docs/fiddles/menus/shortcuts/index.html index 6851357980c72..cabca0bf715a8 100644 --- a/docs/fiddles/menus/shortcuts/index.html +++ b/docs/fiddles/menus/shortcuts/index.html @@ -1,73 +1,73 @@ - - - - - - Keyboard Shortcuts - - - -
-

Keyboard Shortcuts

- -

The globalShortcut and Menu modules can be used to define keyboard shortcuts.

- -

- In Electron, keyboard shortcuts are called accelerators. - They can be assigned to actions in your application's Menu, - or they can be assigned globally so they'll be triggered even when - your app doesn't have keyboard focus. -

- -

- Open the full documentation for the - Menu, - Accelerator, - and - globalShortcut - APIs in your browser. -

- -
- -
-
-
-

- To try this demo, press CommandOrControl+Alt+K on your - keyboard. -

- -

- Global shortcuts are detected even when the app doesn't have - keyboard focus, and they must be registered after the app's - `ready` event is emitted. -

- -
-

ProTip

- Avoid overriding system-wide keyboard shortcuts. -

- When registering global shortcuts, it's important to be aware of - existing defaults in the target operating system, so as not to - override any existing behaviors. For an overview of each - operating system's keyboard shortcuts, view these documents: -

- - -
- -
-
-
- - - + + + + + + Keyboard Shortcuts + + + +
+

Keyboard Shortcuts

+ +

The globalShortcut and Menu modules can be used to define keyboard shortcuts.

+ +

+ In Electron, keyboard shortcuts are called accelerators. + They can be assigned to actions in your application's Menu, + or they can be assigned globally so they'll be triggered even when + your app doesn't have keyboard focus. +

+ +

+ Open the full documentation for the + Menu, + Accelerator, + and + globalShortcut + APIs in your browser. +

+ +
+ +
+
+
+

+ To try this demo, press CommandOrControl+Alt+K on your + keyboard. +

+ +

+ Global shortcuts are detected even when the app doesn't have + keyboard focus, and they must be registered after the app's + `ready` event is emitted. +

+ +
+

ProTip

+ Avoid overriding system-wide keyboard shortcuts. +

+ When registering global shortcuts, it's important to be aware of + existing defaults in the target operating system, so as not to + override any existing behaviors. For an overview of each + operating system's keyboard shortcuts, view these documents: +

+ + +
+ +
+
+
+ + + diff --git a/docs/fiddles/menus/shortcuts/main.js b/docs/fiddles/menus/shortcuts/main.js index ee3708bf565a7..9207702d44391 100644 --- a/docs/fiddles/menus/shortcuts/main.js +++ b/docs/fiddles/menus/shortcuts/main.js @@ -1,5 +1,5 @@ // Modules to control application life and create native browser window -const { app, BrowserWindow, globalShortcut, dialog } = require('electron') +const { app, BrowserWindow, globalShortcut, dialog, shell } = require('electron/main') // Keep a global reference of the window object, if you don't, the window will // be closed automatically when the JavaScript object is garbage collected. @@ -9,10 +9,7 @@ function createWindow () { // Create the browser window. mainWindow = new BrowserWindow({ width: 800, - height: 600, - webPreferences: { - nodeIntegration: true - } + height: 600 }) globalShortcut.register('CommandOrControl+Alt+K', () => { @@ -37,6 +34,12 @@ function createWindow () { // when you should delete the corresponding element. mainWindow = null }) + + // Open external links in the default browser + mainWindow.webContents.on('will-navigate', (event, url) => { + event.preventDefault() + shell.openExternal(url) + }) } // This method will be called when Electron has finished diff --git a/docs/fiddles/menus/tray-menu/index.html b/docs/fiddles/menus/tray-menu/index.html new file mode 100644 index 0000000000000..9f942fded15ad --- /dev/null +++ b/docs/fiddles/menus/tray-menu/index.html @@ -0,0 +1,19 @@ + + + + + + + Tray Menu Demo + + +

Tray Menu Demo

+

This app will stay running even after all windows are closed.

+
    +
  • Use the "Open App" menu item to focus the main window (or open one if it does not exist).
  • +
  • Change between red and green Tray icons with the "Set Green Icon" checkbox.
  • +
  • Give the Tray icon a title using the "Set Title" checkbox.
  • +
  • Quit the app using the "Quit" menu item.
  • +
+ + diff --git a/docs/fiddles/menus/tray-menu/main.js b/docs/fiddles/menus/tray-menu/main.js new file mode 100644 index 0000000000000..c8627e29dcf63 --- /dev/null +++ b/docs/fiddles/menus/tray-menu/main.js @@ -0,0 +1,60 @@ +const { app, BrowserWindow, Menu, Tray } = require('electron/main') +const { nativeImage } = require('electron/common') + +// save a reference to the Tray object globally to avoid garbage collection +let tray = null + +function createWindow () { + const mainWindow = new BrowserWindow() + mainWindow.loadFile('index.html') +} + +// The Tray object can only be instantiated after the 'ready' event is fired +app.whenReady().then(() => { + createWindow() + + const red = nativeImage.createFromDataURL('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAACTSURBVHgBpZKBCYAgEEV/TeAIjuIIbdQIuUGt0CS1gW1iZ2jIVaTnhw+Cvs8/OYDJA4Y8kR3ZR2/kmazxJbpUEfQ/Dm/UG7wVwHkjlQdMFfDdJMFaACebnjJGyDWgcnZu1/lrCrl6NCoEHJBrDwEr5NrT6ko/UV8xdLAC2N49mlc5CylpYh8wCwqrvbBGLoKGvz8Bfq0QPWEUo/EAAAAASUVORK5CYII=') + const green = nativeImage.createFromDataURL('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAACOSURBVHgBpZLRDYAgEEOrEzgCozCCGzkCbKArOIlugJvgoRAUNcLRpvGH19TkgFQWkqIohhK8UEaKwKcsOg/+WR1vX+AlA74u6q4FqgCOSzwsGHCwbKliAF89Cv89tWmOT4VaVMoVbOBrdQUz+FrD6XItzh4LzYB1HFJ9yrEkZ4l+wvcid9pTssh4UKbPd+4vED2Nd54iAAAAAElFTkSuQmCC') + + tray = new Tray(red) + tray.setToolTip('Tray Icon Demo') + + const contextMenu = Menu.buildFromTemplate([ + { + label: 'Open App', + click: () => { + const wins = BrowserWindow.getAllWindows() + if (wins.length === 0) { + createWindow() + } else { + wins[0].focus() + } + } + }, + { + label: 'Set Green Icon', + type: 'checkbox', + click: ({ checked }) => { + checked ? tray.setImage(green) : tray.setImage(red) + } + }, + { + label: 'Set Title', + type: 'checkbox', + click: ({ checked }) => { + checked ? tray.setTitle('Title') : tray.setTitle('') + } + }, + { role: 'quit' } + ]) + + tray.setContextMenu(contextMenu) +}) + +app.on('window-all-closed', function () { + // This will prevent the app from closing when windows close +}) + +app.on('activate', function () { + if (BrowserWindow.getAllWindows().length === 0) createWindow() +}) diff --git a/docs/fiddles/native-ui/dialogs/.keep b/docs/fiddles/native-ui/dialogs/.keep deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/docs/fiddles/native-ui/dialogs/error-dialog/index.html b/docs/fiddles/native-ui/dialogs/error-dialog/index.html index 2d516c28b683e..8f694ed265b9e 100644 --- a/docs/fiddles/native-ui/dialogs/error-dialog/index.html +++ b/docs/fiddles/native-ui/dialogs/error-dialog/index.html @@ -1,81 +1,78 @@ - - - - - Error Dialog - - - -
-

Use system dialogs

- -

- The dialog module in Electron allows you to use native - system dialogs for opening files or directories, saving a file or - displaying informational messages. -

- -

- This is a main process module because this process is more efficient - with native utilities and it allows the call to happen without - interrupting the visible elements in your page's renderer process. -

- -

- Open the - - full API documentation (opens in new window) - - in your browser. -

-
- -
-
-

Error Dialog

-
-
- -
-

- In this demo, the ipc module is used to send a message - from the renderer process instructing the main process to launch the - error dialog. -

- -

- You can use an error dialog before the app's - ready event, which is useful for showing errors upon - startup. -

-
Renderer Process
-
-          
-const {ipcRenderer} = require('electron')
-
-const errorBtn = document.getElementById('error-dialog')
-
-errorBtn.addEventListener('click', (event) => {
-  ipcRenderer.send('open-error-dialog')
-})
-          
-
Main Process
-
-          
-const {ipcMain, dialog} = require('electron')
-
-ipcMain.on('open-error-dialog', (event) => {
-  dialog.showErrorBox('An Error Message', 'Demonstrating an error message.')
-})
-          
-        
-
-
-
- - - - + + + + + Error Dialog + + + +
+

Use system dialogs

+ +

+ The dialog module in Electron allows you to use native + system dialogs for opening files or directories, saving a file or + displaying informational messages. +

+ +

+ This is a main process module because this process is more efficient + with native utilities and it allows the call to happen without + interrupting the visible elements in your page's renderer process. +

+ +

+ Open the + + full API documentation (opens in new window) + + in your browser. +

+
+ +
+
+

Error Dialog

+
+
+ +
+

+ In this demo, the ipc module is used to send a message + from the renderer process instructing the main process to launch the + error dialog. +

+ +

+ You can use an error dialog before the app's + ready event, which is useful for showing errors upon + startup. +

+
Renderer Process
+
+          
+const {ipcRenderer} = require('electron')
+
+const errorBtn = document.getElementById('error-dialog')
+
+errorBtn.addEventListener('click', (event) => {
+  ipcRenderer.send('open-error-dialog')
+})
+          
+
Main Process
+
+          
+const {ipcMain, dialog} = require('electron')
+
+ipcMain.on('open-error-dialog', (event) => {
+  dialog.showErrorBox('An Error Message', 'Demonstrating an error message.')
+})
+          
+        
+
+
+
+ + + + diff --git a/docs/fiddles/native-ui/dialogs/error-dialog/main.js b/docs/fiddles/native-ui/dialogs/error-dialog/main.js index 7567aa411bda2..149cf4e0f58ec 100644 --- a/docs/fiddles/native-ui/dialogs/error-dialog/main.js +++ b/docs/fiddles/native-ui/dialogs/error-dialog/main.js @@ -1,5 +1,6 @@ // Modules to control application life and create native browser window -const { app, BrowserWindow, ipcMain, dialog } = require('electron') +const { app, BrowserWindow, ipcMain, dialog, shell } = require('electron/main') +const path = require('node:path') // Keep a global reference of the window object, if you don't, the window will // be closed automatically when the JavaScript object is garbage collected. @@ -11,7 +12,7 @@ function createWindow () { width: 800, height: 600, webPreferences: { - nodeIntegration: true + preload: path.join(__dirname, 'preload.js') } }) @@ -28,6 +29,12 @@ function createWindow () { // when you should delete the corresponding element. mainWindow = null }) + + // Open external links in the default browser + mainWindow.webContents.on('will-navigate', (event, url) => { + event.preventDefault() + shell.openExternal(url) + }) } // This method will be called when Electron has finished diff --git a/docs/fiddles/native-ui/dialogs/error-dialog/preload.js b/docs/fiddles/native-ui/dialogs/error-dialog/preload.js new file mode 100644 index 0000000000000..e47c74f614bf4 --- /dev/null +++ b/docs/fiddles/native-ui/dialogs/error-dialog/preload.js @@ -0,0 +1,5 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electronAPI', { + openErrorDialog: () => ipcRenderer.send('open-error-dialog') +}) diff --git a/docs/fiddles/native-ui/dialogs/error-dialog/renderer.js b/docs/fiddles/native-ui/dialogs/error-dialog/renderer.js index 4011066587dcb..20ae84f772242 100644 --- a/docs/fiddles/native-ui/dialogs/error-dialog/renderer.js +++ b/docs/fiddles/native-ui/dialogs/error-dialog/renderer.js @@ -1,18 +1,5 @@ -const { ipcRenderer, shell } = require('electron') - -const links = document.querySelectorAll('a[href]') const errorBtn = document.getElementById('error-dialog') -errorBtn.addEventListener('click', event => { - ipcRenderer.send('open-error-dialog') +errorBtn.addEventListener('click', () => { + window.electronAPI.openErrorDialog() }) - -Array.prototype.forEach.call(links, (link) => { - const url = link.getAttribute('href') - if (url.indexOf('http') === 0) { - link.addEventListener('click', (e) => { - e.preventDefault() - shell.openExternal(url) - }) - } -}) \ No newline at end of file diff --git a/docs/fiddles/native-ui/dialogs/information-dialog/index.html b/docs/fiddles/native-ui/dialogs/information-dialog/index.html index 5600b653874ad..8e28f86362843 100644 --- a/docs/fiddles/native-ui/dialogs/information-dialog/index.html +++ b/docs/fiddles/native-ui/dialogs/information-dialog/index.html @@ -1,104 +1,101 @@ - - - - - Information Dialog - - - -
-

Use system dialogs

- -

- The dialog module in Electron allows you to use native - system dialogs for opening files or directories, saving a file or - displaying informational messages. -

- -

- This is a main process module because this process is more efficient - with native utilities and it allows the call to happen without - interrupting the visible elements in your page's renderer process. -

- -

- Open the - - full API documentation (opens in new window) - - in your browser. -

-
- -
-
-

Information Dialog

-
-
- - -
-

- In this demo, the ipc module is used to send a message - from the renderer process instructing the main process to launch the - information dialog. Options may be provided for responses which can - then be relayed back to the renderer process. -

- -

- Note: The title property is not displayed in macOS. -

- -

- An information dialog can contain an icon, your choice of buttons, - title and message. -

-
Renderer Process
-
-            
-const {ipcRenderer} = require('electron')
-
-const informationBtn = document.getElementById('information-dialog')
-
-informationBtn.addEventListener('click', (event) => {
-  ipcRenderer.send('open-information-dialog')
-})
-
-ipcRenderer.on('information-dialog-selection', (event, index) => {
-  let message = 'You selected '
-  if (index === 0) message += 'yes.'
-  else message += 'no.'
-  document.getElementById('info-selection').innerHTML = message
-})
-            
-          
-
Main Process
-
-            
-const {ipcMain, dialog} = require('electron')
-
-ipcMain.on('open-information-dialog', (event) => {
-  const options = {
-    type: 'info',
-    title: 'Information',
-    message: "This is an information dialog. Isn't it nice?",
-    buttons: ['Yes', 'No']
-  }
-  dialog.showMessageBox(options, (index) => {
-    event.sender.send('information-dialog-selection', index)
-  })
-})
-            
-          
-
-
-
- - - - + + + + + Information Dialog + + + +
+

Use system dialogs

+ +

+ The dialog module in Electron allows you to use native + system dialogs for opening files or directories, saving a file or + displaying informational messages. +

+ +

+ This is a main process module because this process is more efficient + with native utilities and it allows the call to happen without + interrupting the visible elements in your page's renderer process. +

+ +

+ Open the + + full API documentation (opens in new window) + + in your browser. +

+
+ +
+
+

Information Dialog

+
+
+ + +
+

+ In this demo, the ipc module is used to send a message + from the renderer process instructing the main process to launch the + information dialog. Options may be provided for responses which can + then be relayed back to the renderer process. +

+ +

+ Note: The title property is not displayed in macOS. +

+ +

+ An information dialog can contain an icon, your choice of buttons, + title and message. +

+
Renderer Process
+
+            
+const {ipcRenderer} = require('electron')
+
+const informationBtn = document.getElementById('information-dialog')
+
+informationBtn.addEventListener('click', (event) => {
+  ipcRenderer.send('open-information-dialog')
+})
+
+ipcRenderer.on('information-dialog-selection', (event, index) => {
+  let message = 'You selected '
+  if (index === 0) message += 'yes.'
+  else message += 'no.'
+  document.getElementById('info-selection').innerHTML = message
+})
+            
+          
+
Main Process
+
+            
+const {ipcMain, dialog} = require('electron')
+
+ipcMain.on('open-information-dialog', (event) => {
+  const options = {
+    type: 'info',
+    title: 'Information',
+    message: "This is an information dialog. Isn't it nice?",
+    buttons: ['Yes', 'No']
+  }
+  dialog.showMessageBox(options, (index) => {
+    event.sender.send('information-dialog-selection', index)
+  })
+})
+            
+          
+
+
+
+ + + + diff --git a/docs/fiddles/native-ui/dialogs/information-dialog/main.js b/docs/fiddles/native-ui/dialogs/information-dialog/main.js index 3e81a5782076f..bbe460464c8cb 100644 --- a/docs/fiddles/native-ui/dialogs/information-dialog/main.js +++ b/docs/fiddles/native-ui/dialogs/information-dialog/main.js @@ -1,5 +1,6 @@ // Modules to control application life and create native browser window -const { app, BrowserWindow, ipcMain, dialog } = require('electron') +const { app, BrowserWindow, ipcMain, dialog, shell } = require('electron/main') +const path = require('node:path') // Keep a global reference of the window object, if you don't, the window will // be closed automatically when the JavaScript object is garbage collected. @@ -11,7 +12,7 @@ function createWindow () { width: 800, height: 600, webPreferences: { - nodeIntegration: true + preload: path.join(__dirname, 'preload.js') } }) @@ -28,6 +29,12 @@ function createWindow () { // when you should delete the corresponding element. mainWindow = null }) + + // Open external links in the default browser + mainWindow.webContents.on('will-navigate', (event, url) => { + event.preventDefault() + shell.openExternal(url) + }) } // This method will be called when Electron has finished @@ -52,19 +59,15 @@ app.on('activate', function () { } }) - -ipcMain.on('open-information-dialog', event => { +ipcMain.handle('open-information-dialog', async () => { const options = { type: 'info', title: 'Information', message: "This is an information dialog. Isn't it nice?", buttons: ['Yes', 'No'] } - dialog.showMessageBox(options, index => { - event.sender.send('information-dialog-selection', index) - }) + return (await dialog.showMessageBox(options)).response }) - // In this file you can include the rest of your app's specific main process // code. You can also put them in separate files and require them here. diff --git a/docs/fiddles/native-ui/dialogs/information-dialog/preload.js b/docs/fiddles/native-ui/dialogs/information-dialog/preload.js new file mode 100644 index 0000000000000..5191aacea2bb2 --- /dev/null +++ b/docs/fiddles/native-ui/dialogs/information-dialog/preload.js @@ -0,0 +1,5 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electronAPI', { + openInformationDialog: () => ipcRenderer.invoke('open-information-dialog') +}) diff --git a/docs/fiddles/native-ui/dialogs/information-dialog/renderer.js b/docs/fiddles/native-ui/dialogs/information-dialog/renderer.js index 69ea9cdb1a2f2..57c8fcc0061b5 100644 --- a/docs/fiddles/native-ui/dialogs/information-dialog/renderer.js +++ b/docs/fiddles/native-ui/dialogs/information-dialog/renderer.js @@ -1,25 +1,7 @@ -const { ipcRenderer, shell } = require('electron') - const informationBtn = document.getElementById('information-dialog') -const links = document.querySelectorAll('a[href]') - -informationBtn.addEventListener('click', event => { - ipcRenderer.send('open-information-dialog') -}) -ipcRenderer.on('information-dialog-selection', (event, index) => { - let message = 'You selected ' - if (index === 0) message += 'yes.' - else message += 'no.' +informationBtn.addEventListener('click', async () => { + const index = await window.electronAPI.openInformationDialog() + const message = `You selected: ${index === 0 ? 'yes' : 'no'}` document.getElementById('info-selection').innerHTML = message }) - -Array.prototype.forEach.call(links, (link) => { - const url = link.getAttribute('href') - if (url.indexOf('http') === 0) { - link.addEventListener('click', (e) => { - e.preventDefault() - shell.openExternal(url) - }) - } -}) \ No newline at end of file diff --git a/docs/fiddles/native-ui/dialogs/open-file-or-directory/index.html b/docs/fiddles/native-ui/dialogs/open-file-or-directory/index.html index df96f2e810812..9443a62ce91df 100644 --- a/docs/fiddles/native-ui/dialogs/open-file-or-directory/index.html +++ b/docs/fiddles/native-ui/dialogs/open-file-or-directory/index.html @@ -1,108 +1,105 @@ - - - - - Open File or Directory - - - -
-

Use system dialogs

- -

- The dialog module in Electron allows you to use native - system dialogs for opening files or directories, saving a file or - displaying informational messages. -

- -

- This is a main process module because this process is more efficient - with native utilities and it allows the call to happen without - interrupting the visible elements in your page's renderer process. -

- -

- Open the - - full API documentation (opens in new window) - - in your browser. -

-
- -
-
-

Open a File or Directory

-
-
- - -
-

- In this demo, the ipc module is used to send a message - from the renderer process instructing the main process to launch the - open file (or directory) dialog. If a file is selected, the main - process can send that information back to the renderer process. -

-
Renderer Process
-
-          
-const {ipcRenderer} = require('electron')
-
-const selectDirBtn = document.getElementById('select-directory')
-
-selectDirBtn.addEventListener('click', (event) => {
-  ipcRenderer.send('open-file-dialog')
-})
-
-ipcRenderer.on('selected-directory', (event, path) => {
-  document.getElementById('selected-file').innerHTML = `You selected: ${path}`
-})
-          
-        
-
Main Process
-
-          
-const {ipcMain, dialog} = require('electron')
-
-ipcMain.on('open-file-dialog', (event) => {
-  dialog.showOpenDialog({
-    properties: ['openFile', 'openDirectory']
-  }, (files) => {
-    if (files) {
-      event.sender.send('selected-directory', files)
-    }
-  })
-})
-          
-        
- -
-

ProTip

- The sheet-style dialog on macOS. -

- On macOS you can choose between a "sheet" dialog or a default - dialog. The sheet version descends from the top of the window. To - use sheet version, pass the window as the first - argument in the dialog method. -

-
const ipc = require('electron').ipcMain
-const dialog = require('electron').dialog
-const BrowserWindow = require('electron').BrowserWindow
-
-
-ipc.on('open-file-dialog-sheet', function (event) {
-  const window = BrowserWindow.fromWebContents(event.sender)
-  const files = dialog.showOpenDialog(window, { properties: [ 'openFile' ]})
-})
-
-
-
-
- - - - + + + + + Open File or Directory + + + +
+

Use system dialogs

+ +

+ The dialog module in Electron allows you to use native + system dialogs for opening files or directories, saving a file or + displaying informational messages. +

+ +

+ This is a main process module because this process is more efficient + with native utilities and it allows the call to happen without + interrupting the visible elements in your page's renderer process. +

+ +

+ Open the + + full API documentation (opens in new window) + + in your browser. +

+
+ +
+
+

Open a File or Directory

+
+
+ + +
+

+ In this demo, the ipc module is used to send a message + from the renderer process instructing the main process to launch the + open file (or directory) dialog. If a file is selected, the main + process can send that information back to the renderer process. +

+
Renderer Process
+
+          
+const {ipcRenderer} = require('electron')
+
+const selectDirBtn = document.getElementById('select-directory')
+
+selectDirBtn.addEventListener('click', (event) => {
+  ipcRenderer.send('open-file-dialog')
+})
+
+ipcRenderer.on('selected-directory', (event, path) => {
+  document.getElementById('selected-file').innerHTML = `You selected: ${path}`
+})
+          
+        
+
Main Process
+
+          
+const {ipcMain, dialog} = require('electron')
+
+ipcMain.on('open-file-dialog', (event) => {
+  dialog.showOpenDialog({
+    properties: ['openFile', 'openDirectory']
+  }, (files) => {
+    if (files) {
+      event.sender.send('selected-directory', files)
+    }
+  })
+})
+          
+        
+ +
+

ProTip

+ The sheet-style dialog on macOS. +

+ On macOS you can choose between a "sheet" dialog or a default + dialog. The sheet version descends from the top of the window. To + use sheet version, pass the window as the first + argument in the dialog method. +

+
const ipc = require('electron').ipcMain
+const dialog = require('electron').dialog
+const BrowserWindow = require('electron').BrowserWindow
+
+
+ipc.on('open-file-dialog-sheet', function (event) {
+  const window = BrowserWindow.fromWebContents(event.sender)
+  const files = dialog.showOpenDialog(window, { properties: [ 'openFile' ]})
+})
+
+
+
+
+ + + + diff --git a/docs/fiddles/native-ui/dialogs/open-file-or-directory/main.js b/docs/fiddles/native-ui/dialogs/open-file-or-directory/main.js index 24b9164dab3a9..5721c69869a55 100644 --- a/docs/fiddles/native-ui/dialogs/open-file-or-directory/main.js +++ b/docs/fiddles/native-ui/dialogs/open-file-or-directory/main.js @@ -1,5 +1,6 @@ // Modules to control application life and create native browser window -const { app, BrowserWindow, ipcMain, dialog } = require('electron') +const { app, BrowserWindow, ipcMain, dialog, shell } = require('electron/main') +const path = require('node:path') // Keep a global reference of the window object, if you don't, the window will // be closed automatically when the JavaScript object is garbage collected. @@ -11,7 +12,7 @@ function createWindow () { width: 800, height: 600, webPreferences: { - nodeIntegration: true + preload: path.join(__dirname, 'preload.js') } }) @@ -28,6 +29,12 @@ function createWindow () { // when you should delete the corresponding element. mainWindow = null }) + + // Open external links in the default browser + mainWindow.webContents.on('will-navigate', (event, url) => { + event.preventDefault() + shell.openExternal(url) + }) } // This method will be called when Electron has finished @@ -52,18 +59,11 @@ app.on('activate', function () { } }) - -ipcMain.on('open-file-dialog', event => { - dialog.showOpenDialog( - { - properties: ['openFile', 'openDirectory'] - }, - files => { - if (files) { - event.sender.send('selected-directory', files) - } - } - ) +ipcMain.handle('open-file-dialog', async () => { + const options = { + properties: ['openFile', 'openDirectory'] + } + return (await dialog.showOpenDialog(options)).filePaths }) // In this file you can include the rest of your app's specific main process diff --git a/docs/fiddles/native-ui/dialogs/open-file-or-directory/preload.js b/docs/fiddles/native-ui/dialogs/open-file-or-directory/preload.js new file mode 100644 index 0000000000000..ace7c2d165710 --- /dev/null +++ b/docs/fiddles/native-ui/dialogs/open-file-or-directory/preload.js @@ -0,0 +1,5 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electronAPI', { + openFileDialog: () => ipcRenderer.invoke('open-file-dialog') +}) diff --git a/docs/fiddles/native-ui/dialogs/open-file-or-directory/renderer.js b/docs/fiddles/native-ui/dialogs/open-file-or-directory/renderer.js index 5389ea50709a0..badfd8776ef63 100644 --- a/docs/fiddles/native-ui/dialogs/open-file-or-directory/renderer.js +++ b/docs/fiddles/native-ui/dialogs/open-file-or-directory/renderer.js @@ -1,22 +1,6 @@ -const { ipcRenderer, shell } = require('electron') - const selectDirBtn = document.getElementById('select-directory') -const links = document.querySelectorAll('a[href]') - -selectDirBtn.addEventListener('click', event => { - ipcRenderer.send('open-file-dialog') -}) -ipcRenderer.on('selected-directory', (event, path) => { +selectDirBtn.addEventListener('click', async () => { + const path = await window.electronAPI.openFileDialog() document.getElementById('selected-file').innerHTML = `You selected: ${path}` }) - -Array.prototype.forEach.call(links, (link) => { - const url = link.getAttribute('href') - if (url.indexOf('http') === 0) { - link.addEventListener('click', (e) => { - e.preventDefault() - shell.openExternal(url) - }) - } -}) diff --git a/docs/fiddles/native-ui/dialogs/save-dialog/index.html b/docs/fiddles/native-ui/dialogs/save-dialog/index.html index b7ceaee7b1202..d8e97edbf8d5a 100644 --- a/docs/fiddles/native-ui/dialogs/save-dialog/index.html +++ b/docs/fiddles/native-ui/dialogs/save-dialog/index.html @@ -1,91 +1,88 @@ - - - - - Save Dialog - - - -
-

Use system dialogs

- -

- The dialog module in Electron allows you to use native - system dialogs for opening files or directories, saving a file or - displaying informational messages. -

- -

- This is a main process module because this process is more efficient - with native utilities and it allows the call to happen without - interrupting the visible elements in your page's renderer process. -

- -

- Open the - - full API documentation (opens in new window) - - in your browser. -

-
- -
-
-

Save Dialog

-
-
- - -
-

- In this demo, the ipc module is used to send a message - from the renderer process instructing the main process to launch the - save dialog. It returns the path selected by the user which can be - relayed back to the renderer process. -

-
Renderer Process
-
-            
-const {ipcRenderer} = require('electron')
-
-const saveBtn = document.getElementById('save-dialog')
-
-saveBtn.addEventListener('click', (event) => {
-  ipcRenderer.send('save-dialog')
-})
-
-ipcRenderer.on('saved-file', (event, path) => {
-  if (!path) path = 'No path'
-  document.getElementById('file-saved').innerHTML = `Path selected: ${path}`
-})
-            
-          
-
Main Process
-
-            
-const {ipcMain, dialog} = require('electron')
-
-ipcMain.on('save-dialog', (event) => {
-  const options = {
-    title: 'Save an Image',
-    filters: [
-      { name: 'Images', extensions: ['jpg', 'png', 'gif'] }
-    ]
-  }
-  dialog.showSaveDialog(options, (filename) => {
-    event.sender.send('saved-file', filename)
-  })
-})
-            
-          
-
-
-
- - - - + + + + + Save Dialog + + + +
+

Use system dialogs

+ +

+ The dialog module in Electron allows you to use native + system dialogs for opening files or directories, saving a file or + displaying informational messages. +

+ +

+ This is a main process module because this process is more efficient + with native utilities and it allows the call to happen without + interrupting the visible elements in your page's renderer process. +

+ +

+ Open the + + full API documentation (opens in new window) + + in your browser. +

+
+ +
+
+

Save Dialog

+
+
+ + +
+

+ In this demo, the ipc module is used to send a message + from the renderer process instructing the main process to launch the + save dialog. It returns the path selected by the user which can be + relayed back to the renderer process. +

+
Renderer Process
+
+            
+const {ipcRenderer} = require('electron')
+
+const saveBtn = document.getElementById('save-dialog')
+
+saveBtn.addEventListener('click', (event) => {
+  ipcRenderer.send('save-dialog')
+})
+
+ipcRenderer.on('saved-file', (event, path) => {
+  if (!path) path = 'No path'
+  document.getElementById('file-saved').innerHTML = `Path selected: ${path}`
+})
+            
+          
+
Main Process
+
+            
+const {ipcMain, dialog} = require('electron')
+
+ipcMain.on('save-dialog', (event) => {
+  const options = {
+    title: 'Save an Image',
+    filters: [
+      { name: 'Images', extensions: ['jpg', 'png', 'gif'] }
+    ]
+  }
+  dialog.showSaveDialog(options, (filename) => {
+    event.sender.send('saved-file', filename)
+  })
+})
+            
+          
+
+
+
+ + + + diff --git a/docs/fiddles/native-ui/dialogs/save-dialog/main.js b/docs/fiddles/native-ui/dialogs/save-dialog/main.js index b6e6ec1331be9..44c8fa1a1e29b 100644 --- a/docs/fiddles/native-ui/dialogs/save-dialog/main.js +++ b/docs/fiddles/native-ui/dialogs/save-dialog/main.js @@ -1,5 +1,6 @@ // Modules to control application life and create native browser window -const { app, BrowserWindow, ipcMain, dialog } = require('electron') +const { app, BrowserWindow, ipcMain, dialog, shell } = require('electron/main') +const path = require('node:path') // Keep a global reference of the window object, if you don't, the window will // be closed automatically when the JavaScript object is garbage collected. @@ -11,7 +12,7 @@ function createWindow () { width: 800, height: 600, webPreferences: { - nodeIntegration: true + preload: path.join(__dirname, 'preload.js') } }) @@ -28,6 +29,12 @@ function createWindow () { // when you should delete the corresponding element. mainWindow = null }) + + // Open external links in the default browser + mainWindow.webContents.on('will-navigate', (event, url) => { + event.preventDefault() + shell.openExternal(url) + }) } // This method will be called when Electron has finished @@ -52,14 +59,12 @@ app.on('activate', function () { } }) -ipcMain.on('save-dialog', event => { +ipcMain.handle('save-dialog', async () => { const options = { title: 'Save an Image', filters: [{ name: 'Images', extensions: ['jpg', 'png', 'gif'] }] } - dialog.showSaveDialog(options, filename => { - event.sender.send('saved-file', filename) - }) + return (await dialog.showSaveDialog(options)).filePath }) // In this file you can include the rest of your app's specific main process diff --git a/docs/fiddles/native-ui/dialogs/save-dialog/preload.js b/docs/fiddles/native-ui/dialogs/save-dialog/preload.js new file mode 100644 index 0000000000000..6d63c2e4552ef --- /dev/null +++ b/docs/fiddles/native-ui/dialogs/save-dialog/preload.js @@ -0,0 +1,5 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electronAPI', { + saveDialog: () => ipcRenderer.invoke('save-dialog') +}) diff --git a/docs/fiddles/native-ui/dialogs/save-dialog/renderer.js b/docs/fiddles/native-ui/dialogs/save-dialog/renderer.js index 9f6da5546946d..c36088c775564 100644 --- a/docs/fiddles/native-ui/dialogs/save-dialog/renderer.js +++ b/docs/fiddles/native-ui/dialogs/save-dialog/renderer.js @@ -1,23 +1,6 @@ -const { ipcRenderer, shell } = require('electron') - const saveBtn = document.getElementById('save-dialog') -const links = document.querySelectorAll('a[href]') - -saveBtn.addEventListener('click', event => { - ipcRenderer.send('save-dialog') -}) -ipcRenderer.on('saved-file', (event, path) => { - if (!path) path = 'No path' +saveBtn.addEventListener('click', async () => { + const path = await window.electronAPI.saveDialog() document.getElementById('file-saved').innerHTML = `Path selected: ${path}` }) - -Array.prototype.forEach.call(links, (link) => { - const url = link.getAttribute('href') - if (url.indexOf('http') === 0) { - link.addEventListener('click', (e) => { - e.preventDefault() - shell.openExternal(url) - }) - } -}) \ No newline at end of file diff --git a/docs/fiddles/native-ui/drag-and-drop/.keep b/docs/fiddles/native-ui/drag-and-drop/.keep deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/docs/fiddles/native-ui/drag-and-drop/index.html b/docs/fiddles/native-ui/drag-and-drop/index.html index 40f2733cd266d..0ed547401f680 100644 --- a/docs/fiddles/native-ui/drag-and-drop/index.html +++ b/docs/fiddles/native-ui/drag-and-drop/index.html @@ -1,76 +1,73 @@ - - - - - Drag and drop files - - - -
-

Drag and drop files

-
Supports: Win, macOS, Linux | Process: Both
-

- Electron supports dragging files and content out from web content into - the operating system's world. -

- -

- Open the - - full API documentation (opens in new window) - - in your browser. -

-
- -
-
-

Dragging files

-
-
- Drag Demo -
-

- Click and drag the link above to copy the renderer process - javascript file on to your machine. -

- -

- In this demo, the webContents.startDrag() API is called - in response to the ondragstart event. -

-
Renderer Process
-

-const {ipcRenderer} = require('electron')
-
-const dragFileLink = document.getElementById('drag-file-link')
-
-dragFileLink.addEventListener('dragstart', (event) => {
-  event.preventDefault()
-  ipcRenderer.send('ondragstart', __filename)
-})
-        
-
Main Process
-
-            
-const {ipcMain} = require('electron')
-const path = require('path')
-
-ipcMain.on('ondragstart', (event, filepath) => {
-  const iconName = 'codeIcon.png'
-  event.sender.startDrag({
-    file: filepath,
-    icon: path.join(__dirname, iconName)
-  })
-})
-            
-
-
-
- - - - + + + + + Drag and drop files + + + +
+

Drag and drop files

+
Supports: Win, macOS, Linux | Process: Both
+

+ Electron supports dragging files and content out from web content into + the operating system's world. +

+ +

+ Open the + + full API documentation (opens in new window) + + in your browser. +

+
+ +
+
+

Dragging files

+
+
+ Drag Demo +
+

+ Click and drag the link above to copy the renderer process + javascript file on to your machine. +

+ +

+ In this demo, the webContents.startDrag() API is called + in response to the ondragstart event. +

+
Renderer Process
+

+const {ipcRenderer} = require('electron')
+
+const dragFileLink = document.getElementById('drag-file-link')
+
+dragFileLink.addEventListener('dragstart', (event) => {
+  event.preventDefault()
+  ipcRenderer.send('ondragstart', __filename)
+})
+        
+
Main Process
+
+            
+const {ipcMain} = require('electron')
+const path = require('path')
+
+ipcMain.on('ondragstart', (event, filepath) => {
+  const iconName = 'codeIcon.png'
+  event.sender.startDrag({
+    file: filepath,
+    icon: path.join(__dirname, iconName)
+  })
+})
+            
+
+
+
+ + + + diff --git a/docs/fiddles/native-ui/drag-and-drop/main.js b/docs/fiddles/native-ui/drag-and-drop/main.js index b7093b59a868b..b4dce1a663708 100644 --- a/docs/fiddles/native-ui/drag-and-drop/main.js +++ b/docs/fiddles/native-ui/drag-and-drop/main.js @@ -1,5 +1,7 @@ // Modules to control application life and create native browser window -const { app, BrowserWindow, ipcMain, nativeImage } = require('electron') +const { app, BrowserWindow, ipcMain, nativeImage, shell } = require('electron/main') +const path = require('node:path') + // Keep a global reference of the window object, if you don't, the window will // be closed automatically when the JavaScript object is garbage collected. let mainWindow @@ -10,7 +12,7 @@ function createWindow () { width: 800, height: 600, webPreferences: { - nodeIntegration: true + preload: path.join(__dirname, 'preload.js') } }) @@ -27,6 +29,12 @@ function createWindow () { // when you should delete the corresponding element. mainWindow = null }) + + // Open external links in the default browser + mainWindow.webContents.on('will-navigate', (event, url) => { + event.preventDefault() + shell.openExternal(url) + }) } // This method will be called when Electron has finished @@ -51,7 +59,8 @@ app.on('activate', function () { } }) -ipcMain.on('ondragstart', (event, filepath) => { +ipcMain.on('ondragstart', (event) => { + const filepath = path.join(__dirname, 'renderer.js') const icon = nativeImage.createFromDataURL('data:image/png;base64,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') event.sender.startDrag({ diff --git a/docs/fiddles/native-ui/drag-and-drop/preload.js b/docs/fiddles/native-ui/drag-and-drop/preload.js new file mode 100644 index 0000000000000..bad5ed4c8466c --- /dev/null +++ b/docs/fiddles/native-ui/drag-and-drop/preload.js @@ -0,0 +1,5 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electronAPI', { + dragStart: () => ipcRenderer.send('ondragstart') +}) diff --git a/docs/fiddles/native-ui/drag-and-drop/renderer.js b/docs/fiddles/native-ui/drag-and-drop/renderer.js index 67f35d61ee1b7..031601023d9a9 100644 --- a/docs/fiddles/native-ui/drag-and-drop/renderer.js +++ b/docs/fiddles/native-ui/drag-and-drop/renderer.js @@ -1,21 +1,6 @@ -const { ipcRenderer } = require('electron') -const shell = require('electron').shell - -const links = document.querySelectorAll('a[href]') - -Array.prototype.forEach.call(links, (link) => { - const url = link.getAttribute('href') - if (url.indexOf('http') === 0) { - link.addEventListener('click', (e) => { - e.preventDefault() - shell.openExternal(url) - }) - } -}) - const dragFileLink = document.getElementById('drag-file-link') dragFileLink.addEventListener('dragstart', event => { event.preventDefault() - ipcRenderer.send('ondragstart', __filename) + window.electronAPI.dragStart() }) diff --git a/docs/fiddles/native-ui/external-links-file-manager/.keep b/docs/fiddles/native-ui/external-links-file-manager/.keep deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/docs/fiddles/native-ui/external-links-file-manager/external-links/index.html b/docs/fiddles/native-ui/external-links-file-manager/external-links/index.html deleted file mode 100644 index f96fae00f79c6..0000000000000 --- a/docs/fiddles/native-ui/external-links-file-manager/external-links/index.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - - Open external links - - -
-
-
-
- -
-

- If you do not want your app to open website links - within the app, you can use the shell module - to open them externally. When clicked, the links will open outside - of your app and in the user's default web browser. -

-

- When the demo button is clicked, the electron website will open in - your browser. -

-

-
Renderer Process
-

-                const { shell } = require('electron')
-                const exLinksBtn = document.getElementById('open-ex-links')
-                exLinksBtn.addEventListener('click', (event) => {
-                shell.openExternal('https://electronjs.org')
-                }) 
-            
- -
-

ProTip

- Open all outbound links externally. -

- You may want to open all http and - https links outside of your app. To do this, query - the document and loop through each link and add a listener. This - app uses the code below which is located in - assets/ex-links.js. -

-
Renderer Process
-

-                const { shell } = require('electron')
-                const links = document.querySelectorAll('a[href]')
-                Array.prototype.forEach.call(links, (link) => {
-                    const url = link.getAttribute('href')
-                    if (url.indexOf('http') === 0) {
-                    link.addEventListener('click', (e) => {
-                        e.preventDefault()
-                        shell.openExternal(url)
-                    })
-                }})
-            
-
-
-
-
- - - - diff --git a/docs/fiddles/native-ui/external-links-file-manager/external-links/main.js b/docs/fiddles/native-ui/external-links-file-manager/external-links/main.js deleted file mode 100644 index 8c60edf69f8b3..0000000000000 --- a/docs/fiddles/native-ui/external-links-file-manager/external-links/main.js +++ /dev/null @@ -1,25 +0,0 @@ -const { app, BrowserWindow } = require('electron') - -let mainWindow = null - -function createWindow () { - const windowOptions = { - width: 600, - height: 400, - title: 'Open External Links', - webPreferences: { - nodeIntegration: true - } - } - - mainWindow = new BrowserWindow(windowOptions) - mainWindow.loadFile('index.html') - - mainWindow.on('closed', () => { - mainWindow = null - }) -} - -app.whenReady().then(() => { - createWindow() -}) diff --git a/docs/fiddles/native-ui/external-links-file-manager/external-links/renderer.js b/docs/fiddles/native-ui/external-links-file-manager/external-links/renderer.js deleted file mode 100644 index 14ed2d979f628..0000000000000 --- a/docs/fiddles/native-ui/external-links-file-manager/external-links/renderer.js +++ /dev/null @@ -1,21 +0,0 @@ -const { shell } = require('electron') - -const exLinksBtn = document.getElementById('open-ex-links') - -exLinksBtn.addEventListener('click', (event) => { - shell.openExternal('https://electronjs.org') -}) - -const OpenAllOutboundLinks = () => { - const links = document.querySelectorAll('a[href]') - - Array.prototype.forEach.call(links, (link) => { - const url = link.getAttribute('href') - if (url.indexOf('http') === 0) { - link.addEventListener('click', (e) => { - e.preventDefault() - shell.openExternal(url) - }) - } - }) -} diff --git a/docs/fiddles/native-ui/external-links-file-manager/index.html b/docs/fiddles/native-ui/external-links-file-manager/index.html index c4b41b9905556..83788b8e4f74b 100644 --- a/docs/fiddles/native-ui/external-links-file-manager/index.html +++ b/docs/fiddles/native-ui/external-links-file-manager/index.html @@ -1,104 +1,100 @@ - - - - - Open external links and the file manager - - -
-

- Open external links and the file manager -

-

- The shell module in Electron allows you to access certain - native elements like the file manager and default web browser. -

- -

This module works in both the main and renderer process.

-

- Open the - - full API documentation (opens in new window) - - in your browser. -

-
- -
-
-

Open Path in File Manager

-
-
- -
-

- This demonstrates using the shell module to open the - system file manager at a particular location. -

-

- Clicking the demo button will open your file manager at the root. -

-
-
-
- -
-
-

Open External Links

-
-
- -
-

- If you do not want your app to open website links - within the app, you can use the shell module - to open them externally. When clicked, the links will open outside - of your app and in the user's default web browser. -

-

- When the demo button is clicked, the electron website will open in - your browser. -

-

- -
-

ProTip

- Open all outbound links externally. -

- You may want to open all http and - https links outside of your app. To do this, query - the document and loop through each link and add a listener. This - app uses the code below which is located in - assets/ex-links.js. -

-
Renderer Process
-
-                
-const shell = require('electron').shell
-
-const links = document.querySelectorAll('a[href]')
-
-Array.prototype.forEach.call(links, (link) => {
-  const url = link.getAttribute('href')
-  if (url.indexOf('http') === 0) {
-    link.addEventListener('click', (e) => {
-      e.preventDefault()
-      shell.openExternal(url)
-    })
-  }
-})
-                
-              
-
-
-
-
- - - - + + + + + Open external links and the file manager + + +
+

+ Open external links and the file manager +

+

+ The shell module in Electron allows you to access certain + native elements like the file manager and default web browser. +

+ +

This module works in both the main and renderer process.

+

+ Open the + + full API documentation (opens in new window) + + in your browser. +

+
+ +
+
+

Open Path in File Manager

+
+
+ +
+

+ This demonstrates using the shell module to open the + system file manager at a particular location. +

+

+ Clicking the demo button will open your file manager at the root. +

+
+
+
+ +
+
+

Open External Links

+
+
+ +
+

+ If you do not want your app to open website links + within the app, you can use the shell module + to open them externally. When clicked, the links will open outside + of your app and in the user's default web browser. +

+

+ When the demo button is clicked, the electron website will open in + your browser. +

+

+ +
+

ProTip

+ Open all outbound links externally. +

+ You may want to open all http and + https links outside of your app. To do this, query + the document and loop through each link and add a listener. This + app uses the code below which is located in + assets/ex-links.js. +

+
Renderer Process
+
+                
+const shell = require('electron').shell
+
+const links = document.querySelectorAll('a[href]')
+
+for (const link of links) {
+  const url = link.getAttribute('href')
+  if (url.indexOf('http') === 0) {
+    link.addEventListener('click', (e) => {
+      e.preventDefault()
+      shell.openExternal(url)
+    })
+  }
+}
+                
+              
+
+
+
+
+ + + diff --git a/docs/fiddles/native-ui/external-links-file-manager/main.js b/docs/fiddles/native-ui/external-links-file-manager/main.js index 6291dcad9c993..b98a8669b0ba7 100644 --- a/docs/fiddles/native-ui/external-links-file-manager/main.js +++ b/docs/fiddles/native-ui/external-links-file-manager/main.js @@ -1,5 +1,15 @@ // Modules to control application life and create native browser window -const { app, BrowserWindow } = require('electron') +const { app, BrowserWindow, shell, ipcMain } = require('electron/main') +const path = require('node:path') +const os = require('node:os') + +ipcMain.on('open-home-dir', () => { + shell.showItemInFolder(os.homedir()) +}) + +ipcMain.on('open-external', (event, url) => { + shell.openExternal(url) +}) // Keep a global reference of the window object, if you don't, the window will // be closed automatically when the JavaScript object is garbage collected. @@ -11,7 +21,7 @@ function createWindow () { width: 800, height: 600, webPreferences: { - nodeIntegration: true + preload: path.join(__dirname, 'preload.js') } }) @@ -28,6 +38,12 @@ function createWindow () { // when you should delete the corresponding element. mainWindow = null }) + + // Open external links in the default browser + mainWindow.webContents.on('will-navigate', (event, url) => { + event.preventDefault() + shell.openExternal(url) + }) } // This method will be called when Electron has finished diff --git a/docs/fiddles/native-ui/external-links-file-manager/path-in-file-manager/index.html b/docs/fiddles/native-ui/external-links-file-manager/path-in-file-manager/index.html deleted file mode 100644 index be6a38c9fa167..0000000000000 --- a/docs/fiddles/native-ui/external-links-file-manager/path-in-file-manager/index.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - -
-
-

Open Path in File Manager

- Supports: Win, macOS, Linux | Process: Both -
-

This demonstrates using the shell module to open the system file manager at a particular location.

-

Clicking the demo button will open your file manager at the root.

-
- -
-
-
-
- - - \ No newline at end of file diff --git a/docs/fiddles/native-ui/external-links-file-manager/path-in-file-manager/main.js b/docs/fiddles/native-ui/external-links-file-manager/path-in-file-manager/main.js deleted file mode 100644 index 9246b95bb242c..0000000000000 --- a/docs/fiddles/native-ui/external-links-file-manager/path-in-file-manager/main.js +++ /dev/null @@ -1,25 +0,0 @@ -const { app, BrowserWindow } = require('electron') - -let mainWindow = null - -function createWindow () { - const windowOptions = { - width: 600, - height: 400, - title: 'Open Path in File Manager', - webPreferences: { - nodeIntegration: true - } - } - - mainWindow = new BrowserWindow(windowOptions) - mainWindow.loadFile('index.html') - - mainWindow.on('closed', () => { - mainWindow = null - }) -} - -app.whenReady().then(() => { - createWindow() -}) diff --git a/docs/fiddles/native-ui/external-links-file-manager/path-in-file-manager/renderer.js b/docs/fiddles/native-ui/external-links-file-manager/path-in-file-manager/renderer.js deleted file mode 100644 index d49754cdb7311..0000000000000 --- a/docs/fiddles/native-ui/external-links-file-manager/path-in-file-manager/renderer.js +++ /dev/null @@ -1,8 +0,0 @@ -const { shell } = require('electron') -const os = require('os') - -const fileManagerBtn = document.getElementById('open-file-manager') - -fileManagerBtn.addEventListener('click', (event) => { - shell.showItemInFolder(os.homedir()) -}) diff --git a/docs/fiddles/native-ui/external-links-file-manager/preload.js b/docs/fiddles/native-ui/external-links-file-manager/preload.js new file mode 100644 index 0000000000000..9be85a13eaeba --- /dev/null +++ b/docs/fiddles/native-ui/external-links-file-manager/preload.js @@ -0,0 +1,6 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electronAPI', { + openHomeDir: () => ipcRenderer.send('open-home-dir'), + openExternal: (url) => ipcRenderer.send('open-external', url) +}) diff --git a/docs/fiddles/native-ui/external-links-file-manager/renderer.js b/docs/fiddles/native-ui/external-links-file-manager/renderer.js index 5ce5bae2da3aa..6903268fd0d02 100644 --- a/docs/fiddles/native-ui/external-links-file-manager/renderer.js +++ b/docs/fiddles/native-ui/external-links-file-manager/renderer.js @@ -1,13 +1,10 @@ -const { shell } = require('electron') -const os = require('os') - const exLinksBtn = document.getElementById('open-ex-links') const fileManagerBtn = document.getElementById('open-file-manager') fileManagerBtn.addEventListener('click', (event) => { - shell.showItemInFolder(os.homedir()) + window.electronAPI.openHomeDir() }) exLinksBtn.addEventListener('click', (event) => { - shell.openExternal('https://electronjs.org') + window.electronAPI.openExternal('https://electronjs.org') }) diff --git a/docs/fiddles/native-ui/notifications/.keep b/docs/fiddles/native-ui/notifications/.keep deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/docs/fiddles/native-ui/notifications/basic-notification/index.html b/docs/fiddles/native-ui/notifications/basic-notification/index.html deleted file mode 100644 index 2ffd45453701a..0000000000000 --- a/docs/fiddles/native-ui/notifications/basic-notification/index.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - -
-

Basic notification

- Supports: Win 7+, macOS, Linux (that supports libnotify)| Process: Renderer -
-
- -
-

This demo demonstrates a basic notification. Text only.

-
-
- - - diff --git a/docs/fiddles/native-ui/notifications/basic-notification/main.js b/docs/fiddles/native-ui/notifications/basic-notification/main.js deleted file mode 100644 index b05ea9cbcc6e5..0000000000000 --- a/docs/fiddles/native-ui/notifications/basic-notification/main.js +++ /dev/null @@ -1,25 +0,0 @@ -const { BrowserWindow, app } = require('electron') - -let mainWindow = null - -function createWindow () { - const windowOptions = { - width: 600, - height: 300, - title: 'Basic Notification', - webPreferences: { - nodeIntegration: true - } - } - - mainWindow = new BrowserWindow(windowOptions) - mainWindow.loadFile('index.html') - - mainWindow.on('closed', () => { - mainWindow = null - }) -} - -app.whenReady().then(() => { - createWindow() -}) diff --git a/docs/fiddles/native-ui/notifications/basic-notification/renderer.js b/docs/fiddles/native-ui/notifications/basic-notification/renderer.js deleted file mode 100644 index a46583c683dea..0000000000000 --- a/docs/fiddles/native-ui/notifications/basic-notification/renderer.js +++ /dev/null @@ -1,14 +0,0 @@ -const notification = { - title: 'Basic Notification', - body: 'Short message part' -} - -const notificationButton = document.getElementById('basic-noti') - -notificationButton.addEventListener('click', () => { - const myNotification = new window.Notification(notification.title, notification) - - myNotification.onclick = () => { - console.log('Notification clicked') - } -}) diff --git a/docs/fiddles/native-ui/notifications/index.html b/docs/fiddles/native-ui/notifications/index.html index 2848ad6d552d3..0eb9e213d556b 100644 --- a/docs/fiddles/native-ui/notifications/index.html +++ b/docs/fiddles/native-ui/notifications/index.html @@ -1,67 +1,64 @@ - - - - - Desktop notifications - - -
-

Desktop notifications

-

- The notification module in Electron allows you to add basic - desktop notifications. -

- -

- Electron conveniently allows developers to send notifications with the - HTML5 Notification API, - using the currently running operating system’s native notification - APIs to display it. -

- -

- Note: Since this is an HTML5 API it is only available in the - renderer process. -

- -

- Open the - - full API documentation(opens in new window) - - in your browser. -

-
- -
-
-

Basic notification

-
-
- -
-

This demo demonstrates a basic notification. Text only.

-
-
-
- -
-
-

Notification with image

-
-
- -
-

- This demo demonstrates a basic notification. Both text and a image -

-
-
-
- - - - + + + + + Desktop notifications + + +
+

Desktop notifications

+

+ The notification module in Electron allows you to add basic + desktop notifications. +

+ +

+ Electron conveniently allows developers to send notifications with the + HTML5 Notification API, + using the currently running operating system’s native notification + APIs to display it. +

+ +

+ Note: Since this is an HTML5 API it is only available in the + renderer process. +

+ +

+ Open the + + full API documentation(opens in new window) + + in your browser. +

+
+ +
+
+

Basic notification

+
+
+ +
+

This demo demonstrates a basic notification. Text only.

+
+
+
+ +
+
+

Notification with image

+
+
+ +
+

+ This demo demonstrates a basic notification. Both text and a image +

+
+
+
+ + + + diff --git a/docs/fiddles/native-ui/notifications/main.js b/docs/fiddles/native-ui/notifications/main.js index 6291dcad9c993..f880a67a492c2 100644 --- a/docs/fiddles/native-ui/notifications/main.js +++ b/docs/fiddles/native-ui/notifications/main.js @@ -1,5 +1,5 @@ // Modules to control application life and create native browser window -const { app, BrowserWindow } = require('electron') +const { app, BrowserWindow, shell } = require('electron/main') // Keep a global reference of the window object, if you don't, the window will // be closed automatically when the JavaScript object is garbage collected. @@ -9,10 +9,7 @@ function createWindow () { // Create the browser window. mainWindow = new BrowserWindow({ width: 800, - height: 600, - webPreferences: { - nodeIntegration: true - } + height: 600 }) // and load the index.html of the app. @@ -28,6 +25,12 @@ function createWindow () { // when you should delete the corresponding element. mainWindow = null }) + + // Open external links in the default browser + mainWindow.webContents.on('will-navigate', (event, url) => { + event.preventDefault() + shell.openExternal(url) + }) } // This method will be called when Electron has finished diff --git a/docs/fiddles/native-ui/notifications/notification-with-image/index.html b/docs/fiddles/native-ui/notifications/notification-with-image/index.html deleted file mode 100644 index 5b9df4e78ecb5..0000000000000 --- a/docs/fiddles/native-ui/notifications/notification-with-image/index.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - -
-

Notification with image

- Supports: Win 7+, macOS, Linux (that supports libnotify)| Process: Renderer -
-
- -
-

This demo demonstrates an advanced notification. Both text and image.

-
-
- - - diff --git a/docs/fiddles/native-ui/notifications/notification-with-image/main.js b/docs/fiddles/native-ui/notifications/notification-with-image/main.js deleted file mode 100644 index 40c6001a99ecd..0000000000000 --- a/docs/fiddles/native-ui/notifications/notification-with-image/main.js +++ /dev/null @@ -1,25 +0,0 @@ -const { BrowserWindow, app } = require('electron') - -let mainWindow = null - -function createWindow () { - const windowOptions = { - width: 600, - height: 300, - title: 'Advanced Notification', - webPreferences: { - nodeIntegration: true - } - } - - mainWindow = new BrowserWindow(windowOptions) - mainWindow.loadFile('index.html') - - mainWindow.on('closed', () => { - mainWindow = null - }) -} - -app.whenReady().then(() => { - createWindow() -}) diff --git a/docs/fiddles/native-ui/notifications/notification-with-image/renderer.js b/docs/fiddles/native-ui/notifications/notification-with-image/renderer.js deleted file mode 100644 index 84c43d2e111be..0000000000000 --- a/docs/fiddles/native-ui/notifications/notification-with-image/renderer.js +++ /dev/null @@ -1,14 +0,0 @@ -const notification = { - title: 'Notification with image', - body: 'Short message plus a custom image', - icon: 'https://raw.githubusercontent.com/electron/electron-api-demos/v2.0.2/assets/img/programming.png' -} -const notificationButton = document.getElementById('advanced-noti') - -notificationButton.addEventListener('click', () => { - const myNotification = new window.Notification(notification.title, notification) - - myNotification.onclick = () => { - console.log('Notification clicked') - } -}) diff --git a/docs/fiddles/native-ui/tray/.keep b/docs/fiddles/native-ui/tray/.keep deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/docs/fiddles/native-ui/tray/index.html b/docs/fiddles/native-ui/tray/index.html deleted file mode 100644 index 2a330342f2df0..0000000000000 --- a/docs/fiddles/native-ui/tray/index.html +++ /dev/null @@ -1,126 +0,0 @@ - - - - - Tray - - -
-

Tray

-

- The tray module allows you to create an icon in the - operating system's notification area. -

-

This icon can also have a context menu attached.

- -

- Open the - - full API documentation (opens in new window) - - in your browser. -

-
- -
-
-
-
- - -
-

- The demo button sends a message to the main process using the - ipc module. In the main process the app is told to - place an icon, with a context menu, in the tray. -

- -

- In this example the tray icon can be removed by clicking 'Remove' in - the context menu or selecting the demo button again. -

-
Main Process
-
-              
-const path = require('path')
-const {ipcMain, app, Menu, Tray} = require('electron')
-
-let appIcon = null
-
-ipcMain.on('put-in-tray', (event) => {
-  const iconName = process.platform === 'win32' ? 'windows-icon.png' : 'iconTemplate.png'
-  const iconPath = path.join(__dirname, iconName)
-  appIcon = new Tray(iconPath)
-
-  const contextMenu = Menu.buildFromTemplate([{
-    label: 'Remove',
-    click: () => {
-      event.sender.send('tray-removed')
-    }
-  }])
-
-  appIcon.setToolTip('Electron Demo in the tray.')
-  appIcon.setContextMenu(contextMenu)
-})
-
-ipcMain.on('remove-tray', () => {
-  appIcon.destroy()
-})
-
-app.on('window-all-closed', () => {
-  if (appIcon) appIcon.destroy()
-})
-              
-            
-
Renderer Process
-
-              
-const ipc = require('electron').ipcRenderer
-
-const trayBtn = document.getElementById('put-in-tray')
-let trayOn = false
-
-trayBtn.addEventListener('click', function (event) {
-  if (trayOn) {
-    trayOn = false
-    document.getElementById('tray-countdown').innerHTML = ''
-    ipc.send('remove-tray')
-  } else {
-    trayOn = true
-    const message = 'Click demo again to remove.'
-    document.getElementById('tray-countdown').innerHTML = message
-    ipc.send('put-in-tray')
-  }
-})
-// Tray removed from context menu on icon
-ipc.on('tray-removed', function () {
-  ipc.send('remove-tray')
-  trayOn = false
-  document.getElementById('tray-countdown').innerHTML = ''
-})                  
-              
-            
- -
-

ProTip

- Tray support in Linux. -

- On Linux distributions that only have app indicator support, users - will need to install libappindicator1 to make the - tray icon work. See the - - full API documentation (opens in new window) - - for more details about using Tray on Linux. -

-
-
-
-
- - - - diff --git a/docs/fiddles/native-ui/tray/main.js b/docs/fiddles/native-ui/tray/main.js deleted file mode 100644 index 9a94efe327315..0000000000000 --- a/docs/fiddles/native-ui/tray/main.js +++ /dev/null @@ -1,77 +0,0 @@ -// Modules to control application life and create native browser window -const { ipcMain, app, nativeImage, Menu, Tray, BrowserWindow } = require('electron') - -// Keep a global reference of the window object, if you don't, the window will -// be closed automatically when the JavaScript object is garbage collected. -let mainWindow -let appIcon = null - -function createWindow () { - // Create the browser window. - mainWindow = new BrowserWindow({ - width: 800, - height: 600, - webPreferences: { - nodeIntegration: true - } - }) - - // and load the index.html of the app. - mainWindow.loadFile('index.html') - - // Open the DevTools. - // mainWindow.webContents.openDevTools() - - // Emitted when the window is closed. - mainWindow.on('closed', function () { - // Dereference the window object, usually you would store windows - // in an array if your app supports multi windows, this is the time - // when you should delete the corresponding element. - mainWindow = null - }) -} - -// This method will be called when Electron has finished -// initialization and is ready to create browser windows. -// Some APIs can only be used after this event occurs. -app.whenReady().then(createWindow) - -// Quit when all windows are closed. -app.on('window-all-closed', function () { - // On macOS it is common for applications and their menu bar - // to stay active until the user quits explicitly with Cmd + Q - if (process.platform !== 'darwin') { - app.quit() - } -}) - -app.on('activate', function () { - // On macOS it is common to re-create a window in the app when the - // dock icon is clicked and there are no other windows open. - if (mainWindow === null) { - createWindow() - } -}) - -ipcMain.on('put-in-tray', (event) => { - const icon = nativeImage.createFromDataURL('data:image/png;base64,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') - - appIcon = new Tray(icon) - - const contextMenu = Menu.buildFromTemplate([{ - label: 'Remove', - click: () => { - event.sender.send('tray-removed') - } - }]) - - appIcon.setToolTip('Electron Demo in the tray.') - appIcon.setContextMenu(contextMenu) -}) - -ipcMain.on('remove-tray', () => { - appIcon.destroy() -}) - -// In this file you can include the rest of your app's specific main process -// code. You can also put them in separate files and require them here. diff --git a/docs/fiddles/native-ui/tray/renderer.js b/docs/fiddles/native-ui/tray/renderer.js deleted file mode 100644 index 40eee8c859bdf..0000000000000 --- a/docs/fiddles/native-ui/tray/renderer.js +++ /dev/null @@ -1,35 +0,0 @@ -const { ipcRenderer, shell } = require('electron') - -const trayBtn = document.getElementById('put-in-tray') -const links = document.querySelectorAll('a[href]') - -let trayOn = false - -trayBtn.addEventListener('click', function (event) { - if (trayOn) { - trayOn = false - document.getElementById('tray-countdown').innerHTML = '' - ipcRenderer.send('remove-tray') - } else { - trayOn = true - const message = 'Click demo again to remove.' - document.getElementById('tray-countdown').innerHTML = message - ipcRenderer.send('put-in-tray') - } -}) -// Tray removed from context menu on icon -ipcRenderer.on('tray-removed', function () { - ipcRenderer.send('remove-tray') - trayOn = false - document.getElementById('tray-countdown').innerHTML = '' -}) - -Array.prototype.forEach.call(links, (link) => { - const url = link.getAttribute('href') - if (url.indexOf('http') === 0) { - link.addEventListener('click', (e) => { - e.preventDefault() - shell.openExternal(url) - }) - } -}) \ No newline at end of file diff --git a/docs/fiddles/quick-start/index.html b/docs/fiddles/quick-start/index.html new file mode 100644 index 0000000000000..f008d867a0f89 --- /dev/null +++ b/docs/fiddles/quick-start/index.html @@ -0,0 +1,16 @@ + + + + + Hello World! + + + +

Hello World!

+

+ We are using Node.js , + Chromium , + and Electron . +

+ + diff --git a/docs/fiddles/quick-start/main.js b/docs/fiddles/quick-start/main.js new file mode 100644 index 0000000000000..c614294e01db3 --- /dev/null +++ b/docs/fiddles/quick-start/main.js @@ -0,0 +1,30 @@ +const { app, BrowserWindow } = require('electron/main') +const path = require('node:path') + +function createWindow () { + const win = new BrowserWindow({ + width: 800, + height: 600, + webPreferences: { + preload: path.join(__dirname, 'preload.js') + } + }) + + win.loadFile('index.html') +} + +app.whenReady().then(() => { + createWindow() + + app.on('activate', () => { + if (BrowserWindow.getAllWindows().length === 0) { + createWindow() + } + }) +}) + +app.on('window-all-closed', () => { + if (process.platform !== 'darwin') { + app.quit() + } +}) diff --git a/docs/fiddles/quick-start/preload.js b/docs/fiddles/quick-start/preload.js new file mode 100644 index 0000000000000..d5f73597ee86b --- /dev/null +++ b/docs/fiddles/quick-start/preload.js @@ -0,0 +1,10 @@ +window.addEventListener('DOMContentLoaded', () => { + const replaceText = (selector, text) => { + const element = document.getElementById(selector) + if (element) element.innerText = text + } + + for (const type of ['chrome', 'node', 'electron']) { + replaceText(`${type}-version`, process.versions[type]) + } +}) diff --git a/docs/fiddles/screen/fit-screen/main.js b/docs/fiddles/screen/fit-screen/main.js index 8fbaabcc5b850..9b1ffcbbe0c10 100644 --- a/docs/fiddles/screen/fit-screen/main.js +++ b/docs/fiddles/screen/fit-screen/main.js @@ -1,16 +1,13 @@ // Retrieve information about screen size, displays, cursor position, etc. // // For more info, see: -// https://electronjs.org/docs/api/screen +// https://www.electronjs.org/docs/latest/api/screen -const { app, BrowserWindow } = require('electron') +const { app, BrowserWindow, screen } = require('electron/main') let mainWindow = null app.whenReady().then(() => { - // We cannot require the screen module until the app is ready. - const { screen } = require('electron') - // Create a window that fills the screen's available work area. const primaryDisplay = screen.getPrimaryDisplay() const { width, height } = primaryDisplay.workAreaSize diff --git a/docs/fiddles/system/clipboard/.keep b/docs/fiddles/system/clipboard/.keep deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/docs/fiddles/system/clipboard/copy/index.html b/docs/fiddles/system/clipboard/copy/index.html index 2bf063a2f516b..0b02eb7b8904b 100644 --- a/docs/fiddles/system/clipboard/copy/index.html +++ b/docs/fiddles/system/clipboard/copy/index.html @@ -2,12 +2,13 @@ +

Clipboard copy

- Supports: Win, macOS, Linux | Process: Both + Supports: Win, macOS, Linux | Process: Main, Renderer (non-sandboxed only)
@@ -17,8 +18,6 @@

Clipboard copy

+ - diff --git a/docs/fiddles/system/clipboard/copy/main.js b/docs/fiddles/system/clipboard/copy/main.js index 36ad14197f6b7..1c76f9d50acf5 100644 --- a/docs/fiddles/system/clipboard/copy/main.js +++ b/docs/fiddles/system/clipboard/copy/main.js @@ -1,4 +1,5 @@ -const { app, BrowserWindow } = require('electron') +const { app, BrowserWindow, ipcMain, clipboard } = require('electron/main') +const path = require('node:path') let mainWindow = null @@ -8,7 +9,7 @@ function createWindow () { height: 400, title: 'Clipboard copy', webPreferences: { - nodeIntegration: true + preload: path.join(__dirname, 'preload.js') } } @@ -20,6 +21,18 @@ function createWindow () { }) } +ipcMain.handle('clipboard:writeText', (event, text) => { + clipboard.writeText(text) +}) + app.whenReady().then(() => { createWindow() + + app.on('activate', function () { + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) +}) + +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit() }) diff --git a/docs/fiddles/system/clipboard/copy/preload.js b/docs/fiddles/system/clipboard/copy/preload.js new file mode 100644 index 0000000000000..580d3866576a6 --- /dev/null +++ b/docs/fiddles/system/clipboard/copy/preload.js @@ -0,0 +1,5 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('clipboard', { + writeText: (text) => ipcRenderer.invoke('clipboard:writeText', text) +}) diff --git a/docs/fiddles/system/clipboard/copy/renderer.js b/docs/fiddles/system/clipboard/copy/renderer.js index 75e204136e09a..cc2069adff95a 100644 --- a/docs/fiddles/system/clipboard/copy/renderer.js +++ b/docs/fiddles/system/clipboard/copy/renderer.js @@ -1,10 +1,8 @@ -const { clipboard } = require('electron') - const copyBtn = document.getElementById('copy-to') const copyInput = document.getElementById('copy-to-input') copyBtn.addEventListener('click', () => { if (copyInput.value !== '') copyInput.value = '' copyInput.placeholder = 'Copied! Paste here to see.' - clipboard.writeText('Electron Demo!') + window.clipboard.writeText('Electron Demo!') }) diff --git a/docs/fiddles/system/clipboard/paste/index.html b/docs/fiddles/system/clipboard/paste/index.html index 9cc2ac5ba7ce8..a7b300ea045b5 100644 --- a/docs/fiddles/system/clipboard/paste/index.html +++ b/docs/fiddles/system/clipboard/paste/index.html @@ -2,12 +2,13 @@ +

Clipboard paste

- Supports: Win, macOS, Linux | Process: Both + Supports: Win, macOS, Linux | Process: Main, Renderer (non-sandboxed only)
@@ -17,8 +18,6 @@

Clipboard paste

+ - diff --git a/docs/fiddles/system/clipboard/paste/main.js b/docs/fiddles/system/clipboard/paste/main.js index b0883e6f4e56f..58c2fbb3e88c8 100644 --- a/docs/fiddles/system/clipboard/paste/main.js +++ b/docs/fiddles/system/clipboard/paste/main.js @@ -1,4 +1,5 @@ -const { app, BrowserWindow } = require('electron') +const { app, BrowserWindow, ipcMain, clipboard } = require('electron/main') +const path = require('node:path') let mainWindow = null @@ -8,7 +9,7 @@ function createWindow () { height: 400, title: 'Clipboard paste', webPreferences: { - nodeIntegration: true + preload: path.join(__dirname, 'preload.js') } } @@ -20,6 +21,22 @@ function createWindow () { }) } +ipcMain.handle('clipboard:readText', () => { + return clipboard.readText() +}) + +ipcMain.handle('clipboard:writeText', (event, text) => { + clipboard.writeText(text) +}) + app.whenReady().then(() => { createWindow() + + app.on('activate', function () { + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) +}) + +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit() }) diff --git a/docs/fiddles/system/clipboard/paste/preload.js b/docs/fiddles/system/clipboard/paste/preload.js new file mode 100644 index 0000000000000..31ce721451d61 --- /dev/null +++ b/docs/fiddles/system/clipboard/paste/preload.js @@ -0,0 +1,6 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('clipboard', { + readText: () => ipcRenderer.invoke('clipboard:readText'), + writeText: (text) => ipcRenderer.invoke('clipboard:writeText', text) +}) diff --git a/docs/fiddles/system/clipboard/paste/renderer.js b/docs/fiddles/system/clipboard/paste/renderer.js index 27a52422cf0da..a4c75790f9385 100644 --- a/docs/fiddles/system/clipboard/paste/renderer.js +++ b/docs/fiddles/system/clipboard/paste/renderer.js @@ -1,9 +1,7 @@ -const { clipboard } = require('electron') - const pasteBtn = document.getElementById('paste-to') -pasteBtn.addEventListener('click', () => { - clipboard.writeText('What a demo!') - const message = `Clipboard contents: ${clipboard.readText()}` +pasteBtn.addEventListener('click', async () => { + await window.clipboard.writeText('What a demo!') + const message = `Clipboard contents: ${await window.clipboard.readText()}` document.getElementById('paste-from').innerHTML = message }) diff --git a/docs/fiddles/system/protocol-handler/.keep b/docs/fiddles/system/protocol-handler/.keep deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/index.html b/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/index.html index 1c89c4ce49b13..17e326b6cf8c5 100644 --- a/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/index.html +++ b/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/index.html @@ -1,92 +1,81 @@ - - - Hello World! - + + + + + + + app.setAsDefaultProtocol Demo + + -
-
-

- Protocol Handler -

-

The app module provides methods for handling protocols.

-

These methods allow you to set and unset the protocols your app should be the default app for. Similar to when a browser asks to be your default for viewing web pages.

+

App Default Protocol Demo

+ +

The protocol API allows us to register a custom protocol and intercept existing protocol requests.

+

These methods allow you to set and unset the protocols your app should be the default app for. Similar to when a + browser asks to be your default for viewing web pages.

+ +

Open the full protocol API documentation in your + browser.

+ + ----- + +

Demo

+

+ First: Launch current page in browser + +

+ +

+ Then: Launch the app from a web link! + Click here to launch the app +

+ + ---- -

Open the full app API documentation(opens in new window) in your browser.

-
+

You can set your app as the default app to open for a specific protocol. For instance, in this demo we set this app + as the default for electron-fiddle://. The demo button above will launch a page in your default + browser with a link. Click that link and it will re-launch this app.

-
- - -
-

You can set your app as the default app to open for a specific protocol. For instance, in this demo we set this app as the default for electron-api-demos://. The demo button above will launch a page in your default browser with a link. Click that link and it will re-launch this app.

-
Packaging
-

This feature will only work on macOS when your app is packaged. It will not work when you're launching it in development from the command-line. When you package your app you'll need to make sure the macOS plist for the app is updated to include the new protocol handler. If you're using electron-packager then you can add the flag --extend-info with a path to the plist you've created. The one for this app is below.

-
Renderer Process
-

-            const {shell} = require('electron')
-            const path = require('path')
-            const protocolHandlerBtn = document.getElementById('protocol-handler')
-            protocolHandlerBtn.addEventListener('click', () => {
-                const pageDirectory = __dirname.replace('app.asar', 'app.asar.unpacked')
-                const pagePath = path.join('file://', pageDirectory, '../../sections/system/protocol-link.html')
-                shell.openExternal(pagePath)
-            })
-          
-
Main Process
-

-            const {app, dialog} = require('electron')
-            const path = require('path')
 
-            if (process.defaultApp) {
-                if (process.argv.length >= 2) {
-                    app.setAsDefaultProtocolClient('electron-api-demos', process.execPath, [path.resolve(process.argv[1])])
-                }
-            } else {
-                app.setAsDefaultProtocolClient('electron-api-demos')
-            }
+  

Packaging

+

This feature will only work on macOS when your app is packaged. It will not work when you're launching it in + development from the command-line. When you package your app you'll need to make sure the macOS plist + for the app is updated to include the new protocol handler. If you're using @electron/packager then you + can add the flag --extend-info with a path to the plist you've created. The one for this + app is below:

- app.on('open-url', (event, url) => { - dialog.showErrorBox('Welcome Back', `You arrived from: ${url}`) - }) +

+

macOS plist
+

+    <?xml version="1.0" encoding="UTF-8"?>
+    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+            <plist version="1.0">
+                <dict>
+                    <key>CFBundleURLTypes</key>
+                    <array>
+                        <dict>
+                            <key>CFBundleURLSchemes</key>
+                            <array>
+                                <string>electron-api-demos</string>
+                            </array>
+                            <key>CFBundleURLName</key>
+                            <string>Electron API Demos Protocol</string>
+                        </dict>
+                    </array>
+                    <key>ElectronTeamID</key>
+                    <string>VEKTX9H2N7</string>
+                </dict>
+            </plist>
+        
+    
+

-

-
macOS plist
-

-            
-                
-                    
-                        
-                            CFBundleURLTypes
-                            
-                                
-                                    CFBundleURLSchemes
-                                    
-                                        electron-api-demos
-                                    
-                                    CFBundleURLName
-                                    Electron API Demos Protocol
-                                
-                            
-                            ElectronTeamID
-                            VEKTX9H2N7
-                        
-                    
-                
-            
-
-
- -
+ + - - - + \ No newline at end of file diff --git a/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/main.js b/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/main.js index fe3918e6a1a70..84efd0cb9748a 100644 --- a/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/main.js +++ b/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/main.js @@ -1,69 +1,65 @@ // Modules to control application life and create native browser window -const { app, BrowserWindow, dialog } = require('electron') -const path = require('path') +const { app, BrowserWindow, ipcMain, shell, dialog } = require('electron/main') +const path = require('node:path') -// Keep a global reference of the window object, if you don't, the window will -// be closed automatically when the JavaScript object is garbage collected. let mainWindow +if (process.defaultApp) { + if (process.argv.length >= 2) { + app.setAsDefaultProtocolClient('electron-fiddle', process.execPath, [path.resolve(process.argv[1])]) + } +} else { + app.setAsDefaultProtocolClient('electron-fiddle') +} + +const gotTheLock = app.requestSingleInstanceLock() + +if (!gotTheLock) { + app.quit() +} else { + app.on('second-instance', (event, commandLine, workingDirectory) => { + // Someone tried to run a second instance, we should focus our window. + if (mainWindow) { + if (mainWindow.isMinimized()) mainWindow.restore() + mainWindow.focus() + } + + dialog.showErrorBox('Welcome Back', `You arrived from: ${commandLine.pop().slice(0, -1)}`) + }) + + // Create mainWindow, load the rest of the app, etc... + app.whenReady().then(() => { + createWindow() + }) + + app.on('open-url', (event, url) => { + dialog.showErrorBox('Welcome Back', `You arrived from: ${url}`) + }) +} + function createWindow () { // Create the browser window. mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { - nodeIntegration: true + preload: path.join(__dirname, 'preload.js') } }) - // and load the index.html of the app. mainWindow.loadFile('index.html') - - // Open the DevTools. - mainWindow.webContents.openDevTools() - - // Emitted when the window is closed. - mainWindow.on('closed', function () { - // Dereference the window object, usually you would store windows - // in an array if your app supports multi windows, this is the time - // when you should delete the corresponding element. - mainWindow = null - }) } -// This method will be called when Electron has finished -// initialization and is ready to create browser windows. -// Some APIs can only be used after this event occurs. -app.whenReady().then(createWindow) - -// Quit when all windows are closed. +// Quit when all windows are closed, except on macOS. There, it's common +// for applications and their menu bar to stay active until the user quits +// explicitly with Cmd + Q. app.on('window-all-closed', function () { - // On macOS it is common for applications and their menu bar - // to stay active until the user quits explicitly with Cmd + Q - if (process.platform !== 'darwin') { - app.quit() - } + if (process.platform !== 'darwin') app.quit() }) -app.on('activate', function () { - // On macOS it is common to re-create a window in the app when the - // dock icon is clicked and there are no other windows open. - if (mainWindow === null) { - createWindow() - } -}) - -// In this file you can include the rest of your app's specific main process -// code. You can also put them in separate files and require them here. - -if (process.defaultApp) { - if (process.argv.length >= 2) { - app.setAsDefaultProtocolClient('electron-api-demos', process.execPath, [path.resolve(process.argv[1])]) - } -} else { - app.setAsDefaultProtocolClient('electron-api-demos') -} - -app.on('open-url', (event, url) => { - dialog.showErrorBox('Welcome Back', `You arrived from: ${url}`) +// Handle window controls via IPC +ipcMain.on('shell:open', () => { + const pageDirectory = __dirname.replace('app.asar', 'app.asar.unpacked') + const pagePath = path.join('file://', pageDirectory, 'index.html') + shell.openExternal(pagePath) }) diff --git a/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/preload.js b/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/preload.js new file mode 100644 index 0000000000000..eda1d8c721844 --- /dev/null +++ b/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/preload.js @@ -0,0 +1,5 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('shell', { + open: () => ipcRenderer.send('shell:open') +}) diff --git a/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/renderer.js b/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/renderer.js index 8aa314d3c2c06..a933c04e70a88 100644 --- a/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/renderer.js +++ b/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/renderer.js @@ -1,14 +1,8 @@ -const { shell } = require('electron') -const path = require('path') +// This file is required by the index.html file and will +// be executed in the renderer process for that window. +// All APIs exposed by the context bridge are available here. -const openInBrowserButton = document.getElementById('open-in-browser') -const openAppLink = document.getElementById('open-app-link') -// Hides openAppLink when loaded inside Electron -openAppLink.style.display = 'none' - -openInBrowserButton.addEventListener('click', () => { - console.log('clicked') - const pageDirectory = __dirname.replace('app.asar', 'app.asar.unpacked') - const pagePath = path.join('file://', pageDirectory, 'index.html') - shell.openExternal(pagePath) +// Binds the buttons to the context bridge API. +document.getElementById('open-in-browser').addEventListener('click', () => { + window.shell.open() }) diff --git a/docs/fiddles/system/system-app-user-information/.keep b/docs/fiddles/system/system-app-user-information/.keep deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/docs/fiddles/system/system-app-user-information/app-information/index.html b/docs/fiddles/system/system-app-user-information/app-information/index.html index 18b05ae23dae6..f8b0e38c3fd13 100644 --- a/docs/fiddles/system/system-app-user-information/app-information/index.html +++ b/docs/fiddles/system/system-app-user-information/app-information/index.html @@ -14,13 +14,10 @@

App Information

The main process app module can be used to get the path at which your app is located on the user's computer.

In this example, to get that information from the renderer process, we use the ipc module to send a message to the main process requesting the app's path.

-

See the app module documentation(opens in new window) for more.

+

See the app module documentation(opens in new window) for more.

- + - \ No newline at end of file + \ No newline at end of file diff --git a/docs/fiddles/system/system-app-user-information/app-information/main.js b/docs/fiddles/system/system-app-user-information/app-information/main.js index 64141f98e88dd..247bad8f5272c 100644 --- a/docs/fiddles/system/system-app-user-information/app-information/main.js +++ b/docs/fiddles/system/system-app-user-information/app-information/main.js @@ -1,5 +1,34 @@ -const {app, ipcMain} = require('electron') +const { app, BrowserWindow, ipcMain, shell } = require('electron/main') +const path = require('node:path') -ipcMain.on('get-app-path', (event) => { - event.sender.send('got-app-path', app.getAppPath()) -}) \ No newline at end of file +let mainWindow = null + +ipcMain.handle('get-app-path', (event) => app.getAppPath()) + +function createWindow () { + const windowOptions = { + width: 600, + height: 400, + title: 'Get app information', + webPreferences: { + preload: path.join(__dirname, 'preload.js') + } + } + + mainWindow = new BrowserWindow(windowOptions) + mainWindow.loadFile('index.html') + + mainWindow.on('closed', () => { + mainWindow = null + }) + + // Open external links in the default browser + mainWindow.webContents.on('will-navigate', (event, url) => { + event.preventDefault() + shell.openExternal(url) + }) +} + +app.whenReady().then(() => { + createWindow() +}) diff --git a/docs/fiddles/system/system-app-user-information/app-information/preload.js b/docs/fiddles/system/system-app-user-information/app-information/preload.js new file mode 100644 index 0000000000000..92e3efa325035 --- /dev/null +++ b/docs/fiddles/system/system-app-user-information/app-information/preload.js @@ -0,0 +1,5 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electronAPI', { + getAppPath: () => ipcRenderer.invoke('get-app-path') +}) diff --git a/docs/fiddles/system/system-app-user-information/app-information/renderer.js b/docs/fiddles/system/system-app-user-information/app-information/renderer.js index 3f971abcab7c5..35b201bf4091e 100644 --- a/docs/fiddles/system/system-app-user-information/app-information/renderer.js +++ b/docs/fiddles/system/system-app-user-information/app-information/renderer.js @@ -1,18 +1,7 @@ -const {ipcRenderer} = require('electron') - const appInfoBtn = document.getElementById('app-info') -const electron_doc_link = document.querySelectorAll('a[href]') - -appInfoBtn.addEventListener('click', () => { - ipcRenderer.send('get-app-path') -}) -ipcRenderer.on('got-app-path', (event, path) => { +appInfoBtn.addEventListener('click', async () => { + const path = await window.electronAPI.getAppPath() const message = `This app is located at: ${path}` document.getElementById('got-app-info').innerHTML = message }) - -electron_doc_link.addEventListener('click', (e) => { - e.preventDefault() - shell.openExternal(url) -}) \ No newline at end of file diff --git a/docs/fiddles/system/system-information/get-version-information/index.html b/docs/fiddles/system/system-information/get-version-information/index.html index b19df1f2b534b..3bd06b382ec04 100644 --- a/docs/fiddles/system/system-information/get-version-information/index.html +++ b/docs/fiddles/system/system-information/get-version-information/index.html @@ -15,12 +15,10 @@

Get version information

The process module is built into Node.js (therefore you can use this in both the main and renderer processes) and in Electron apps this object has a few more useful properties on it.

The example below gets the version of Electron in use by the app.

-

See the process documentation (opens in new window) for more.

+

See the process documentation (opens in new window) for more.

- + diff --git a/docs/fiddles/system/system-information/get-version-information/main.js b/docs/fiddles/system/system-information/get-version-information/main.js index daf87d0fda97a..e1a7434a52479 100644 --- a/docs/fiddles/system/system-information/get-version-information/main.js +++ b/docs/fiddles/system/system-information/get-version-information/main.js @@ -1,4 +1,5 @@ -const { app, BrowserWindow } = require('electron') +const { app, BrowserWindow, shell } = require('electron/main') +const path = require('node:path') let mainWindow = null @@ -8,7 +9,7 @@ function createWindow () { height: 400, title: 'Get version information', webPreferences: { - nodeIntegration: true + preload: path.join(__dirname, 'preload.js') } } @@ -18,6 +19,12 @@ function createWindow () { mainWindow.on('closed', () => { mainWindow = null }) + + // Open external links in the default browser + mainWindow.webContents.on('will-navigate', (event, url) => { + event.preventDefault() + shell.openExternal(url) + }) } app.whenReady().then(() => { diff --git a/docs/fiddles/system/system-information/get-version-information/preload.js b/docs/fiddles/system/system-information/get-version-information/preload.js new file mode 100644 index 0000000000000..fa4eab9154a8d --- /dev/null +++ b/docs/fiddles/system/system-information/get-version-information/preload.js @@ -0,0 +1,3 @@ +const { contextBridge } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electronVersion', process.versions.electron) diff --git a/docs/fiddles/system/system-information/get-version-information/renderer.js b/docs/fiddles/system/system-information/get-version-information/renderer.js index 40f7f2cf2cf64..3e7c22e5c2075 100644 --- a/docs/fiddles/system/system-information/get-version-information/renderer.js +++ b/docs/fiddles/system/system-information/get-version-information/renderer.js @@ -1,8 +1,6 @@ const versionInfoBtn = document.getElementById('version-info') -const electronVersion = process.versions.electron - versionInfoBtn.addEventListener('click', () => { - const message = `This app is using Electron version: ${electronVersion}` + const message = `This app is using Electron version: ${window.electronVersion}` document.getElementById('got-version-info').innerHTML = message }) diff --git a/docs/fiddles/tutorial-first-app/index.html b/docs/fiddles/tutorial-first-app/index.html new file mode 100644 index 0000000000000..3d677b7c97b5b --- /dev/null +++ b/docs/fiddles/tutorial-first-app/index.html @@ -0,0 +1,21 @@ + + + + + + + Hello from Electron renderer! + + +

Hello from Electron renderer!

+

👋

+

+ + + diff --git a/docs/fiddles/tutorial-first-app/main.js b/docs/fiddles/tutorial-first-app/main.js new file mode 100644 index 0000000000000..8e92734f271ee --- /dev/null +++ b/docs/fiddles/tutorial-first-app/main.js @@ -0,0 +1,26 @@ +const { app, BrowserWindow } = require('electron/main') + +const createWindow = () => { + const win = new BrowserWindow({ + width: 800, + height: 600 + }) + + win.loadFile('index.html') +} + +app.whenReady().then(() => { + createWindow() + + app.on('activate', () => { + if (BrowserWindow.getAllWindows().length === 0) { + createWindow() + } + }) +}) + +app.on('window-all-closed', () => { + if (process.platform !== 'darwin') { + app.quit() + } +}) diff --git a/docs/fiddles/tutorial-preload/index.html b/docs/fiddles/tutorial-preload/index.html new file mode 100644 index 0000000000000..3d677b7c97b5b --- /dev/null +++ b/docs/fiddles/tutorial-preload/index.html @@ -0,0 +1,21 @@ + + + + + + + Hello from Electron renderer! + + +

Hello from Electron renderer!

+

👋

+

+ + + diff --git a/docs/fiddles/tutorial-preload/main.js b/docs/fiddles/tutorial-preload/main.js new file mode 100644 index 0000000000000..f62f401355d11 --- /dev/null +++ b/docs/fiddles/tutorial-preload/main.js @@ -0,0 +1,30 @@ +const { app, BrowserWindow } = require('electron/main') +const path = require('node:path') + +const createWindow = () => { + const win = new BrowserWindow({ + width: 800, + height: 600, + webPreferences: { + preload: path.join(__dirname, 'preload.js') + } + }) + + win.loadFile('index.html') +} + +app.whenReady().then(() => { + createWindow() + + app.on('activate', () => { + if (BrowserWindow.getAllWindows().length === 0) { + createWindow() + } + }) +}) + +app.on('window-all-closed', () => { + if (process.platform !== 'darwin') { + app.quit() + } +}) diff --git a/docs/fiddles/tutorial-preload/preload.js b/docs/fiddles/tutorial-preload/preload.js new file mode 100644 index 0000000000000..561df488dce66 --- /dev/null +++ b/docs/fiddles/tutorial-preload/preload.js @@ -0,0 +1,7 @@ +const { contextBridge } = require('electron/renderer') + +contextBridge.exposeInMainWorld('versions', { + node: () => process.versions.node, + chrome: () => process.versions.chrome, + electron: () => process.versions.electron +}) diff --git a/docs/fiddles/tutorial-preload/renderer.js b/docs/fiddles/tutorial-preload/renderer.js new file mode 100644 index 0000000000000..6c8c471aa3390 --- /dev/null +++ b/docs/fiddles/tutorial-preload/renderer.js @@ -0,0 +1,2 @@ +const information = document.getElementById('info') +information.innerText = `This app is using Chrome (v${window.versions.chrome()}), Node.js (v${window.versions.node()}), and Electron (v${window.versions.electron()})` diff --git a/docs/fiddles/windows/manage-windows/.keep b/docs/fiddles/windows/manage-windows/.keep deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/docs/fiddles/windows/manage-windows/create-frameless-window/index.html b/docs/fiddles/windows/manage-windows/create-frameless-window/index.html deleted file mode 100644 index c83c43d636ed9..0000000000000 --- a/docs/fiddles/windows/manage-windows/create-frameless-window/index.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - -
-
-

Create a frameless window

- Supports: Win, macOS, Linux | Process: Main -
-

A frameless window is a window that has no "chrome", - such as toolbars, title bars, status bars, borders, etc. You can make - a browser window frameless by setting - frame to false when creating the window.

-
- -
-
-
-
- - - \ No newline at end of file diff --git a/docs/fiddles/windows/manage-windows/create-frameless-window/main.js b/docs/fiddles/windows/manage-windows/create-frameless-window/main.js deleted file mode 100644 index 05d530736a3b8..0000000000000 --- a/docs/fiddles/windows/manage-windows/create-frameless-window/main.js +++ /dev/null @@ -1,22 +0,0 @@ -const { app, BrowserWindow, ipcMain } = require('electron') - -ipcMain.on('create-frameless-window', (event, {url}) => { - const win = new BrowserWindow({ frame: false }) - win.loadURL(url) -}) - -function createWindow () { - const mainWindow = new BrowserWindow({ - width: 600, - height: 400, - title: 'Create a frameless window', - webPreferences: { - nodeIntegration: true - } - }) - mainWindow.loadFile('index.html') -} - -app.whenReady().then(() => { - createWindow() -}) diff --git a/docs/fiddles/windows/manage-windows/create-frameless-window/renderer.js b/docs/fiddles/windows/manage-windows/create-frameless-window/renderer.js deleted file mode 100644 index 21f91ad561b37..0000000000000 --- a/docs/fiddles/windows/manage-windows/create-frameless-window/renderer.js +++ /dev/null @@ -1,8 +0,0 @@ -const { ipcRenderer } = require('electron') - -const newWindowBtn = document.getElementById('frameless-window') - -newWindowBtn.addEventListener('click', () => { - const url = 'data:text/html,

Hello World!

Close this Window' - ipcRenderer.send('create-frameless-window', { url }) -}) diff --git a/docs/fiddles/windows/manage-windows/frameless-window/index.html b/docs/fiddles/windows/manage-windows/frameless-window/index.html index 3f8b1b90552da..69ef074f23a56 100644 --- a/docs/fiddles/windows/manage-windows/frameless-window/index.html +++ b/docs/fiddles/windows/manage-windows/frameless-window/index.html @@ -1,76 +1,73 @@ - - - - - Frameless window - - - -
-

Create and Manage Windows

- -

- The BrowserWindow module in Electron allows you to create a - new browser window or manage an existing one. -

- -

- Each browser window is a separate process, known as the renderer - process. This process, like the main process that controls the life - cycle of the app, has full access to the Node.js APIs. -

- -

- Open the - - full API documentation (opens in new window) - - in your browser. -

-
- -
-
-

Create a frameless window

-
-
- -
-

- A frameless window is a window that has no - - "chrome" - - , such as toolbars, title bars, status bars, borders, etc. You can - make a browser window frameless by setting frame to - false when creating the window. -

- -

- Windows can have a transparent background, too. By setting the - transparent option to true, you can also - make your frameless window transparent: -

-
-var win = new BrowserWindow({
-  transparent: true,
-  frame: false
-})
- -

- For more details, see the - - Frameless Window - - documentation. -

-
-
-
- - - - + + + + + Frameless window + + + +
+

Create and Manage Windows

+ +

+ The BrowserWindow module in Electron allows you to create a + new browser window or manage an existing one. +

+ +

+ Each browser window is a separate process, known as the renderer + process. This process, like the main process that controls the life + cycle of the app, has full access to the Node.js APIs. +

+ +

+ Open the + + full API documentation (opens in new window) + + in your browser. +

+
+ +
+
+

Create a frameless window

+
+
+ +
+

+ A frameless window is a window that has no + + "chrome" + + , such as toolbars, title bars, status bars, borders, etc. You can + make a browser window frameless by setting frame to + false when creating the window. +

+ +

+ Windows can have a transparent background, too. By setting the + transparent option to true, you can also + make your frameless window transparent: +

+
+var win = new BrowserWindow({
+  transparent: true,
+  frame: false
+})
+ +

+ For more details, see the + + Window Customization + + + documentation. +

+
+
+
+ + + diff --git a/docs/fiddles/windows/manage-windows/frameless-window/main.js b/docs/fiddles/windows/manage-windows/frameless-window/main.js index d7925cd7ff4a6..507242962ab05 100644 --- a/docs/fiddles/windows/manage-windows/frameless-window/main.js +++ b/docs/fiddles/windows/manage-windows/frameless-window/main.js @@ -1,7 +1,8 @@ // Modules to control application life and create native browser window -const { app, BrowserWindow } = require('electron') +const { app, BrowserWindow, ipcMain, shell } = require('electron/main') +const path = require('node:path') -ipcMain.on('create-frameless-window', (event, {url}) => { +ipcMain.on('create-frameless-window', (event, { url }) => { const win = new BrowserWindow({ frame: false }) win.loadURL(url) }) @@ -12,34 +13,38 @@ function createWindow () { width: 800, height: 600, webPreferences: { - nodeIntegration: true + preload: path.join(__dirname, 'preload.js') } }) // and load the index.html of the app. mainWindow.loadFile('index.html') + + // Open external links in the default browser + mainWindow.webContents.on('will-navigate', (event, url) => { + event.preventDefault() + shell.openExternal(url) + }) } // This method will be called when Electron has finished // initialization and is ready to create browser windows. // Some APIs can only be used after this event occurs. -app.whenReady().then(createWindow) +app.whenReady().then(() => { + createWindow() -// Quit when all windows are closed. -app.on('window-all-closed', function () { - // On macOS it is common for applications and their menu bar - // to stay active until the user quits explicitly with Cmd + Q - if (process.platform !== 'darwin') { - app.quit() - } + app.on('activate', function () { + // On macOS it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) }) -app.on('activate', function () { - // On macOS it is common to re-create a window in the app when the - // dock icon is clicked and there are no other windows open. - if (mainWindow === null) { - createWindow() - } +// Quit when all windows are closed, except on macOS. There, it's common +// for applications and their menu bar to stay active until the user quits +// explicitly with Cmd + Q. +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit() }) // In this file you can include the rest of your app's specific main process diff --git a/docs/fiddles/windows/manage-windows/frameless-window/preload.js b/docs/fiddles/windows/manage-windows/frameless-window/preload.js new file mode 100644 index 0000000000000..0feaa676755cc --- /dev/null +++ b/docs/fiddles/windows/manage-windows/frameless-window/preload.js @@ -0,0 +1,5 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electronAPI', { + createFramelessWindow: (args) => ipcRenderer.send('create-frameless-window', args) +}) diff --git a/docs/fiddles/windows/manage-windows/frameless-window/renderer.js b/docs/fiddles/windows/manage-windows/frameless-window/renderer.js index 21f91ad561b37..7638f56099f0e 100644 --- a/docs/fiddles/windows/manage-windows/frameless-window/renderer.js +++ b/docs/fiddles/windows/manage-windows/frameless-window/renderer.js @@ -1,8 +1,6 @@ -const { ipcRenderer } = require('electron') - const newWindowBtn = document.getElementById('frameless-window') newWindowBtn.addEventListener('click', () => { const url = 'data:text/html,

Hello World!

Close this Window' - ipcRenderer.send('create-frameless-window', { url }) + window.electronAPI.createFramelessWindow({ url }) }) diff --git a/docs/fiddles/windows/manage-windows/manage-window-state/index.html b/docs/fiddles/windows/manage-windows/manage-window-state/index.html index e9e39ceccc18e..9c6236dd77d2b 100644 --- a/docs/fiddles/windows/manage-windows/manage-window-state/index.html +++ b/docs/fiddles/windows/manage-windows/manage-window-state/index.html @@ -1,64 +1,60 @@ - - - - - Manage window state - - - -
-

Create and Manage Windows

- -

- The BrowserWindow module in Electron allows you to create a - new browser window or manage an existing one. -

- -

- Each browser window is a separate process, known as the renderer - process. This process, like the main process that controls the life - cycle of the app, has full access to the Node.js APIs. -

- -

- Open the - - full API documentation (opens in new window) - - in your browser. -

-
- -
-
-

Manage window state

-
-
- - -
-

- In this demo we create a new window and listen for - move and resize events on it. Click the - demo button, change the new window and see the dimensions and - position update here, above. -

-

- There are a lot of methods for controlling the state of the window - such as the size, location, and focus status as well as events to - listen to for window changes. Visit the - - documentation (opens in new window) - - for the full list. -

-
-
-
- - - - + + + + + Manage window state + + + +
+

Create and Manage Windows

+ +

+ The BrowserWindow module in Electron allows you to create a + new browser window or manage an existing one. +

+ +

+ Each browser window is a separate process, known as the renderer + process. This process, like the main process that controls the life + cycle of the app, has full access to the Node.js APIs. +

+ +

+ Open the + + full API documentation (opens in new window) + + in your browser. +

+
+ +
+
+

Manage window state

+
+
+ + +
+

+ In this demo we create a new window and listen for + move and resize events on it. Click the + demo button, change the new window and see the dimensions and + position update here, above. +

+

+ There are a lot of methods for controlling the state of the window + such as the size, location, and focus status as well as events to + listen to for window changes. Visit the + + documentation (opens in new window) + + for the full list. +

+
+
+
+ + + diff --git a/docs/fiddles/windows/manage-windows/manage-window-state/main.js b/docs/fiddles/windows/manage-windows/manage-window-state/main.js index 166ff0fa62f5a..afb42233926be 100644 --- a/docs/fiddles/windows/manage-windows/manage-window-state/main.js +++ b/docs/fiddles/windows/manage-windows/manage-window-state/main.js @@ -1,10 +1,11 @@ // Modules to control application life and create native browser window -const { app, BrowserWindow, ipcMain } = require('electron') +const { app, BrowserWindow, ipcMain, shell } = require('electron/main') +const path = require('node:path') ipcMain.on('create-demo-window', (event) => { const win = new BrowserWindow({ width: 400, height: 275 }) - function updateReply() { + function updateReply () { event.sender.send('bounds-changed', { size: win.getSize(), position: win.getPosition() @@ -18,38 +19,42 @@ ipcMain.on('create-demo-window', (event) => { function createWindow () { // Create the browser window. - mainWindow = new BrowserWindow({ + const mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { - nodeIntegration: true + preload: path.join(__dirname, 'preload.js') } }) // and load the index.html of the app. mainWindow.loadFile('index.html') + + // Open external links in the default browser + mainWindow.webContents.on('will-navigate', (event, url) => { + event.preventDefault() + shell.openExternal(url) + }) } // This method will be called when Electron has finished // initialization and is ready to create browser windows. // Some APIs can only be used after this event occurs. -app.whenReady().then(createWindow) +app.whenReady().then(() => { + createWindow() -// Quit when all windows are closed. -app.on('window-all-closed', function () { - // On macOS it is common for applications and their menu bar - // to stay active until the user quits explicitly with Cmd + Q - if (process.platform !== 'darwin') { - app.quit() - } + app.on('activate', function () { + // On macOS it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) }) -app.on('activate', function () { - // On macOS it is common to re-create a window in the app when the - // dock icon is clicked and there are no other windows open. - if (mainWindow === null) { - createWindow() - } +// Quit when all windows are closed, except on macOS. There, it's common +// for applications and their menu bar to stay active until the user quits +// explicitly with Cmd + Q. +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit() }) // In this file you can include the rest of your app's specific main process diff --git a/docs/fiddles/windows/manage-windows/manage-window-state/preload.js b/docs/fiddles/windows/manage-windows/manage-window-state/preload.js new file mode 100644 index 0000000000000..d604ee529cb1e --- /dev/null +++ b/docs/fiddles/windows/manage-windows/manage-window-state/preload.js @@ -0,0 +1,6 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electronAPI', { + createDemoWindow: () => ipcRenderer.send('create-demo-window'), + onBoundsChanged: (callback) => ipcRenderer.on('bounds-changed', () => callback()) +}) diff --git a/docs/fiddles/windows/manage-windows/manage-window-state/renderer.js b/docs/fiddles/windows/manage-windows/manage-window-state/renderer.js index 7b1aa8ae23b11..c152fd5ae1e90 100644 --- a/docs/fiddles/windows/manage-windows/manage-window-state/renderer.js +++ b/docs/fiddles/windows/manage-windows/manage-window-state/renderer.js @@ -1,25 +1,11 @@ -const { shell, ipcRenderer } = require('electron') - const manageWindowBtn = document.getElementById('manage-window') -const links = document.querySelectorAll('a[href]') - -ipcRenderer.on('bounds-changed', (event, bounds) => { +window.electronAPI.onBoundsChanged((event, bounds) => { const manageWindowReply = document.getElementById('manage-window-reply') const message = `Size: ${bounds.size} Position: ${bounds.position}` manageWindowReply.textContent = message }) manageWindowBtn.addEventListener('click', (event) => { - ipcRenderer.send('create-demo-window') -}) - -Array.prototype.forEach.call(links, (link) => { - const url = link.getAttribute('href') - if (url.indexOf('http') === 0) { - link.addEventListener('click', (e) => { - e.preventDefault() - shell.openExternal(url) - }) - } + window.electronAPI.createDemoWindow() }) diff --git a/docs/fiddles/windows/manage-windows/new-window/index.html b/docs/fiddles/windows/manage-windows/new-window/index.html index 08fbcab03c943..3cd5df4a17966 100644 --- a/docs/fiddles/windows/manage-windows/new-window/index.html +++ b/docs/fiddles/windows/manage-windows/new-window/index.html @@ -8,18 +8,15 @@

Create a new window

Supports: Win, macOS, Linux | Process: Main

The BrowserWindow module gives you the ability to create new windows in your app.

-

There are a lot of options when creating a new window. A few are in this demo, but visit the documentation(opens in new window) -

-

ProTip

- Use an invisible browser window to run background tasks. -

You can set a new browser window to not be shown (be invisible) in order to use that additional renderer process as a kind of new thread in which to run JavaScript in the background of your app. You do this by setting the show property to false when defining the new window.

-
var win = new BrowserWindow({
+  

There are a lot of options when creating a new window. A few are in this demo, but visit the documentation(opens in new window) +

+

ProTip

+ Use an invisible browser window to run background tasks. +

You can set a new browser window to not be shown (be invisible) in order to use that additional renderer process as a kind of new thread in which to run JavaScript in the background of your app. You do this by setting the show property to false when defining the new window.

+
var win = new BrowserWindow({
   width: 400, height: 225, show: false
 })
-
- +
+ diff --git a/docs/fiddles/windows/manage-windows/new-window/main.js b/docs/fiddles/windows/manage-windows/new-window/main.js index 2e51387e37aca..109055ac80b0e 100644 --- a/docs/fiddles/windows/manage-windows/new-window/main.js +++ b/docs/fiddles/windows/manage-windows/new-window/main.js @@ -1,5 +1,6 @@ // Modules to control application life and create native browser window -const { app, BrowserWindow, ipcMain } = require('electron') +const { app, BrowserWindow, ipcMain, shell } = require('electron/main') +const path = require('node:path') ipcMain.on('new-window', (event, { url, width, height }) => { const win = new BrowserWindow({ width, height }) @@ -12,34 +13,38 @@ function createWindow () { width: 800, height: 600, webPreferences: { - nodeIntegration: true + preload: path.join(__dirname, 'preload.js') } }) // and load the index.html of the app. mainWindow.loadFile('index.html') + + // Open external links in the default browser + mainWindow.webContents.on('will-navigate', (event, url) => { + event.preventDefault() + shell.openExternal(url) + }) } // This method will be called when Electron has finished // initialization and is ready to create browser windows. // Some APIs can only be used after this event occurs. -app.whenReady().then(createWindow) +app.whenReady().then(() => { + createWindow() -// Quit when all windows are closed. -app.on('window-all-closed', function () { - // On macOS it is common for applications and their menu bar - // to stay active until the user quits explicitly with Cmd + Q - if (process.platform !== 'darwin') { - app.quit() - } + app.on('activate', function () { + // On macOS it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) }) -app.on('activate', function () { - // On macOS it is common to re-create a window in the app when the - // dock icon is clicked and there are no other windows open. - if (mainWindow === null) { - createWindow() - } +// Quit when all windows are closed, except on macOS. There, it's common +// for applications and their menu bar to stay active until the user quits +// explicitly with Cmd + Q. +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit() }) // In this file you can include the rest of your app's specific main process diff --git a/docs/fiddles/windows/manage-windows/new-window/preload.js b/docs/fiddles/windows/manage-windows/new-window/preload.js new file mode 100644 index 0000000000000..53019d908fb73 --- /dev/null +++ b/docs/fiddles/windows/manage-windows/new-window/preload.js @@ -0,0 +1,5 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electronAPI', { + newWindow: (args) => ipcRenderer.send('new-window', args) +}) diff --git a/docs/fiddles/windows/manage-windows/new-window/renderer.js b/docs/fiddles/windows/manage-windows/new-window/renderer.js index ccb8b22643296..22caea84a3153 100644 --- a/docs/fiddles/windows/manage-windows/new-window/renderer.js +++ b/docs/fiddles/windows/manage-windows/new-window/renderer.js @@ -1,14 +1,6 @@ -const { shell, ipcRenderer } = require('electron') - const newWindowBtn = document.getElementById('new-window') -const link = document.getElementById('browser-window-link') newWindowBtn.addEventListener('click', (event) => { const url = 'https://electronjs.org' - ipcRenderer.send('new-window', { url, width: 400, height: 320 }); -}) - -link.addEventListener('click', (e) => { - e.preventDefault() - shell.openExternal("https://electronjs.org/docs/api/browser-window") + window.electronAPI.newWindow({ url, width: 400, height: 320 }) }) diff --git a/docs/fiddles/windows/manage-windows/window-events/index.html b/docs/fiddles/windows/manage-windows/window-events/index.html index d244bf167506c..5c05a3c9a2e76 100644 --- a/docs/fiddles/windows/manage-windows/window-events/index.html +++ b/docs/fiddles/windows/manage-windows/window-events/index.html @@ -1,58 +1,54 @@ - - - - - Window events - - - -
-

Create and Manage Windows

- -

- The BrowserWindow module in Electron allows you to create a - new browser window or manage an existing one. -

- -

- Each browser window is a separate process, known as the renderer - process. This process, like the main process that controls the life - cycle of the app, has full access to the Node.js APIs. -

- -

- Open the - - full API documentation (opens in new window) - - in your browser. -

-
- -
-
-

Window events

-
-
- - -
-

- In this demo, we create a new window and listen for - blur event on it. Click the demo button to create a new - modal window, and switch focus back to the parent window by clicking - on it. You can click the Focus on Demo button to switch focus - to the modal window again. -

-
-
-
- - - - + + + + + Window events + + + +
+

Create and Manage Windows

+ +

+ The BrowserWindow module in Electron allows you to create a + new browser window or manage an existing one. +

+ +

+ Each browser window is a separate process, known as the renderer + process. This process, like the main process that controls the life + cycle of the app, has full access to the Node.js APIs. +

+ +

+ Open the + + full API documentation (opens in new window) + + in your browser. +

+
+ +
+
+

Window events

+
+
+ + +
+

+ In this demo, we create a new window and listen for + blur event on it. Click the demo button to create a new + modal window, and switch focus back to the parent window by clicking + on it. You can click the Focus on Demo button to switch focus + to the modal window again. +

+
+
+
+ + + diff --git a/docs/fiddles/windows/manage-windows/window-events/main.js b/docs/fiddles/windows/manage-windows/window-events/main.js index 3effec304fc4f..5f10651d240a6 100644 --- a/docs/fiddles/windows/manage-windows/window-events/main.js +++ b/docs/fiddles/windows/manage-windows/window-events/main.js @@ -1,5 +1,6 @@ // Modules to control application life and create native browser window -const { app, BrowserWindow, ipcMain } = require('electron') +const { app, BrowserWindow, ipcMain, shell } = require('electron/main') +const path = require('node:path') function createWindow () { // Create the browser window. @@ -7,13 +8,19 @@ function createWindow () { width: 800, height: 600, webPreferences: { - nodeIntegration: true + preload: path.join(__dirname, 'preload.js') } }) // and load the index.html of the app. mainWindow.loadFile('index.html') + // Open external links in the default browser + mainWindow.webContents.on('will-navigate', (event, url) => { + event.preventDefault() + shell.openExternal(url) + }) + let demoWindow ipcMain.on('show-demo-window', () => { if (demoWindow) { @@ -23,6 +30,7 @@ function createWindow () { demoWindow = new BrowserWindow({ width: 600, height: 400 }) demoWindow.loadURL('https://electronjs.org') demoWindow.on('close', () => { + demoWindow = undefined mainWindow.webContents.send('window-close') }) demoWindow.on('focus', () => { @@ -41,23 +49,21 @@ function createWindow () { // This method will be called when Electron has finished // initialization and is ready to create browser windows. // Some APIs can only be used after this event occurs. -app.whenReady().then(createWindow) +app.whenReady().then(() => { + createWindow() -// Quit when all windows are closed. -app.on('window-all-closed', function () { - // On macOS it is common for applications and their menu bar - // to stay active until the user quits explicitly with Cmd + Q - if (process.platform !== 'darwin') { - app.quit() - } + app.on('activate', function () { + // On macOS it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) }) -app.on('activate', function () { - // On macOS it is common to re-create a window in the app when the - // dock icon is clicked and there are no other windows open. - if (mainWindow === null) { - createWindow() - } +// Quit when all windows are closed, except on macOS. There, it's common +// for applications and their menu bar to stay active until the user quits +// explicitly with Cmd + Q. +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit() }) // In this file you can include the rest of your app's specific main process diff --git a/docs/fiddles/windows/manage-windows/window-events/preload.js b/docs/fiddles/windows/manage-windows/window-events/preload.js new file mode 100644 index 0000000000000..b33f860a6446e --- /dev/null +++ b/docs/fiddles/windows/manage-windows/window-events/preload.js @@ -0,0 +1,9 @@ +const { contextBridge, ipcRenderer } = require('electron/renderer') + +contextBridge.exposeInMainWorld('electronAPI', { + showDemoWindow: () => ipcRenderer.send('show-demo-window'), + focusDemoWindow: () => ipcRenderer.send('focus-demo-window'), + onWindowFocus: (callback) => ipcRenderer.on('window-focus', () => callback()), + onWindowBlur: (callback) => ipcRenderer.on('window-blur', () => callback()), + onWindowClose: (callback) => ipcRenderer.on('window-close', () => callback()) +}) diff --git a/docs/fiddles/windows/manage-windows/window-events/renderer.js b/docs/fiddles/windows/manage-windows/window-events/renderer.js index 575d283a615a3..814605ecbe295 100644 --- a/docs/fiddles/windows/manage-windows/window-events/renderer.js +++ b/docs/fiddles/windows/manage-windows/window-events/renderer.js @@ -1,5 +1,3 @@ -const { shell, ipcRenderer } = require('electron') - const listenToWindowBtn = document.getElementById('listen-to-window') const focusModalBtn = document.getElementById('focus-on-modal-window') @@ -15,25 +13,13 @@ const showFocusBtn = (btn) => { focusModalBtn.addEventListener('click', focusWindow) } const focusWindow = () => { - ipcRenderer.send('focus-demo-window') + window.electronAPI.focusDemoWindow() } -ipcRenderer.on('window-focus', hideFocusBtn) -ipcRenderer.on('window-close', hideFocusBtn) -ipcRenderer.on('window-blur', showFocusBtn) +window.electronAPI.onWindowFocus(hideFocusBtn) +window.electronAPI.onWindowClose(hideFocusBtn) +window.electronAPI.onWindowBlur(showFocusBtn) listenToWindowBtn.addEventListener('click', () => { - ipcRenderer.send('show-demo-window') -}) - -const links = document.querySelectorAll('a[href]') - -Array.prototype.forEach.call(links, (link) => { - const url = link.getAttribute('href') - if (url.indexOf('http') === 0) { - link.addEventListener('click', (e) => { - e.preventDefault() - shell.openExternal(url) - }) - } + window.electronAPI.showDemoWindow() }) diff --git a/docs/glossary.md b/docs/glossary.md index 500f095b1171d..a108f1079507b 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -4,15 +4,48 @@ This page defines some terminology that is commonly used in Electron development ### ASAR -ASAR stands for Atom Shell Archive Format. An [asar][asar] archive is a simple +ASAR stands for Atom Shell Archive Format. An [asar][] archive is a simple `tar`-like format that concatenates files into a single file. Electron can read arbitrary files from it without unpacking the whole file. -The ASAR format was created primarily to improve performance on Windows... TODO +The ASAR format was created primarily to improve performance on Windows when +reading large quantities of small files (e.g. when loading your app's JavaScript +dependency tree from `node_modules`). + +### ASAR integrity + +ASAR integrity is a security feature that validates the contents of your app's +ASAR archives at runtime. When enabled, your Electron app will verify the +header hash of its ASAR archive on runtime. If no hash is present or if there is a mismatch in the +hashes, the app will forcefully terminate. + +See the [ASAR Integrity](./tutorial/asar-integrity.md) guide for more details. + +### code signing + +Code signing is a process where an app developer digitally signs their code to +ensure that it hasn't been tampered with after packaging. Both Windows and +macOS implement their own version of code signing. As a desktop app developer, +it's important that you sign your code if you plan on distributing it to the +general public. + +For more information, read the [Code Signing][] tutorial. + +### context isolation + +Context isolation is a security measure in Electron that ensures that your +preload script cannot leak privileged Electron or Node.js APIs to the web +contents in your renderer process. With context isolation enabled, the +only way to expose APIs from your preload script is through the +`contextBridge` API. + +For more information, read the [Context Isolation][] tutorial. + +See also: [preload script](#preload-script), [renderer process](#renderer-process) ### CRT -The C Run-time Library (CRT) is the part of the C++ Standard Library that +The C Runtime Library (CRT) is the part of the C++ Standard Library that incorporates the ISO C99 standard library. The Visual C++ libraries that implement the CRT support native code development, and both mixed native and managed code, and pure managed code for .NET development. @@ -20,8 +53,7 @@ managed code, and pure managed code for .NET development. ### DMG An Apple Disk Image is a packaging format used by macOS. DMG files are -commonly used for distributing application "installers". [electron-builder] -supports `dmg` as a build target. +commonly used for distributing application "installers". ### IME @@ -31,19 +63,15 @@ keyboards to input Chinese, Japanese, Korean and Indic characters. ### IDL -Interface description language. Write function signatures and data types in a format that can be used to generate interfaces in Java, C++, JavaScript, etc. +Interface description language. Write function signatures and data types in a +format that can be used to generate interfaces in Java, C++, JavaScript, etc. ### IPC -IPC stands for Inter-Process Communication. Electron uses IPC to send -serialized JSON messages between the [main] and [renderer] processes. - -### libchromiumcontent - -A shared library that includes the [Chromium Content module] and all its -dependencies (e.g., Blink, [V8], etc.). Also referred to as "libcc". +IPC stands for inter-process communication. Electron uses IPC to send +serialized JSON messages between the main and renderer processes. -- [github.com/electron/libchromiumcontent](https://github.com/electron/libchromiumcontent) +see also: [main process](#main-process), [renderer process](#renderer-process) ### main process @@ -64,17 +92,29 @@ See also: [process](#process), [renderer process](#renderer-process) ### MAS Acronym for Apple's Mac App Store. For details on submitting your app to the -MAS, see the [Mac App Store Submission Guide]. +MAS, see the [Mac App Store Submission Guide][]. ### Mojo -An IPC system for communicating intra- or inter-process, and that's important because Chrome is keen on being able to split its work into separate processes or not, depending on memory pressures etc. +An IPC system for communicating intra- or inter-process, and that's important +because Chrome is keen on being able to split its work into separate processes +or not, depending on memory pressures etc. + +See https://chromium.googlesource.com/chromium/src/+/main/mojo/README.md + +See also: [IPC](#ipc) + +### MSI -See https://chromium.googlesource.com/chromium/src/+/master/mojo/README.md +On Windows, MSI packages are used by the Windows Installer +(also known as Microsoft Installer) service to install and configure +applications. + +More information can be found in [Microsoft's documentation][msi]. ### native modules -Native modules (also called [addons] in +Native modules (also called [addons][] in Node.js) are modules written in C or C++ that can be loaded into Node.js or Electron using the require() function, and used as if they were an ordinary Node.js module. They are used primarily to provide an interface @@ -85,26 +125,37 @@ likely to use a different V8 version from the Node binary installed in your system, you have to manually specify the location of Electron’s headers when building native modules. -See also [Using Native Node Modules]. +For more information, read the [Native Node Modules][] tutorial. + +### notarization -### NSIS +Notarization is a macOS-specific process where a developer can send a +code-signed app to Apple servers to get verified for malicious +components through an automated service. -Nullsoft Scriptable Install System is a script-driven Installer -authoring tool for Microsoft Windows. It is released under a combination of -free software licenses, and is a widely-used alternative to commercial -proprietary products like InstallShield. [electron-builder] supports NSIS -as a build target. +See also: [code signing](#code-signing) ### OSR -OSR (Off-screen rendering) can be used for loading heavy page in +OSR (offscreen rendering) can be used for loading a heavy page in background and then displaying it after (it will be much faster). -It allows you to render page without showing it on screen. +It allows you to render a page without showing it on screen. + +For more information, read the [Offscreen Rendering][] tutorial. + +### preload script + +Preload scripts contain code that executes in a renderer process +before its web contents begin loading. These scripts run within +the renderer context, but are granted more privileges by having +access to Node.js APIs. + +See also: [renderer process](#renderer-process), [context isolation](#context-isolation) ### process A process is an instance of a computer program that is being executed. Electron -apps that make use of the [main] and one or many [renderer] process are +apps that make use of the [main][] and one or many [renderer][] process are actually running several programs simultaneously. In Node.js and Electron, each running process has a `process` object. This @@ -120,17 +171,21 @@ The renderer process is a browser window in your app. Unlike the main process, there can be multiple of these and each is run in a separate process. They can also be hidden. -In normal browsers, web pages usually run in a sandboxed environment and are not -allowed access to native resources. Electron users, however, have the power to -use Node.js APIs in web pages allowing lower level operating system -interactions. - See also: [process](#process), [main process](#main-process) +### sandbox + +The sandbox is a security feature inherited from Chromium that restricts +your renderer processes to a limited set of permissions. + +For more information, read the [Process Sandboxing][] tutorial. + +See also: [process](#process) + ### Squirrel Squirrel is an open-source framework that enables Electron apps to update -automatically as new versions are released. See the [autoUpdater] API for +automatically as new versions are released. See the [autoUpdater][] API for info about getting started with Squirrel. ### userland @@ -148,6 +203,15 @@ overly prescriptive about how it should be used. Userland enables users to create and share tools that provide additional functionality on top of what is available in "core". +### utility process + +The utility process is a child of the main process that allows running any +untrusted services that cannot be run in the main process. Chromium uses this +process to perform network I/O, audio/video processing, device inputs etc. +In Electron, you can create this process using [UtilityProcess][] API. + +See also: [process](#process), [main process](#main-process) + ### V8 V8 is Google's open source JavaScript engine. It is written in C++ and is @@ -174,13 +238,14 @@ embedded content. [addons]: https://nodejs.org/api/addons.html [asar]: https://github.com/electron/asar -[autoUpdater]: api/auto-updater.md -[Chromium Content module]: https://www.chromium.org/developers/content-module -[electron-builder]: https://github.com/electron-userland/electron-builder -[libchromiumcontent]: #libchromiumcontent -[Mac App Store Submission Guide]: tutorial/mac-app-store-submission-guide.md +[autoupdater]: api/auto-updater.md +[code signing]: tutorial/code-signing.md +[context isolation]: tutorial/context-isolation.md +[mac app store submission guide]: tutorial/mac-app-store-submission-guide.md [main]: #main-process +[msi]: https://learn.microsoft.com/en-us/windows/win32/msi/windows-installer-portal +[Native Node Modules]: tutorial/using-native-node-modules.md +[offscreen rendering]: tutorial/offscreen-rendering.md +[process sandboxing]: tutorial/sandbox.md [renderer]: #renderer-process -[userland]: #userland -[Using Native Node Modules]: tutorial/using-native-node-modules.md -[V8]: #v8 +[UtilityProcess]: api/utility-process.md diff --git a/docs/images/chrome-processes.png b/docs/images/chrome-processes.png new file mode 100644 index 0000000000000..1b0a1c0060f95 Binary files /dev/null and b/docs/images/chrome-processes.png differ diff --git a/docs/images/connection-status.png b/docs/images/connection-status.png new file mode 100644 index 0000000000000..6dcf2574e86a0 Binary files /dev/null and b/docs/images/connection-status.png differ diff --git a/docs/images/corner-smoothing-example-0.svg b/docs/images/corner-smoothing-example-0.svg new file mode 100644 index 0000000000000..928435ed0b006 --- /dev/null +++ b/docs/images/corner-smoothing-example-0.svg @@ -0,0 +1,3 @@ + + + diff --git a/docs/images/corner-smoothing-example-100.svg b/docs/images/corner-smoothing-example-100.svg new file mode 100644 index 0000000000000..34d0802239bef --- /dev/null +++ b/docs/images/corner-smoothing-example-100.svg @@ -0,0 +1,3 @@ + + + diff --git a/docs/images/corner-smoothing-example-30.svg b/docs/images/corner-smoothing-example-30.svg new file mode 100644 index 0000000000000..4996a25253ce0 --- /dev/null +++ b/docs/images/corner-smoothing-example-30.svg @@ -0,0 +1,3 @@ + + + diff --git a/docs/images/corner-smoothing-example-60.svg b/docs/images/corner-smoothing-example-60.svg new file mode 100644 index 0000000000000..cb1e68a8ff688 --- /dev/null +++ b/docs/images/corner-smoothing-example-60.svg @@ -0,0 +1,3 @@ + + + diff --git a/docs/images/corner-smoothing-summary.svg b/docs/images/corner-smoothing-summary.svg new file mode 100644 index 0000000000000..75bffa8e259d3 --- /dev/null +++ b/docs/images/corner-smoothing-summary.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/docs/images/frameless-window.png b/docs/images/frameless-window.png new file mode 100644 index 0000000000000..586242c19bde1 Binary files /dev/null and b/docs/images/frameless-window.png differ diff --git a/docs/images/gatekeeper.png b/docs/images/gatekeeper.png index ed4b15ec7e8d2..ee5e22d63043c 100644 Binary files a/docs/images/gatekeeper.png and b/docs/images/gatekeeper.png differ diff --git a/docs/images/message-notification-renderer.png b/docs/images/message-notification-renderer.png deleted file mode 100644 index 87c8a876a2b4f..0000000000000 Binary files a/docs/images/message-notification-renderer.png and /dev/null differ diff --git a/docs/images/notification-main.png b/docs/images/notification-main.png deleted file mode 100644 index 221c7230e3eb6..0000000000000 Binary files a/docs/images/notification-main.png and /dev/null differ diff --git a/docs/images/notification-renderer.png b/docs/images/notification-renderer.png deleted file mode 100644 index e66bc96abd7fb..0000000000000 Binary files a/docs/images/notification-renderer.png and /dev/null differ diff --git a/docs/images/online-event-detection.png b/docs/images/online-event-detection.png deleted file mode 100644 index 4f16489a7271c..0000000000000 Binary files a/docs/images/online-event-detection.png and /dev/null differ diff --git a/docs/images/preload-example.png b/docs/images/preload-example.png new file mode 100644 index 0000000000000..9f330b32de9ca Binary files /dev/null and b/docs/images/preload-example.png differ diff --git a/docs/images/recent-documents.png b/docs/images/recent-documents.png index 331466f3b1b35..3542c1315e34a 100644 Binary files a/docs/images/recent-documents.png and b/docs/images/recent-documents.png differ diff --git a/docs/images/represented-file.png b/docs/images/represented-file.png index a2d3a3cdd7707..8ccb477ab7e5a 100644 Binary files a/docs/images/represented-file.png and b/docs/images/represented-file.png differ diff --git a/docs/images/transparent-window-mission-control.png b/docs/images/transparent-window-mission-control.png new file mode 100644 index 0000000000000..444d87ddb4202 Binary files /dev/null and b/docs/images/transparent-window-mission-control.png differ diff --git a/docs/images/transparent-window.png b/docs/images/transparent-window.png new file mode 100644 index 0000000000000..8d5e51708177c Binary files /dev/null and b/docs/images/transparent-window.png differ diff --git a/docs/images/tutorial-release-schedule.svg b/docs/images/tutorial-release-schedule.svg deleted file mode 100644 index 6fa6539167894..0000000000000 --- a/docs/images/tutorial-release-schedule.svg +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - master - - - - - 2.0 - - v2.0.0-beta0 - - v2.0.0 - - - - - 2.1 - - v2.1.0-beta0 - - v2.1.0-beta1 - - v2.1.0 - - - - - 3.0 - - v3.0.0-beta0 - - v3.0.0 - - - - - bug fix - - - - - bug fix - - - - - bug fix - - - - - bug fix - - - - - bug fix - - - - - - feature - - - - feature - - - - feature - - - - - chromiumupdate - - - - ~1 week - - - - ~1 week - - - - ~1 week - - - - \ No newline at end of file diff --git a/docs/images/versioning-sketch-0.png b/docs/images/versioning-sketch-0.png deleted file mode 100644 index 2150b0c1c324a..0000000000000 Binary files a/docs/images/versioning-sketch-0.png and /dev/null differ diff --git a/docs/images/versioning-sketch-1.png b/docs/images/versioning-sketch-1.png deleted file mode 100644 index 4ba2695408719..0000000000000 Binary files a/docs/images/versioning-sketch-1.png and /dev/null differ diff --git a/docs/images/versioning-sketch-2.png b/docs/images/versioning-sketch-2.png deleted file mode 100755 index 81e71bf768422..0000000000000 Binary files a/docs/images/versioning-sketch-2.png and /dev/null differ diff --git a/docs/images/versioning-sketch-3.png b/docs/images/versioning-sketch-3.png deleted file mode 100644 index 6c2ebc4b2cf31..0000000000000 Binary files a/docs/images/versioning-sketch-3.png and /dev/null differ diff --git a/docs/images/versioning-sketch-4.png b/docs/images/versioning-sketch-4.png deleted file mode 100644 index 16236e955107d..0000000000000 Binary files a/docs/images/versioning-sketch-4.png and /dev/null differ diff --git a/docs/images/versioning-sketch-5.png b/docs/images/versioning-sketch-5.png deleted file mode 100644 index 9af531c750bde..0000000000000 Binary files a/docs/images/versioning-sketch-5.png and /dev/null differ diff --git a/docs/images/versioning-sketch-6.png b/docs/images/versioning-sketch-6.png deleted file mode 100644 index 4ede4fd5ab85d..0000000000000 Binary files a/docs/images/versioning-sketch-6.png and /dev/null differ diff --git a/docs/images/versioning-sketch-7.png b/docs/images/versioning-sketch-7.png deleted file mode 100644 index 47c49291d955f..0000000000000 Binary files a/docs/images/versioning-sketch-7.png and /dev/null differ diff --git a/docs/images/viewing-heap-dumps.png b/docs/images/viewing-heap-dumps.png new file mode 100644 index 0000000000000..de4eae135fef0 Binary files /dev/null and b/docs/images/viewing-heap-dumps.png differ diff --git a/docs/images/vs-options-debugging-symbols.png b/docs/images/vs-options-debugging-symbols.png new file mode 100644 index 0000000000000..30ab3961379a9 Binary files /dev/null and b/docs/images/vs-options-debugging-symbols.png differ diff --git a/docs/images/vs-tools-options.png b/docs/images/vs-tools-options.png new file mode 100644 index 0000000000000..4acad752afbd0 Binary files /dev/null and b/docs/images/vs-tools-options.png differ diff --git a/docs/images/web-contents-text-selection-after.png b/docs/images/web-contents-text-selection-after.png new file mode 100644 index 0000000000000..6e57ce8ae0386 Binary files /dev/null and b/docs/images/web-contents-text-selection-after.png differ diff --git a/docs/images/web-contents-text-selection-before.png b/docs/images/web-contents-text-selection-before.png new file mode 100644 index 0000000000000..3609d4b629a94 Binary files /dev/null and b/docs/images/web-contents-text-selection-before.png differ diff --git a/docs/images/windows-progress-bar.png b/docs/images/windows-progress-bar.png new file mode 100644 index 0000000000000..92c261788654b Binary files /dev/null and b/docs/images/windows-progress-bar.png differ diff --git a/docs/images/windows-taskbar-icon-overlay.png b/docs/images/windows-taskbar-icon-overlay.png new file mode 100644 index 0000000000000..fb9a86d530bb1 Binary files /dev/null and b/docs/images/windows-taskbar-icon-overlay.png differ diff --git a/docs/images/windows-taskbar-jumplist.png b/docs/images/windows-taskbar-jumplist.png new file mode 100644 index 0000000000000..7660abcbb1051 Binary files /dev/null and b/docs/images/windows-taskbar-jumplist.png differ diff --git a/docs/images/windows-taskbar-thumbnail-toolbar.png b/docs/images/windows-taskbar-thumbnail-toolbar.png new file mode 100644 index 0000000000000..41a251e8d7b36 Binary files /dev/null and b/docs/images/windows-taskbar-thumbnail-toolbar.png differ diff --git a/docs/styleguide.md b/docs/styleguide.md deleted file mode 100644 index 80f6699b76504..0000000000000 --- a/docs/styleguide.md +++ /dev/null @@ -1,233 +0,0 @@ -# Electron Documentation Style Guide - -These are the guidelines for writing Electron documentation. - -## Titles - -* Each page must have a single `#`-level title at the top. -* Chapters in the same page must have `##`-level titles. -* Sub-chapters need to increase the number of `#` in the title according to - their nesting depth. -* All words in the page's title must be capitalized, except for conjunctions - like "of" and "and" . -* Only the first word of a chapter title must be capitalized. - -Using `Quick Start` as example: - -```markdown -# Quick Start - -... - -## Main process - -... - -## Renderer process - -... - -## Run your app - -... - -### Run as a distribution - -... - -### Manually downloaded Electron binary - -... -``` - -For API references, there are exceptions to this rule. - -## Markdown rules - -* Use `sh` instead of `cmd` in code blocks (due to the syntax highlighter). -* Lines should be wrapped at 80 columns. -* No nesting lists more than 2 levels (due to the markdown renderer). -* All `js` and `javascript` code blocks are linted with -[standard-markdown](https://www.npmjs.com/package/standard-markdown). - -## Picking words - -* Use "will" over "would" when describing outcomes. -* Prefer "in the ___ process" over "on". - -## API references - -The following rules only apply to the documentation of APIs. - -### Page title - -Each page must use the actual object name returned by `require('electron')` -as the title, such as `BrowserWindow`, `autoUpdater`, and `session`. - -Under the page title must be a one-line description starting with `>`. - -Using `session` as example: - -```markdown -# session - -> Manage browser sessions, cookies, cache, proxy settings, etc. -``` - -### Module methods and events - -For modules that are not classes, their methods and events must be listed under -the `## Methods` and `## Events` chapters. - -Using `autoUpdater` as an example: - -```markdown -# autoUpdater - -## Events - -### Event: 'error' - -## Methods - -### `autoUpdater.setFeedURL(url[, requestHeaders])` -``` - -### Classes - -* API classes or classes that are part of modules must be listed under a - `## Class: TheClassName` chapter. -* One page can have multiple classes. -* Constructors must be listed with `###`-level titles. -* [Static Methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/static) must be listed under a `### Static Methods` chapter. -* [Instance Methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#Prototype_methods) must be listed under an `### Instance Methods` chapter. -* All methods that have a return value must start their description with "Returns `[TYPE]` - Return description" - * If the method returns an `Object`, its structure can be specified using a colon followed by a newline then an unordered list of properties in the same style as function parameters. -* Instance Events must be listed under an `### Instance Events` chapter. -* Instance Properties must be listed under an `### Instance Properties` chapter. - * Instance properties must start with "A [Property Type] ..." - -Using the `Session` and `Cookies` classes as an example: - -```markdown -# session - -## Methods - -### session.fromPartition(partition) - -## Static Properties - -### session.defaultSession - -## Class: Session - -### Instance Events - -#### Event: 'will-download' - -### Instance Methods - -#### `ses.getCacheSize()` - -### Instance Properties - -#### `ses.cookies` - -## Class: Cookies - -### Instance Methods - -#### `cookies.get(filter, callback)` -``` - -### Methods - -The methods chapter must be in the following form: - -```markdown -### `objectName.methodName(required[, optional]))` - -* `required` String - A parameter description. -* `optional` Integer (optional) - Another parameter description. - -... -``` - -The title can be `###` or `####`-levels depending on whether it is a method of -a module or a class. - -For modules, the `objectName` is the module's name. For classes, it must be the -name of the instance of the class, and must not be the same as the module's -name. - -For example, the methods of the `Session` class under the `session` module must -use `ses` as the `objectName`. - -The optional arguments are notated by square brackets `[]` surrounding the optional argument -as well as the comma required if this optional argument follows another -argument: - -```sh -required[, optional] -``` - -Below the method is more detailed information on each of the arguments. The type -of argument is notated by either the common types: - -* [`String`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) -* [`Number`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number) -* [`Object`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) -* [`Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) -* [`Boolean`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean) -* Or a custom type like Electron's [`WebContent`](api/web-contents.md) - -If an argument or a method is unique to certain platforms, those platforms are -denoted using a space-delimited italicized list following the datatype. Values -can be `macOS`, `Windows` or `Linux`. - -```markdown -* `animate` Boolean (optional) _macOS_ _Windows_ - Animate the thing. -``` - -`Array` type arguments must specify what elements the array may include in -the description below. - -The description for `Function` type arguments should make it clear how it may be -called and list the types of the parameters that will be passed to it. - -### Events - -The events chapter must be in following form: - -```markdown -### Event: 'wake-up' - -Returns: - -* `time` String - -... -``` - -The title can be `###` or `####`-levels depending on whether it is an event of -a module or a class. - -The arguments of an event follow the same rules as methods. - -### Properties - -The properties chapter must be in following form: - -```markdown -### session.defaultSession - -... -``` - -The title can be `###` or `####`-levels depending on whether it is a property of -a module or a class. - -## Documentation Translations - -See [electron/i18n](https://github.com/electron/i18n#readme) diff --git a/docs/tutorial/accessibility.md b/docs/tutorial/accessibility.md index a2c47d47d13cb..45c13cdc92bd6 100644 --- a/docs/tutorial/accessibility.md +++ b/docs/tutorial/accessibility.md @@ -1,48 +1,7 @@ # Accessibility -Making accessible applications is important and we're happy to provide -functionality to [Devtron][devtron] and [Spectron][spectron] that gives -developers the opportunity to make their apps better for everyone. - ---- - Accessibility concerns in Electron applications are similar to those of -websites because they're both ultimately HTML. With Electron apps, however, -you can't use the online resources for accessibility audits because your app -doesn't have a URL to point the auditor to. - -These features bring those auditing tools to your Electron app. You can -choose to add audits to your tests with Spectron or use them within DevTools -with Devtron. Read on for a summary of the tools. - -## Spectron - -In the testing framework Spectron, you can now audit each window and `` -tag in your application. For example: - -```javascript -app.client.auditAccessibility().then(function (audit) { - if (audit.failed) { - console.error(audit.message) - } -}) -``` - -You can read more about this feature in [Spectron's documentation][spectron-a11y]. - -## Devtron - -In Devtron, there is an accessibility tab which will allow you to audit a -page in your app, sort and filter the results. - -![devtron screenshot][devtron-screenshot] - -Both of these tools are using the [Accessibility Developer Tools][a11y-devtools] -library built by Google for Chrome. You can learn more about the accessibility -audit rules this library uses on that [repository's wiki][a11y-devtools-wiki]. - -If you know of other great accessibility tools for Electron, add them to the -accessibility documentation with a pull request. +websites because they're both ultimately HTML. ## Manually enabling accessibility features @@ -69,6 +28,8 @@ On macOS, third-party assistive technology can toggle accessibility features ins Electron applications by setting the `AXManualAccessibility` attribute programmatically: +Using Objective-C: + ```objc CFStringRef kAXManualAccessibility = CFSTR("AXManualAccessibility"); @@ -84,11 +45,16 @@ CFStringRef kAXManualAccessibility = CFSTR("AXManualAccessibility"); } ``` -[devtron]: https://electronjs.org/devtron -[devtron-screenshot]: https://cloud.githubusercontent.com/assets/1305617/17156618/9f9bcd72-533f-11e6-880d-389115f40a2a.png -[spectron]: https://electronjs.org/spectron -[spectron-a11y]: https://github.com/electron/spectron#accessibility-testing +Using Swift: + +```swift +import Cocoa +let name = CommandLine.arguments.count >= 2 ? CommandLine.arguments[1] : "Electron" +let pid = NSWorkspace.shared.runningApplications.first(where: {$0.localizedName == name})!.processIdentifier +let axApp = AXUIElementCreateApplication(pid) +let result = AXUIElementSetAttributeValue(axApp, "AXManualAccessibility" as CFString, true as CFTypeRef) +print("Setting 'AXManualAccessibility' \(error.rawValue == 0 ? "succeeded" : "failed")") +``` + [a11y-docs]: https://www.chromium.org/developers/design-documents/accessibility#TOC-How-Chrome-detects-the-presence-of-Assistive-Technology -[a11y-devtools]: https://github.com/GoogleChrome/accessibility-developer-tools -[a11y-devtools-wiki]: https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules [setAccessibilitySupportEnabled]: ../api/app.md#appsetaccessibilitysupportenabledenabled-macos-windows diff --git a/docs/tutorial/application-debugging.md b/docs/tutorial/application-debugging.md index 0f4315632821c..1de789c249015 100644 --- a/docs/tutorial/application-debugging.md +++ b/docs/tutorial/application-debugging.md @@ -12,7 +12,7 @@ including instances of `BrowserWindow`, `BrowserView`, and `WebView`. You can open them programmatically by calling the `openDevTools()` API on the `webContents` of the instance: -```javascript +```js const { BrowserWindow } = require('electron') const win = new BrowserWindow() @@ -26,8 +26,8 @@ of the most powerful utilities in any Electron Developer's tool belt. ## Main Process Debugging the main process is a bit trickier, since you cannot open -developer tools for them. The Chromium Developer Tools can [be used -to debug Electron's main process][node-inspect] thanks to a closer collaboration +developer tools for them. The Chromium Developer Tools can +[be used to debug Electron's main process][node-inspect] thanks to a closer collaboration between Google / Chrome and Node.js, but you might encounter oddities like `require` not being present in the console. @@ -43,6 +43,6 @@ If the V8 context crashes, the DevTools will display this message. `DevTools was disconnected from the page. Once page is reloaded, DevTools will automatically reconnect.` -Chromium logs can be enabled via the `ELECTRON_ENABLE_LOGGING` environment variable. For more information, see the [environment variables documentation](https://www.electronjs.org/docs/api/environment-variables#electron_enable_logging). +Chromium logs can be enabled via the `ELECTRON_ENABLE_LOGGING` environment variable. For more information, see the [environment variables documentation](../api/environment-variables.md#electron_enable_logging). -Alternatively, the command line argument `--enable-logging` can be passed. More information is available in the [command line switches documentation](https://www.electronjs.org/docs/api/command-line-switches#--enable-logging). +Alternatively, the command line argument `--enable-logging` can be passed. More information is available in the [command line switches documentation](../api/command-line-switches.md#--enable-loggingfile). diff --git a/docs/tutorial/application-distribution.md b/docs/tutorial/application-distribution.md index b74f6a1956ebc..734aad1cd961d 100644 --- a/docs/tutorial/application-distribution.md +++ b/docs/tutorial/application-distribution.md @@ -1,163 +1,124 @@ -# Application Distribution +--- +title: 'Application Packaging' +description: 'To distribute your app with Electron, you need to package and rebrand it. To do this, you can either use specialized tooling or manual approaches.' +slug: application-distribution +hide_title: false +--- -To distribute your app with Electron, you need to package and rebrand it. The easiest way to do this is to use one of the following third party packaging tools: +To distribute your app with Electron, you need to package and rebrand it. To do this, you +can either use specialized tooling or manual approaches. -* [electron-forge](https://github.com/electron-userland/electron-forge) -* [electron-builder](https://github.com/electron-userland/electron-builder) -* [electron-packager](https://github.com/electron/electron-packager) +## With tooling -These tools will take care of all the steps you need to take to end up with a distributable Electron applications, such as packaging your application, rebranding the executable, setting the right icons and optionally creating installers. +There are a couple tools out there that exist to package and distribute your Electron app. +We recommend using [Electron Forge](./forge-overview.md). You can check out +its [documentation](https://www.electronforge.io) directly, or refer to the [Packaging and Distribution](./tutorial-5-packaging.md) +part of the Electron tutorial. -## Manual distribution +## Manual packaging -You can also choose to manually get your app ready for distribution. The steps needed to do this are outlined below. +If you prefer the manual approach, there are 2 ways to distribute your application: -To distribute your app with Electron, you need to download Electron's [prebuilt -binaries](https://github.com/electron/electron/releases). Next, the folder +- With prebuilt binaries +- With an app source code archive + +### With prebuilt binaries + +To distribute your app manually, you need to download Electron's +[prebuilt binaries](https://github.com/electron/electron/releases). Next, the folder containing your app should be named `app` and placed in Electron's resources -directory as shown in the following examples. Note that the location of -Electron's prebuilt binaries is indicated with `electron/` in the examples -below. +directory as shown in the following examples. -On macOS: +:::note +The location of Electron's prebuilt binaries is indicated +with `electron/` in the examples below. +::: -```plaintext +```plain title='macOS' electron/Electron.app/Contents/Resources/app/ ├── package.json ├── main.js └── index.html ``` -On Windows and Linux: - -```plaintext +```plain title='Windows and Linux' electron/resources/app ├── package.json ├── main.js └── index.html ``` -Then execute `Electron.app` (or `electron` on Linux, `electron.exe` on Windows), -and Electron will start as your app. The `electron` directory will then be -your distribution to deliver to final users. +Then execute `Electron.app` on macOS, `electron` on Linux, or `electron.exe` +on Windows, and Electron will start as your app. The `electron` directory +will then be your distribution to deliver to users. -## Packaging Your App into a File +### With an app source code archive (asar) -Apart from shipping your app by copying all of its source files, you can also -package your app into an [asar](https://github.com/electron/asar) archive to avoid -exposing your app's source code to users. +Instead of shipping your app by copying all of its source files, you can +package your app into an [asar][] archive to improve the performance of reading +files on platforms like Windows, if you are not already using a bundler such +as Parcel or Webpack. To use an `asar` archive to replace the `app` folder, you need to rename the archive to `app.asar`, and put it under Electron's resources directory like below, and Electron will then try to read the archive and start from it. -On macOS: - -```plaintext +```plain title='macOS' electron/Electron.app/Contents/Resources/ └── app.asar ``` -On Windows and Linux: - -```plaintext +```plain title='Windows' electron/resources/ └── app.asar ``` -More details can be found in [Application packaging](application-packaging.md). +You can find more details on how to use `asar` in the +[`electron/asar` repository][asar]. -## Rebranding with Downloaded Binaries +### Rebranding with downloaded binaries After bundling your app into Electron, you will want to rebrand Electron before distributing it to users. -### Windows +- **Windows:** You can rename `electron.exe` to any name you like, and edit + its icon and other information with tools like [rcedit](https://github.com/electron/rcedit). +- **Linux:** You can rename the `electron` executable to any name you like. +- **macOS:** You can rename `Electron.app` to any name you want, and you also have to rename + the `CFBundleDisplayName`, `CFBundleIdentifier` and `CFBundleName` fields in the + following files: -You can rename `electron.exe` to any name you like, and edit its icon and other -information with tools like [rcedit](https://github.com/electron/rcedit). + - `Electron.app/Contents/Info.plist` + - `Electron.app/Contents/Frameworks/Electron Helper.app/Contents/Info.plist` -### macOS + You can also rename the helper app to avoid showing `Electron Helper` in the + Activity Monitor, but make sure you have renamed the helper app's executable + file's name. -You can rename `Electron.app` to any name you want, and you also have to rename -the `CFBundleDisplayName`, `CFBundleIdentifier` and `CFBundleName` fields in the -following files: + The structure of a renamed app would be like: -* `Electron.app/Contents/Info.plist` -* `Electron.app/Contents/Frameworks/Electron Helper.app/Contents/Info.plist` - -You can also rename the helper app to avoid showing `Electron Helper` in the -Activity Monitor, but make sure you have renamed the helper app's executable -file's name. - -The structure of a renamed app would be like: - -```plaintext +```plain MyApp.app/Contents ├── Info.plist ├── MacOS/ -│   └── MyApp +│ └── MyApp └── Frameworks/ └── MyApp Helper.app ├── Info.plist └── MacOS/ -    └── MyApp Helper + └── MyApp Helper ``` -### Linux - -You can rename the `electron` executable to any name you like. - -## Rebranding by Rebuilding Electron from Source +:::note -It is also possible to rebrand Electron by changing the product name and +it is also possible to rebrand Electron by changing the product name and building it from source. To do this you need to set the build argument corresponding to the product name (`electron_product_name = "YourProductName"`) in the `args.gn` file and rebuild. -### Creating a Custom Electron Fork - -Creating a custom fork of Electron is almost certainly not something you will -need to do in order to build your app, even for "Production Level" applications. -Using a tool such as `electron-packager` or `electron-forge` will allow you to -"Rebrand" Electron without having to do these steps. - -You need to fork Electron when you have custom C++ code that you have patched -directly into Electron, that either cannot be upstreamed, or has been rejected -from the official version. As maintainers of Electron, we very much would like -to make your scenario work, so please try as hard as you can to get your changes -into the official version of Electron, it will be much much easier on you, and -we appreciate your help. - -#### Creating a Custom Release with surf-build - -1. Install [Surf](https://github.com/surf-build/surf), via npm: - `npm install -g surf-build@latest` - -2. Create a new S3 bucket and create the following empty directory structure: - - ```sh - - electron/ - - symbols/ - - dist/ - ``` - -3. Set the following Environment Variables: - - * `ELECTRON_GITHUB_TOKEN` - a token that can create releases on GitHub - * `ELECTRON_S3_ACCESS_KEY`, `ELECTRON_S3_BUCKET`, `ELECTRON_S3_SECRET_KEY` - - the place where you'll upload Node.js headers as well as symbols - * `ELECTRON_RELEASE` - Set to `true` and the upload part will run, leave unset - and `surf-build` will do CI-type checks, appropriate to run for every - pull request. - * `CI` - Set to `true` or else it will fail - * `GITHUB_TOKEN` - set it to the same as `ELECTRON_GITHUB_TOKEN` - * `SURF_TEMP` - set to `C:\Temp` on Windows to prevent path too long issues - * `TARGET_ARCH` - set to `ia32` or `x64` - -4. In `script/upload.py`, you _must_ set `ELECTRON_REPO` to your fork (`MYORG/electron`), - especially if you are a contributor to Electron proper. +Keep in mind this is not recommended as setting up the environment to compile +from source is not trivial and takes significant time. -5. `surf-build -r https://github.com/MYORG/electron -s YOUR_COMMIT -n 'surf-PLATFORM-ARCH'` +::: -6. Wait a very, very long time for the build to complete. +[asar]: https://github.com/electron/asar diff --git a/docs/tutorial/application-menu.md b/docs/tutorial/application-menu.md new file mode 100644 index 0000000000000..c77e7983ce067 --- /dev/null +++ b/docs/tutorial/application-menu.md @@ -0,0 +1,208 @@ +--- +title: Application Menu +description: Customize the main application menu for your Electron app +slug: application-menu +hide_title: true +--- + +# Application Menu + +Each Electron app has a single top-level application menu. + +* On macOS, this menu is shown in the system [menu bar](https://support.apple.com/en-ca/guide/mac-help/mchlp1446/mac). +* On Windows and Linux, this menu is shown at the top of each [BaseWindow](../api/base-window.md). + +## Building application menus + +The application menu can be set by passing a [Menu](../api/menu.md) instance into the +[`Menu.setApplicationMenu`](../api/menu.md#menusetapplicationmenumenu) static function. + +When building an application menu in Electron, each top-level array menu item **must be a submenu**. + +Electron will set a default menu for your app if this API is never called. Below is an example of +that default menu being created manually using shorthand [`MenuItem` roles](./menus.md#roles). + +```js title='Manually creating the default menu' @ts-expect-error=[107] +const { shell } = require('electron/common') +const { app, Menu } = require('electron/main') + +const isMac = process.platform === 'darwin' +const template = [ + // { role: 'appMenu' } + ...(isMac + ? [{ + label: app.name, + submenu: [ + { role: 'about' }, + { type: 'separator' }, + { role: 'services' }, + { type: 'separator' }, + { role: 'hide' }, + { role: 'hideOthers' }, + { role: 'unhide' }, + { type: 'separator' }, + { role: 'quit' } + ] + }] + : []), + // { role: 'fileMenu' } + { + label: 'File', + submenu: [ + isMac ? { role: 'close' } : { role: 'quit' } + ] + }, + // { role: 'editMenu' } + { + label: 'Edit', + submenu: [ + { role: 'undo' }, + { role: 'redo' }, + { type: 'separator' }, + { role: 'cut' }, + { role: 'copy' }, + { role: 'paste' }, + ...(isMac + ? [ + { role: 'pasteAndMatchStyle' }, + { role: 'delete' }, + { role: 'selectAll' }, + { type: 'separator' }, + { + label: 'Speech', + submenu: [ + { role: 'startSpeaking' }, + { role: 'stopSpeaking' } + ] + } + ] + : [ + { role: 'delete' }, + { type: 'separator' }, + { role: 'selectAll' } + ]) + ] + }, + // { role: 'viewMenu' } + { + label: 'View', + submenu: [ + { role: 'reload' }, + { role: 'forceReload' }, + { role: 'toggleDevTools' }, + { type: 'separator' }, + { role: 'resetZoom' }, + { role: 'zoomIn' }, + { role: 'zoomOut' }, + { type: 'separator' }, + { role: 'togglefullscreen' } + ] + }, + // { role: 'windowMenu' } + { + label: 'Window', + submenu: [ + { role: 'minimize' }, + { role: 'zoom' }, + ...(isMac + ? [ + { type: 'separator' }, + { role: 'front' }, + { type: 'separator' }, + { role: 'window' } + ] + : [ + { role: 'close' } + ]) + ] + }, + { + role: 'help', + submenu: [ + { + label: 'Learn More', + click: async () => { + const { shell } = require('electron') + await shell.openExternal('https://electronjs.org') + } + } + ] + } +] + +const menu = Menu.buildFromTemplate(template) +Menu.setApplicationMenu(menu) +``` + +> [!IMPORTANT] +> On macOS, the first submenu of the application menu will **always** have your application's name +> as its label. In general, you can populate this submenu by conditionally adding a menu item with +> the `appMenu` role. + +> [!TIP] +> For additional descriptions of available roles, see the [`MenuItem` roles](./menus.md#roles) +> section of the general Menus guide. + +### Using standard OS menu roles + +Defining each submenu explicitly can get very verbose. If you want to re-use default submenus +in your app, you can use various submenu-related roles provided by Electron. + +```js title='Using default roles for each submenu' @ts-expect-error=[26] +const { shell } = require('electron/common') +const { app, Menu } = require('electron/main') + +const template = [ + ...(process.platform === 'darwin' + ? [{ role: 'appMenu' }] + : []), + { role: 'fileMenu' }, + { role: 'editMenu' }, + { role: 'viewMenu' }, + { role: 'windowMenu' }, + { + role: 'help', + submenu: [ + { + label: 'Learn More', + click: async () => { + const { shell } = require('electron') + await shell.openExternal('https://electronjs.org') + } + } + ] + } +] + +const menu = Menu.buildFromTemplate(template) +Menu.setApplicationMenu(menu) +``` + +> [!NOTE] +> On macOS, the `help` role defines a top-level Help submenu that has a search bar for +> other menu items. It requires items to be added to its `submenu` to function. + +## Setting window-specific application menus _Linux_ _Windows_ + +Since the root application menu exists on each `BaseWindow` on Windows and Linux, you can override +it with a window-specific `Menu` instance via the [`win.setMenu`](../api/browser-window.md#winsetmenumenu-linux-windows) method. + +```js title='Override a window's menu' +const { BrowserWindow, Menu } = require('electron/main') + +const win = new BrowserWindow() +const menu = Menu.buildFromTemplate([ + { + label: 'my custom menu', + submenu: [ + { role: 'copy' }, + { role: 'paste' } + ] + } +]) +win.setMenu(menu) +``` + +> [!TIP] +> You can remove a specific window's application menu by calling the +> [`win.removeMenu`](../api/base-window.md#winremovemenu-linux-windows) API. diff --git a/docs/tutorial/application-packaging.md b/docs/tutorial/application-packaging.md deleted file mode 100644 index e0c782fe7d1e9..0000000000000 --- a/docs/tutorial/application-packaging.md +++ /dev/null @@ -1,194 +0,0 @@ -# Application Packaging - -To mitigate [issues](https://github.com/joyent/node/issues/6960) around long -path names on Windows, slightly speed up `require` and conceal your source code -from cursory inspection, you can choose to package your app into an [asar][asar] -archive with little changes to your source code. - -Most users will get this feature for free, since it's supported out of the box -by [`electron-packager`][electron-packager], [`electron-forge`][electron-forge], -and [`electron-builder`][electron-builder]. If you are not using any of these -tools, read on. - -## Generating `asar` Archives - -An [asar][asar] archive is a simple tar-like format that concatenates files -into a single file. Electron can read arbitrary files from it without unpacking -the whole file. - -Steps to package your app into an `asar` archive: - -### 1. Install the asar Utility - -```sh -$ npm install -g asar -``` - -### 2. Package with `asar pack` - -```sh -$ asar pack your-app app.asar -``` - -## Using `asar` Archives - -In Electron there are two sets of APIs: Node APIs provided by Node.js and Web -APIs provided by Chromium. Both APIs support reading files from `asar` archives. - -### Node API - -With special patches in Electron, Node APIs like `fs.readFile` and `require` -treat `asar` archives as virtual directories, and the files in it as normal -files in the filesystem. - -For example, suppose we have an `example.asar` archive under `/path/to`: - -```sh -$ asar list /path/to/example.asar -/app.js -/file.txt -/dir/module.js -/static/index.html -/static/main.css -/static/jquery.min.js -``` - -Read a file in the `asar` archive: - -```javascript -const fs = require('fs') -fs.readFileSync('/path/to/example.asar/file.txt') -``` - -List all files under the root of the archive: - -```javascript -const fs = require('fs') -fs.readdirSync('/path/to/example.asar') -``` - -Use a module from the archive: - -```javascript -require('./path/to/example.asar/dir/module.js') -``` - -You can also display a web page in an `asar` archive with `BrowserWindow`: - -```javascript -const { BrowserWindow } = require('electron') -const win = new BrowserWindow() - -win.loadURL('file:///path/to/example.asar/static/index.html') -``` - -### Web API - -In a web page, files in an archive can be requested with the `file:` protocol. -Like the Node API, `asar` archives are treated as directories. - -For example, to get a file with `$.get`: - -```html - -``` - -### Treating an `asar` Archive as a Normal File - -For some cases like verifying the `asar` archive's checksum, we need to read the -content of an `asar` archive as a file. For this purpose you can use the built-in -`original-fs` module which provides original `fs` APIs without `asar` support: - -```javascript -const originalFs = require('original-fs') -originalFs.readFileSync('/path/to/example.asar') -``` - -You can also set `process.noAsar` to `true` to disable the support for `asar` in -the `fs` module: - -```javascript -const fs = require('fs') -process.noAsar = true -fs.readFileSync('/path/to/example.asar') -``` - -## Limitations of the Node API - -Even though we tried hard to make `asar` archives in the Node API work like -directories as much as possible, there are still limitations due to the -low-level nature of the Node API. - -### Archives Are Read-only - -The archives can not be modified so all Node APIs that can modify files will not -work with `asar` archives. - -### Working Directory Can Not Be Set to Directories in Archive - -Though `asar` archives are treated as directories, there are no actual -directories in the filesystem, so you can never set the working directory to -directories in `asar` archives. Passing them as the `cwd` option of some APIs -will also cause errors. - -### Extra Unpacking on Some APIs - -Most `fs` APIs can read a file or get a file's information from `asar` archives -without unpacking, but for some APIs that rely on passing the real file path to -underlying system calls, Electron will extract the needed file into a -temporary file and pass the path of the temporary file to the APIs to make them -work. This adds a little overhead for those APIs. - -APIs that requires extra unpacking are: - -* `child_process.execFile` -* `child_process.execFileSync` -* `fs.open` -* `fs.openSync` -* `process.dlopen` - Used by `require` on native modules - -### Fake Stat Information of `fs.stat` - -The `Stats` object returned by `fs.stat` and its friends on files in `asar` -archives is generated by guessing, because those files do not exist on the -filesystem. So you should not trust the `Stats` object except for getting file -size and checking file type. - -### Executing Binaries Inside `asar` Archive - -There are Node APIs that can execute binaries like `child_process.exec`, -`child_process.spawn` and `child_process.execFile`, but only `execFile` is -supported to execute binaries inside `asar` archive. - -This is because `exec` and `spawn` accept `command` instead of `file` as input, -and `command`s are executed under shell. There is no reliable way to determine -whether a command uses a file in asar archive, and even if we do, we can not be -sure whether we can replace the path in command without side effects. - -## Adding Unpacked Files to `asar` Archives - -As stated above, some Node APIs will unpack the file to the filesystem when -called. Apart from the performance issues, various anti-virus scanners might -be triggered by this behavior. - -As a workaround, you can leave various files unpacked using the `--unpack` option. -In the following example, shared libraries of native Node.js modules will not be -packed: - -```sh -$ asar pack app app.asar --unpack *.node -``` - -After running the command, you will notice that a folder named `app.asar.unpacked` -was created together with the `app.asar` file. It contains the unpacked files -and should be shipped together with the `app.asar` archive. - -[asar]: https://github.com/electron/asar -[electron-packager]: https://github.com/electron/electron-packager -[electron-forge]: https://github.com/electron-userland/electron-forge -[electron-builder]: https://github.com/electron-userland/electron-builder diff --git a/docs/tutorial/asar-archives.md b/docs/tutorial/asar-archives.md new file mode 100644 index 0000000000000..8537e80b2edf7 --- /dev/null +++ b/docs/tutorial/asar-archives.md @@ -0,0 +1,179 @@ +--- +title: ASAR Archives +description: What is ASAR archive and how does it affect the application. +slug: asar-archives +hide_title: false +--- + +After creating an [application distribution](application-distribution.md), the +app's source code is usually bundled into an [ASAR archive](https://github.com/electron/asar), +which is a simple extensive archive format designed for Electron apps. By bundling the app +we can mitigate issues around long path names on Windows, speed up `require` and conceal your source +code from cursory inspection. + +The bundled app runs in a virtual file system and most APIs would just work +normally, but for some cases you might want to work on ASAR archives explicitly +due to a few caveats. + +## Using ASAR Archives + +In Electron there are two sets of APIs: Node APIs provided by Node.js and Web +APIs provided by Chromium. Both APIs support reading files from ASAR archives. + +### Node API + +With special patches in Electron, Node APIs like `fs.readFile` and `require` +treat ASAR archives as virtual directories, and the files in it as normal +files in the filesystem. + +For example, suppose we have an `example.asar` archive under `/path/to`: + +```sh +$ asar list /path/to/example.asar +/app.js +/file.txt +/dir/module.js +/static/index.html +/static/main.css +/static/jquery.min.js +``` + +Read a file in the ASAR archive: + +```js +const fs = require('node:fs') + +fs.readFileSync('/path/to/example.asar/file.txt') +``` + +List all files under the root of the archive: + +```js +const fs = require('node:fs') + +fs.readdirSync('/path/to/example.asar') +``` + +Use a module from the archive: + +```js @ts-nocheck +require('./path/to/example.asar/dir/module.js') +``` + +You can also display a web page in an ASAR archive with `BrowserWindow`: + +```js +const { BrowserWindow } = require('electron') + +const win = new BrowserWindow() + +win.loadURL('file:///path/to/example.asar/static/index.html') +``` + +### Web API + +In a web page, files in an archive can be requested with the `file:` protocol. +Like the Node API, ASAR archives are treated as directories. + +For example, to get a file with `$.get`: + +```html + +``` + +### Treating an ASAR archive as a Normal File + +For some cases like verifying the ASAR archive's checksum, we need to read the +content of an ASAR archive as a file. For this purpose you can use the built-in +`original-fs` module which provides original `fs` APIs without `asar` support: + +```js +const originalFs = require('original-fs') + +originalFs.readFileSync('/path/to/example.asar') +``` + +You can also set `process.noAsar` to `true` to disable the support for `asar` in +the `fs` module: + +```js +const fs = require('node:fs') + +process.noAsar = true +fs.readFileSync('/path/to/example.asar') +``` + +## Limitations of the Node API + +Even though we tried hard to make ASAR archives in the Node API work like +directories as much as possible, there are still limitations due to the +low-level nature of the Node API. + +### Archives Are Read-only + +The archives can not be modified so all Node APIs that can modify files will not +work with ASAR archives. + +### Working Directory Can Not Be Set to Directories in Archive + +Though ASAR archives are treated as directories, there are no actual +directories in the filesystem, so you can never set the working directory to +directories in ASAR archives. Passing them as the `cwd` option of some APIs +will also cause errors. + +### Extra Unpacking on Some APIs + +Most `fs` APIs can read a file or get a file's information from ASAR archives +without unpacking, but for some APIs that rely on passing the real file path to +underlying system calls, Electron will extract the needed file into a +temporary file and pass the path of the temporary file to the APIs to make them +work. This adds a little overhead for those APIs. + +APIs that require extra unpacking are: + +* `child_process.execFile` +* `child_process.execFileSync` +* `fs.open` +* `fs.openSync` +* `process.dlopen` - Used by `require` on native modules + +### Fake Stat Information of `fs.stat` + +The `Stats` object returned by `fs.stat` and its friends on files in `asar` +archives is generated by guessing, because those files do not exist on the +filesystem. So you should not trust the `Stats` object except for getting file +size and checking file type. + +### Executing Binaries Inside ASAR archive + +There are Node APIs that can execute binaries like `child_process.exec`, +`child_process.spawn` and `child_process.execFile`, but only `execFile` is +supported to execute binaries inside ASAR archive. + +This is because `exec` and `spawn` accept `command` instead of `file` as input, +and `command`s are executed under shell. There is no reliable way to determine +whether a command uses a file in asar archive, and even if we do, we can not be +sure whether we can replace the path in command without side effects. + +## Adding Unpacked Files to ASAR archives + +As stated above, some Node APIs will unpack the file to the filesystem when +called. Apart from the performance issues, various anti-virus scanners might +be triggered by this behavior. + +As a workaround, you can leave various files unpacked using the `--unpack` option. +In the following example, shared libraries of native Node.js modules will not be +packed: + +```sh +$ asar pack app app.asar --unpack *.node +``` + +After running the command, you will notice that a folder named `app.asar.unpacked` +was created together with the `app.asar` file. It contains the unpacked files +and should be shipped together with the `app.asar` archive. diff --git a/docs/tutorial/asar-integrity.md b/docs/tutorial/asar-integrity.md new file mode 100644 index 0000000000000..0362ea5427008 --- /dev/null +++ b/docs/tutorial/asar-integrity.md @@ -0,0 +1,135 @@ +--- +title: 'ASAR Integrity' +description: 'An experimental feature that ensures the validity of ASAR contents at runtime.' +slug: asar-integrity +hide_title: false +--- + +ASAR integrity is a security feature that validates the contents of your app's +[ASAR archives](./asar-archives.md) at runtime. + +## Version support + +Currently, ASAR integrity checking is supported on: + +* macOS as of `electron>=16.0.0` +* Windows as of `electron>=30.0.0` + +> [!NOTE] +> ASAR integrity is fully supported in Mac App Store (MAS) builds and is recommended +> as a best practice. While MAS-installed applications have their `Resources/` folder +> protected by the system (owned by root), ASAR integrity still provides an additional +> layer of security. It is especially important if you use Electron's MAS build but +> distribute your app through channels other than the Mac App Store (such as direct +> download), since those installations won't have the system-level read-only protections. + +In order to enable ASAR integrity checking, you also need to ensure that your `app.asar` file +was generated by a version of the `@electron/asar` npm package that supports ASAR integrity. + +Support was introduced in `asar@3.1.0`. Note that this package has since migrated over to `@electron/asar`. +All versions of `@electron/asar` support ASAR integrity. + +## How it works + +Each ASAR archive contains a JSON string header. The header format includes an `integrity` object +that contains a hex encoded hash of the entire archive as well as an array of hex encoded hashes for each +block of `blockSize` bytes. + +```json +{ + "algorithm": "SHA256", + "hash": "...", + "blockSize": 1024, + "blocks": ["...", "..."] +} +``` + +Separately, you need to define a hex encoded hash of the entire ASAR header when packaging your Electron app. + +When ASAR integrity is enabled, your Electron app will verify the header hash of the ASAR archive on runtime. +If no hash is present or if there is a mismatch in the hashes, the app will forcefully terminate. + +## Enabling ASAR integrity in the binary + +ASAR integrity checking is currently disabled by default in Electron and can +be enabled on build time by toggling the `EnableEmbeddedAsarIntegrityValidation` +[Electron fuse](fuses.md). + +When enabling this fuse, you typically also want to enable the `onlyLoadAppFromAsar` fuse. +Otherwise, the validity checking can be bypassed via the Electron app code search path. + +```js @ts-nocheck +const { flipFuses, FuseVersion, FuseV1Options } = require('@electron/fuses') + +flipFuses( + // E.g. /a/b/Foo.app + pathToPackagedApp, + { + version: FuseVersion.V1, + [FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: true, + [FuseV1Options.OnlyLoadAppFromAsar]: true + } +) +``` + +> [!TIP] +> With Electron Forge, you can configure your app's fuses with +> [@electron-forge/plugin-fuses](https://www.electronforge.io/config/plugins/fuses) +> in your Forge configuration file. + +## Providing the header hash + +ASAR integrity validates the contents of the ASAR archive against the header hash that you provide +on package time. The process of providing this packaged hash is different for macOS and Windows. + +### Using Electron tooling + +Electron Forge and Electron Packager do this setup automatically for you with no additional +configuration whenever `asar` is enabled. The minimum required versions for ASAR integrity are: + +* `@electron/packager@18.3.1` +* `@electron/forge@7.4.0` + +### Using other build systems + +#### macOS + +When packaging for macOS, you must populate a valid `ElectronAsarIntegrity` dictionary block +in your packaged app's `Info.plist`. An example is included below. + +```xml title='Info.plist' +ElectronAsarIntegrity + + Resources/app.asar + + algorithm + SHA256 + hash + 9d1f61ea03c4bb62b4416387a521101b81151da0cfbe18c9f8c8b818c5cebfac + + +``` + +Valid `algorithm` values are currently `SHA256` only. The `hash` is a hash of the ASAR header using the given algorithm. +The `@electron/asar` package exposes a `getRawHeader` method whose result can then be hashed to generate this value +(e.g. using the [`node:crypto`](https://nodejs.org/api/crypto.html) module). + +#### Windows + +When packaging for Windows, you must populate a valid [resource](https://learn.microsoft.com/en-us/windows/win32/menurc/resources) +entry of type `Integrity` and name `ElectronAsar`. The value of this resource should be a JSON encoded dictionary +in the form included below: + +```json +[ + { + "file": "resources\\app.asar", + "alg": "sha256", + "value": "9d1f61ea03c4bb62b4416387a521101b81151da0cfbe18c9f8c8b818c5cebfac" + } +] +``` + +> [!NOTE] +> For an implementation example, see [`src/resedit.ts`](https://github.com/electron/packager/blob/main/src/resedit.ts) +> in the Electron Packager code. diff --git a/docs/tutorial/automated-testing-with-a-custom-driver.md b/docs/tutorial/automated-testing-with-a-custom-driver.md deleted file mode 100644 index a5e7920eb3683..0000000000000 --- a/docs/tutorial/automated-testing-with-a-custom-driver.md +++ /dev/null @@ -1,135 +0,0 @@ -# Automated Testing with a Custom Driver - -To write automated tests for your Electron app, you will need a way to "drive" your application. [Spectron](https://electronjs.org/spectron) is a commonly-used solution which lets you emulate user actions via [WebDriver](https://webdriver.io/). However, it's also possible to write your own custom driver using node's builtin IPC-over-STDIO. The benefit of a custom driver is that it tends to require less overhead than Spectron, and lets you expose custom methods to your test suite. - -To create a custom driver, we'll use Node.js' [child_process](https://nodejs.org/api/child_process.html) API. The test suite will spawn the Electron process, then establish a simple messaging protocol: - -```js -const childProcess = require('child_process') -const electronPath = require('electron') - -// spawn the process -const env = { /* ... */ } -const stdio = ['inherit', 'inherit', 'inherit', 'ipc'] -const appProcess = childProcess.spawn(electronPath, ['./app'], { stdio, env }) - -// listen for IPC messages from the app -appProcess.on('message', (msg) => { - // ... -}) - -// send an IPC message to the app -appProcess.send({ my: 'message' }) -``` - -From within the Electron app, you can listen for messages and send replies using the Node.js [process](https://nodejs.org/api/process.html) API: - -```js -// listen for IPC messages from the test suite -process.on('message', (msg) => { - // ... -}) - -// send an IPC message to the test suite -process.send({ my: 'message' }) -``` - -We can now communicate from the test suite to the Electron app using the `appProcess` object. - -For convenience, you may want to wrap `appProcess` in a driver object that provides more high-level functions. Here is an example of how you can do this: - -```js -class TestDriver { - constructor ({ path, args, env }) { - this.rpcCalls = [] - - // start child process - env.APP_TEST_DRIVER = 1 // let the app know it should listen for messages - this.process = childProcess.spawn(path, args, { stdio: ['inherit', 'inherit', 'inherit', 'ipc'], env }) - - // handle rpc responses - this.process.on('message', (message) => { - // pop the handler - const rpcCall = this.rpcCalls[message.msgId] - if (!rpcCall) return - this.rpcCalls[message.msgId] = null - // reject/resolve - if (message.reject) rpcCall.reject(message.reject) - else rpcCall.resolve(message.resolve) - }) - - // wait for ready - this.isReady = this.rpc('isReady').catch((err) => { - console.error('Application failed to start', err) - this.stop() - process.exit(1) - }) - } - - // simple RPC call - // to use: driver.rpc('method', 1, 2, 3).then(...) - async rpc (cmd, ...args) { - // send rpc request - const msgId = this.rpcCalls.length - this.process.send({ msgId, cmd, args }) - return new Promise((resolve, reject) => this.rpcCalls.push({ resolve, reject })) - } - - stop () { - this.process.kill() - } -} -``` - -In the app, you'd need to write a simple handler for the RPC calls: - -```js -if (process.env.APP_TEST_DRIVER) { - process.on('message', onMessage) -} - -async function onMessage ({ msgId, cmd, args }) { - let method = METHODS[cmd] - if (!method) method = () => new Error('Invalid method: ' + cmd) - try { - const resolve = await method(...args) - process.send({ msgId, resolve }) - } catch (err) { - const reject = { - message: err.message, - stack: err.stack, - name: err.name - } - process.send({ msgId, reject }) - } -} - -const METHODS = { - isReady () { - // do any setup needed - return true - } - // define your RPC-able methods here -} -``` - -Then, in your test suite, you can use your test-driver as follows: - -```js -const test = require('ava') -const electronPath = require('electron') - -const app = new TestDriver({ - path: electronPath, - args: ['./app'], - env: { - NODE_ENV: 'test' - } -}) -test.before(async t => { - await app.isReady -}) -test.after.always('cleanup', async t => { - await app.stop() -}) -``` diff --git a/docs/tutorial/automated-testing.md b/docs/tutorial/automated-testing.md new file mode 100644 index 0000000000000..740f79c393618 --- /dev/null +++ b/docs/tutorial/automated-testing.md @@ -0,0 +1,447 @@ +# Automated Testing + +Test automation is an efficient way of validating that your application code works as intended. +While Electron doesn't actively maintain its own testing solution, this guide will go over a couple +ways you can run end-to-end automated tests on your Electron app. + +## Using the WebDriver interface + +From [ChromeDriver - WebDriver for Chrome][chrome-driver]: + +> WebDriver is an open source tool for automated testing of web apps across many +> browsers. It provides capabilities for navigating to web pages, user input, +> JavaScript execution, and more. ChromeDriver is a standalone server which +> implements WebDriver's wire protocol for Chromium. It is being developed by +> members of the Chromium and WebDriver teams. + +There are a few ways that you can set up testing using WebDriver. + +### With WebdriverIO + +[WebdriverIO](https://webdriver.io/) (WDIO) is a test automation framework that provides a +Node.js package for testing with WebDriver. Its ecosystem also includes various plugins +(e.g. reporter and services) that can help you put together your test setup. + +If you already have an existing WebdriverIO setup, it is recommended to update your dependencies and validate your existing configuration with how it is [outlined in the docs](https://webdriver.io/docs/desktop-testing/electron#configuration). + +#### Install the test runner + +If you don't use WebdriverIO in your project yet, you can add it by running the starter toolkit in your project root directory: + +```sh npm2yarn +npm init wdio@latest ./ +``` + +This starts a configuration wizard that helps you put together the right setup, installs all necessary packages, and generates a `wdio.conf.js` configuration file. Make sure to select _"Desktop Testing - of Electron Applications"_ on one of the first questions asking _"What type of testing would you like to do?"_. + +#### Connect WDIO to your Electron app + +After running the configuration wizard, your `wdio.conf.js` should include roughly the following content: + +```js title='wdio.conf.js' @ts-nocheck +export const config = { + // ... + services: ['electron'], + capabilities: [{ + browserName: 'electron', + 'wdio:electronServiceOptions': { + // WebdriverIO can automatically find your bundled application + // if you use Electron Forge or electron-builder, otherwise you + // can define it here, e.g.: + // appBinaryPath: './path/to/bundled/application.exe', + appArgs: ['foo', 'bar=baz'] + } + }] + // ... +} +``` + +#### Write your tests + +Use the [WebdriverIO API](https://webdriver.io/docs/api) to interact with elements on the screen. The framework provides custom "matchers" that make asserting the state of your application easy, e.g.: + +```js @ts-nocheck +import { browser, $, expect } from '@wdio/globals' + +describe('keyboard input', () => { + it('should detect keyboard input', async () => { + await browser.keys(['y', 'o']) + await expect($('keypress-count')).toHaveText('YO') + }) +}) +``` + +Furthermore, WebdriverIO allows you to access Electron APIs to get static information about your application: + +```js @ts-nocheck +import { browser } from '@wdio/globals' + +describe('trigger message modal', async () => { + it('message modal can be triggered from a test', async () => { + await browser.electron.execute( + (electron, param1, param2, param3) => { + const appWindow = electron.BrowserWindow.getFocusedWindow() + electron.dialog.showMessageBox(appWindow, { + message: 'Hello World!', + detail: `${param1} + ${param2} + ${param3} = ${param1 + param2 + param3}` + }) + }, + 1, + 2, + 3 + ) + }) +}) +``` + +#### Run your tests + +To run your tests: + +```sh +$ npx wdio run wdio.conf.js +``` + +WebdriverIO helps launch and shut down the application for you. + +#### More documentation + +Find more documentation on Mocking Electron APIs and other useful resources in the [official WebdriverIO documentation](https://webdriver.io/docs/desktop-testing/electron). + +### With Selenium + +[Selenium](https://www.selenium.dev/) is a web automation framework that +exposes bindings to WebDriver APIs in many languages. Their Node.js bindings +are available under the `selenium-webdriver` package on NPM. + +#### Run a ChromeDriver server + +In order to use Selenium with Electron, you need to download the `electron-chromedriver` +binary, and run it: + +```sh npm2yarn +npm install --save-dev electron-chromedriver +./node_modules/.bin/chromedriver +Starting ChromeDriver (v2.10.291558) on port 9515 +Only local connections are allowed. +``` + +Remember the port number `9515`, which will be used later. + +#### Connect Selenium to ChromeDriver + +Next, install Selenium into your project: + +```sh npm2yarn +npm install --save-dev selenium-webdriver +``` + +Usage of `selenium-webdriver` with Electron is the same as with +normal websites, except that you have to manually specify how to connect +ChromeDriver and where to find the binary of your Electron app: + +```js title='test.js' @ts-expect-error=[1] +const webdriver = require('selenium-webdriver') + +const driver = new webdriver.Builder() + // The "9515" is the port opened by ChromeDriver. + .usingServer('http://localhost:9515') + .withCapabilities({ + 'goog:chromeOptions': { + // Here is the path to your Electron binary. + binary: '/Path-to-Your-App.app/Contents/MacOS/Electron' + } + }) + .forBrowser('chrome') // note: use .forBrowser('electron') for selenium-webdriver <= 3.6.0 + .build() +driver.get('https://www.google.com') +driver.findElement(webdriver.By.name('q')).sendKeys('webdriver') +driver.findElement(webdriver.By.name('btnG')).click() +driver.wait(() => { + return driver.getTitle().then((title) => { + return title === 'webdriver - Google Search' + }) +}, 1000) +driver.quit() +``` + +## Using Playwright + +[Microsoft Playwright](https://playwright.dev) is an end-to-end testing framework built +using browser-specific remote debugging protocols, similar to the [Puppeteer][] headless +Node.js API but geared towards end-to-end testing. Playwright has experimental Electron +support via Electron's support for the [Chrome DevTools Protocol][] (CDP). + +### Install dependencies + +You can install Playwright through your preferred Node.js package manager. It comes with its +own [test runner][playwright-intro], which is built for end-to-end testing: + +```sh npm2yarn +npm install --save-dev @playwright/test +``` + +:::caution Dependencies +This tutorial was written with `@playwright/test@1.52.0`. Check out +[Playwright's releases][playwright-releases] page to learn about +changes that might affect the code below. +::: + +### Write your tests + +Playwright launches your app in development mode through the `_electron.launch` API. +To point this API to your Electron app, you can pass the path to your main process +entry point (here, it is `main.js`). + +```js {5} @ts-nocheck +import { test, _electron as electron } from '@playwright/test' + +test('launch app', async () => { + const electronApp = await electron.launch({ args: ['.'] }) + // close app + await electronApp.close() +}) +``` + +After that, you will have access to an instance of Playwright's `ElectronApp` class. This +is a powerful class that has access to main process modules for example: + +```js {5-10} @ts-nocheck +import { test, _electron as electron } from '@playwright/test' + +test('get isPackaged', async () => { + const electronApp = await electron.launch({ args: ['.'] }) + const isPackaged = await electronApp.evaluate(async ({ app }) => { + // This runs in Electron's main process, parameter here is always + // the result of the require('electron') in the main app script. + return app.isPackaged + }) + console.log(isPackaged) // false (because we're in development mode) + // close app + await electronApp.close() +}) +``` + +It can also create individual [Page][playwright-page] objects from Electron BrowserWindow instances. +For example, to grab the first BrowserWindow and save a screenshot: + +```js {6-7} @ts-nocheck +import { test, _electron as electron } from '@playwright/test' + +test('save screenshot', async () => { + const electronApp = await electron.launch({ args: ['.'] }) + const window = await electronApp.firstWindow() + await window.screenshot({ path: 'intro.png' }) + // close app + await electronApp.close() +}) +``` + +Putting all this together using the Playwright test-runner, let's create an `example.spec.js` +test file with a single test and assertion: + +```js title='example.spec.js' @ts-nocheck +import { test, expect, _electron as electron } from '@playwright/test' + +test('example test', async () => { + const electronApp = await electron.launch({ args: ['.'] }) + const isPackaged = await electronApp.evaluate(async ({ app }) => { + // This runs in Electron's main process, parameter here is always + // the result of the require('electron') in the main app script. + return app.isPackaged + }) + + expect(isPackaged).toBe(false) + + // Wait for the first BrowserWindow to open + // and return its Page object + const window = await electronApp.firstWindow() + await window.screenshot({ path: 'intro.png' }) + + // close app + await electronApp.close() +}) +``` + +Then, run Playwright Test using `npx playwright test`. You should see the test pass in your +console, and have an `intro.png` screenshot on your filesystem. + +```console +☁ $ npx playwright test + +Running 1 test using 1 worker + + ✓ example.spec.js:4:1 › example test (1s) +``` + +:::info +Playwright Test will automatically run any files matching the `.*(test|spec)\.(js|ts|mjs)` regex. +You can customize this match in the [Playwright Test configuration options][playwright-test-config]. +It also works with TypeScript out of the box. +::: + +:::tip Further reading +Check out Playwright's documentation for the full [Electron][playwright-electron] +and [ElectronApplication][playwright-electronapplication] class APIs. +::: + +## Using a custom test driver + +It's also possible to write your own custom driver using Node.js' built-in IPC-over-STDIO. +Custom test drivers require you to write additional app code, but have lower overhead and let you +expose custom methods to your test suite. + +To create a custom driver, we'll use Node.js' [`child_process`](https://nodejs.org/api/child_process.html) API. +The test suite will spawn the Electron process, then establish a simple messaging protocol: + +```js title='testDriver.js' @ts-nocheck +const electronPath = require('electron') + +const childProcess = require('node:child_process') + +// spawn the process +const env = { /* ... */ } +const stdio = ['inherit', 'inherit', 'inherit', 'ipc'] +const appProcess = childProcess.spawn(electronPath, ['./app'], { stdio, env }) + +// listen for IPC messages from the app +appProcess.on('message', (msg) => { + // ... +}) + +// send an IPC message to the app +appProcess.send({ my: 'message' }) +``` + +From within the Electron app, you can listen for messages and send replies using the Node.js +[`process`](https://nodejs.org/api/process.html) API: + +```js title='main.js' +// listen for messages from the test suite +process.on('message', (msg) => { + // ... +}) + +// send a message to the test suite +process.send({ my: 'message' }) +``` + +We can now communicate from the test suite to the Electron app using the `appProcess` object. + +For convenience, you may want to wrap `appProcess` in a driver object that provides more +high-level functions. Here is an example of how you can do this. Let's start by creating +a `TestDriver` class: + +```js title='testDriver.js' @ts-nocheck +class TestDriver { + constructor ({ path, args, env }) { + this.rpcCalls = [] + + // start child process + env.APP_TEST_DRIVER = 1 // let the app know it should listen for messages + this.process = childProcess.spawn(path, args, { stdio: ['inherit', 'inherit', 'inherit', 'ipc'], env }) + + // handle rpc responses + this.process.on('message', (message) => { + // pop the handler + const rpcCall = this.rpcCalls[message.msgId] + if (!rpcCall) return + this.rpcCalls[message.msgId] = null + // reject/resolve + if (message.reject) rpcCall.reject(message.reject) + else rpcCall.resolve(message.resolve) + }) + + // wait for ready + this.isReady = this.rpc('isReady').catch((err) => { + console.error('Application failed to start', err) + this.stop() + process.exit(1) + }) + } + + // simple RPC call + // to use: driver.rpc('method', 1, 2, 3).then(...) + async rpc (cmd, ...args) { + // send rpc request + const msgId = this.rpcCalls.length + this.process.send({ msgId, cmd, args }) + return new Promise((resolve, reject) => this.rpcCalls.push({ resolve, reject })) + } + + stop () { + this.process.kill() + } +} + +module.exports = { TestDriver } +``` + +In your app code, you can then write a simple handler to receive RPC calls: + +```js title='main.js' +const METHODS = { + isReady () { + // do any setup needed + return true + } + // define your RPC-able methods here +} + +const onMessage = async ({ msgId, cmd, args }) => { + let method = METHODS[cmd] + if (!method) method = () => new Error('Invalid method: ' + cmd) + try { + const resolve = await method(...args) + process.send({ msgId, resolve }) + } catch (err) { + const reject = { + message: err.message, + stack: err.stack, + name: err.name + } + process.send({ msgId, reject }) + } +} + +if (process.env.APP_TEST_DRIVER) { + process.on('message', onMessage) +} +``` + +Then, in your test suite, you can use your `TestDriver` class with the test automation +framework of your choosing. The following example uses +[`ava`](https://www.npmjs.com/package/ava), but other popular choices like Jest +or Mocha would work as well: + +```js title='test.js' @ts-nocheck +const electronPath = require('electron') + +const test = require('ava') + +const { TestDriver } = require('./testDriver') + +const app = new TestDriver({ + path: electronPath, + args: ['./app'], + env: { + NODE_ENV: 'test' + } +}) +test.before(async t => { + await app.isReady +}) +test.after.always('cleanup', async t => { + await app.stop() +}) +``` + +[chrome-driver]: https://sites.google.com/chromium.org/driver/ +[Puppeteer]: https://github.com/puppeteer/puppeteer +[playwright-intro]: https://playwright.dev/docs/intro +[playwright-electron]: https://playwright.dev/docs/api/class-electron/ +[playwright-electronapplication]: https://playwright.dev/docs/api/class-electronapplication +[playwright-page]: https://playwright.dev/docs/api/class-page +[playwright-releases]: https://playwright.dev/docs/release-notes +[playwright-test-config]: https://playwright.dev/docs/api/class-testconfig#test-config-test-match +[Chrome DevTools Protocol]: https://chromedevtools.github.io/devtools-protocol/ diff --git a/docs/tutorial/boilerplates-and-clis.md b/docs/tutorial/boilerplates-and-clis.md index 304254285180e..254f8887cb9ba 100644 --- a/docs/tutorial/boilerplates-and-clis.md +++ b/docs/tutorial/boilerplates-and-clis.md @@ -21,18 +21,16 @@ can clone and customize to your heart's content. A command line tool on the other hand continues to support you throughout the development and release. They are more helpful and supportive but enforce -guidelines on how your code should be structured and built. *Especially for -beginners, using a command line tool is likely to be helpful*. +guidelines on how your code should be structured and built. _Especially for +beginners, using a command line tool is likely to be helpful_. -## electron-forge +## Electron Forge -A "complete tool for building modern Electron applications". Electron Forge -unifies the existing (and well maintained) build tools for Electron development -into a cohesive package so that anyone can jump right in to Electron -development. +Electron Forge is a tool for packaging and publishing Electron applications. It unifies Electron's tooling ecosystem +into a single extensible interface so that anyone can jump right into making Electron apps. Forge comes with [a ready-to-use template](https://electronforge.io/templates) using Webpack as a bundler. It includes an example typescript configuration and provides two configuration files to enable easy customization. It uses the same core modules used by the -greater Electron community (like [`electron-packager`](https://github.com/electron/electron-packager)) – +greater Electron community (like [`@electron/packager`](https://github.com/electron/packager)) – changes made by Electron maintainers (like Slack) benefit Forge's users, too. You can find more information and documentation on [electronforge.io](https://electronforge.io/). @@ -54,7 +52,7 @@ You can find more information and documentation in [the repository](https://gith ## electron-react-boilerplate If you don't want any tools but only a solid boilerplate to build from, -CT Lin's [`electron-react-boilerplate`](https://github.com/chentsulin/electron-react-boilerplate) might be worth +CT Lin's [`electron-react-boilerplate`](https://github.com/electron-react-boilerplate/electron-react-boilerplate) might be worth a look. It's quite popular in the community and uses `electron-builder` internally. diff --git a/docs/tutorial/code-signing.md b/docs/tutorial/code-signing.md index e869416d3515e..18ed03beffb0e 100644 --- a/docs/tutorial/code-signing.md +++ b/docs/tutorial/code-signing.md @@ -1,219 +1,285 @@ -# Code Signing +--- +title: 'Code Signing' +description: 'Code signing is a security technology that you use to certify that an app was created by you.' +slug: code-signing +hide_title: false +--- -Code signing is a security technology that you use to certify that an app was -created by you. +Code signing is a security technology to certify that an app was created by you. +You should sign your application so it does not trigger any operating system +security warnings. -On macOS the system can detect any change to the app, whether the change is -introduced accidentally or by malicious code. +![macOS Sonoma Gatekeeper warning: The app is damaged](../images/gatekeeper.png) -On Windows, the system assigns a trust level to your code signing certificate -which if you don't have, or if your trust level is low, will cause security -dialogs to appear when users start using your application. Trust level builds -over time so it's better to start code signing as early as possible. - -While it is possible to distribute unsigned apps, it is not recommended. Both -Windows and macOS will, by default, prevent either the download or the execution -of unsigned applications. Starting with macOS Catalina (version 10.15), users -have to go through multiple manual steps to open unsigned applications. - -![macOS Catalina Gatekeeper warning: The app cannot be opened because the -developer cannot be verified](../images/gatekeeper.png) - -As you can see, users get two options: Move the app straight to the trash or -cancel running it. You don't want your users to see that dialog. +Both Windows and macOS prevent users from running unsigned applications. It is +possible to distribute applications without codesigning them - but in order to +run them, users need to go through multiple advanced and manual steps. If you are building an Electron app that you intend to package and distribute, -it should be code-signed. +it should be code signed. The Electron ecosystem tooling makes codesigning your +apps straightforward - this documentation explains how to sign your apps on both +Windows and macOS. -# Signing & notarizing macOS builds +## Signing & notarizing macOS builds -Properly preparing macOS applications for release requires two steps: First, the -app needs to be code-signed. Then, the app needs to be uploaded to Apple for a -process called "notarization", where automated systems will further verify that +Preparing macOS applications for release requires two steps: First, the +app needs to be code signed. Then, the app needs to be uploaded to Apple for a +process called **notarization**, where automated systems will further verify that your app isn't doing anything to endanger its users. To start the process, ensure that you fulfill the requirements for signing and notarizing your app: -1. Enroll in the [Apple Developer Program] (requires an annual fee) -2. Download and install [Xcode] - this requires a computer running macOS -3. Generate, download, and install [signing certificates] +1. Enroll in the [Apple Developer Program][] (requires an annual fee) +2. Download and install [Xcode][] - this requires a computer running macOS +3. Generate, download, and install [signing certificates][] Electron's ecosystem favors configuration and freedom, so there are multiple ways to get your application signed and notarized. -## `electron-forge` +### Using Electron Forge If you're using Electron's favorite build tool, getting your application signed and notarized requires a few additions to your configuration. [Forge](https://electronforge.io) is a -collection of the official Electron tools, using [`electron-packager`], -[`electron-osx-sign`], and [`electron-notarize`] under the hood. - -Let's take a look at an example configuration with all required fields. Not all -of them are required: the tools will be clever enough to automatically find a -suitable `identity`, for instance, but we recommend that you are explicit. - -```json -{ - "name": "my-app", - "version": "0.0.1", - "config": { - "forge": { - "packagerConfig": { - "osxSign": { - "identity": "Developer ID Application: Felix Rieseberg (LT94ZKYDCJ)", - "hardened-runtime": true, - "entitlements": "entitlements.plist", - "entitlements-inherit": "entitlements.plist", - "signature-flags": "library" - }, - "osxNotarize": { - "appleId": "felix@felix.fun", - "appleIdPassword": "my-apple-id-password", - } - } - } +collection of the official Electron tools, using [`@electron/packager`][], +[`@electron/osx-sign`][], and [`@electron/notarize`][] under the hood. + +Detailed instructions on how to configure your application can be found in the +[Signing macOS Apps](https://www.electronforge.io/guides/code-signing/code-signing-macos) guide in +the Electron Forge docs. + +### Using Electron Packager + +If you're not using an integrated build pipeline like Forge, you +are likely using [`@electron/packager`][], which includes [`@electron/osx-sign`][] and +[`@electron/notarize`][]. + +If you're using Packager's API, you can pass +[in configuration that both signs and notarizes your application](https://electron.github.io/packager/main/modules.html). +If the example below does not meet your needs, please see [`@electron/osx-sign`][] and +[`@electron/notarize`][] for the many possible configuration options. + +```js @ts-nocheck +const packager = require('@electron/packager') + +packager({ + dir: '/path/to/my/app', + osxSign: {}, + osxNotarize: { + appleId: 'felix@felix.fun', + appleIdPassword: 'my-apple-id-password' } -} +}) ``` -The `plist` file referenced here needs the following macOS-specific entitlements -to assure the Apple security mechanisms that your app is doing these things -without meaning any harm: - -```xml - - - - - com.apple.security.cs.allow-jit - - com.apple.security.cs.allow-unsigned-executable-memory - - com.apple.security.cs.debugger - - - -``` +### Signing Mac App Store applications -To see all of this in action, check out Electron Fiddle's source code, -[especially its `electron-forge` configuration -file](https://github.com/electron/fiddle/blob/master/forge.config.js). +See the [Mac App Store Guide][]. -If you plan to access the microphone or camera within your app using Electron's APIs, you'll also -need to add the following entitlements: +## Signing Windows builds -```xml -com.apple.security.device.audio-input - -com.apple.security.device.camera - -``` +### Using traditional certificates -If these are not present in your app's entitlements when you invoke, for example: +Before you can code sign your application, you need to acquire a code signing +certificate. Unlike Apple, Microsoft allows developers to purchase those +certificates on the open market. They are usually sold by the same companies +also offering HTTPS certificates. Prices vary, so it may be worth your time to +shop around. Popular resellers include: -```js -const { systemPreferences } = require('electron') +- [Certum EV code signing certificate](https://shop.certum.eu/data-safety/code-signing-certificates/certum-ev-code-sigining.html) +- [DigiCert EV code signing certificate](https://www.digicert.com/signing/code-signing-certificates) +- [Entrust EV code signing certificate](https://www.entrustdatacard.com/products/digital-signing-certificates/code-signing-certificates) +- [GlobalSign EV code signing certificate](https://www.globalsign.com/en/code-signing-certificate/ev-code-signing-certificates) +- [IdenTrust EV code signing certificate](https://www.identrust.com/digital-certificates/trustid-ev-code-signing) +- [Sectigo (formerly Comodo) EV code signing certificate](https://sectigo.com/ssl-certificates-tls/code-signing) +- [SSL.com EV code signing certificate](https://www.ssl.com/certificates/ev-code-signing/) -const microphone = systemPreferences.askForMediaAccess('microphone') -``` +It is important to call out that since June 2023, Microsoft requires software to +be signed with an "extended validation" certificate, also called an "EV code signing +certificate". In the past, developers could sign software with a simpler and cheaper +certificate called "authenticode code signing certificate" or "software-based OV certificate". +These simpler certificates no longer provide benefits: Windows will treat your app as +completely unsigned and display the equivalent warning dialogs. -Your app may crash. See the Resource Access section in [Hardened Runtime](https://developer.apple.com/documentation/security/hardened_runtime) for more information and entitlements you may need. +The new EV certificates are required to be stored on a hardware storage module +compliant with FIPS 140 Level 2, Common Criteria EAL 4+ or equivalent. In other words, +the certificate cannot be simply downloaded onto a CI infrastructure. In practice, +those storage modules look like fancy USB thumb drives. -## `electron-builder` +Many certificate providers now offer "cloud-based signing" - the entire signing hardware +is in their data center and you can use it to remotely sign code. This approach is +popular with Electron maintainers since it makes signing your applications in CI (like +GitHub Actions, CircleCI, etc) relatively easy. -Electron Builder comes with a custom solution for signing your application. You -can find [its documentation here](https://www.electron.build/code-signing). +At the time of writing, Electron's own apps use [DigiCert KeyLocker](https://docs.digicert.com/en/digicert-keylocker.html), but any provider that provides a command line tool for +signing files will be compatible with Electron's tooling. + +All tools in the Electron ecosystem use [`@electron/windows-sign`][] and typically +expose configuration options through a `windowsSign` property. You can either use it +to sign files directly - or use the same `windowsSign` configuration across Electron +Forge, [`@electron/packager`][], [`electron-winstaller`][], and [`electron-wix-msi`][]. -## `electron-packager` +#### Using Electron Forge -If you're not using an integrated build pipeline like Forge or Builder, you -are likely using [`electron-packager`], which includes [`electron-osx-sign`] and -[`electron-notarize`]. +Electron Forge is the recommended way to sign your app as well as your `Squirrel.Windows` +and `WiX MSI` installers. Detailed instructions on how to configure your application can +be found in the [Electron Forge Code Signing Tutorial](https://www.electronforge.io/guides/code-signing/code-signing-windows). -If you're using Packager's API, you can pass [in configuration that both signs -and notarizes your -application](https://electron.github.io/electron-packager/master/interfaces/electronpackager.options.html). +#### Using Electron Packager -```js -const packager = require('electron-packager') +If you're not using an integrated build pipeline like Forge, you +are likely using [`@electron/packager`][], which includes [`@electron/windows-sign`][]. + +If you're using Packager's API, you can pass +[in configuration that signs your application](https://electron.github.io/packager/main/modules.html). +If the example below does not meet your needs, please see [`@electron/windows-sign`][] +for the many possible configuration options. + +```js @ts-nocheck +const packager = require('@electron/packager') packager({ dir: '/path/to/my/app', - osxSign: { - identity: 'Developer ID Application: Felix Rieseberg (LT94ZKYDCJ)', - 'hardened-runtime': true, - entitlements: 'entitlements.plist', - 'entitlements-inherit': 'entitlements.plist', - 'signature-flags': 'library' - }, - osxNotarize: { - appleId: 'felix@felix.fun', - appleIdPassword: 'my-apple-id-password' + windowsSign: { + signWithParams: '--my=custom --parameters', + // If signtool.exe does not work for you, customize! + signToolPath: 'C:\\Path\\To\\my-custom-tool.exe' } }) ``` -The `plist` file referenced here needs the following macOS-specific entitlements -to assure the Apple security mechanisms that your app is doing these things -without meaning any harm: - -```xml - - - - - com.apple.security.cs.allow-jit - - com.apple.security.cs.allow-unsigned-executable-memory - - com.apple.security.cs.debugger - - - +#### Using electron-winstaller (Squirrel.Windows) + +[`electron-winstaller`][] is a package that can generate Squirrel.Windows installers for your +Electron app. This is the tool used under the hood by Electron Forge's +[Squirrel.Windows Maker][maker-squirrel]. Just like `@electron/packager`, it uses +[`@electron/windows-sign`][] under the hood and supports the same `windowsSign` +options. + +```js {10-11} @ts-nocheck +const electronInstaller = require('electron-winstaller') +// NB: Use this syntax within an async function, Node does not have support for +// top-level await as of Node 12. +try { + await electronInstaller.createWindowsInstaller({ + appDirectory: '/tmp/build/my-app-64', + outputDirectory: '/tmp/build/installer64', + authors: 'My App Inc.', + exe: 'myapp.exe', + windowsSign: { + signWithParams: '--my=custom --parameters', + // If signtool.exe does not work for you, customize! + signToolPath: 'C:\\Path\\To\\my-custom-tool.exe' + } + }) + console.log('It worked!') +} catch (e) { + console.log(`No dice: ${e.message}`) +} +``` + +For full configuration options, check out the [`electron-winstaller`][] repository! + +#### Using electron-wix-msi (WiX MSI) + +[`electron-wix-msi`][] is a package that can generate MSI installers for your +Electron app. This is the tool used under the hood by Electron Forge's [MSI Maker][maker-msi]. +Just like `@electron/packager`, it uses [`@electron/windows-sign`][] under the hood +and supports the same `windowsSign` options. + +```js {12-13} @ts-nocheck +import { MSICreator } from 'electron-wix-msi' + +// Step 1: Instantiate the MSICreator +const msiCreator = new MSICreator({ + appDirectory: '/path/to/built/app', + description: 'My amazing Kitten simulator', + exe: 'kittens', + name: 'Kittens', + manufacturer: 'Kitten Technologies', + version: '1.1.2', + outputDirectory: '/path/to/output/folder', + windowsSign: { + signWithParams: '--my=custom --parameters', + // If signtool.exe does not work for you, customize! + signToolPath: 'C:\\Path\\To\\my-custom-tool.exe' + } +}) + +// Step 2: Create a .wxs template file +const supportBinaries = await msiCreator.create() + +// 🆕 Step 2a: optionally sign support binaries if you +// sign your binaries as part of your packaging script +for (const binary of supportBinaries) { + // Binaries are the new stub executable and optionally + // the Squirrel auto updater. + await signFile(binary) +} + +// Step 3: Compile the template to a .msi file +await msiCreator.compile() ``` -## Mac App Store +For full configuration options, check out the [`electron-wix-msi`][] repository! -See the [Mac App Store Guide]. +#### Using Electron Builder -# Signing Windows builds +Electron Builder comes with a custom solution for signing your application. You +can find [its documentation here](https://www.electron.build/code-signing). -Before signing Windows builds, you must do the following: +### Using Azure Trusted Signing -1. Get a Windows Authenticode code signing certificate (requires an annual fee) -2. Install Visual Studio to get the signing utility (the free [Community - Edition](https://visualstudio.microsoft.com/vs/community/) is enough) +[Azure Trusted Signing][] is Microsoft's modern cloud-based alternative to EV certificates. +It is the cheapest option for code signing on Windows, and it gets rid of SmartScreen warnings. + +As of October 2025, Azure Trusted Signing is available to US and Canada-based organizations +with 3+ years of verifiable business history and to individual developers in the US and Canada. +Microsoft is looking to make the program more widely available. If you're reading this at a +later point, it could make sense to check if the eligibility criteria have changed. + +#### Using `jsign` for Azure Trusted Signing + +For developers on Linux or macOS, [`jsign`](https://ebourg.github.io/jsign/) can be used to sign Windows apps via Azure Trusted Signing. Example usage: + +```bash +jsign --storetype TRUSTEDSIGNING \ + --keystore https://eus.codesigning.azure.net/ \ + --storepass $AZURE_ACCESS_TOKEN \ + --alias trusted-sign-acct/AppName \ + --tsaurl http://timestamp.acs.microsoft.com/ \ + --tsmode RFC3161 \ + --replace +``` -You can get a code signing certificate from a lot of resellers. Prices vary, so -it may be worth your time to shop around. Popular resellers include: +#### Using Electron Forge -* [digicert](https://www.digicert.com/code-signing/microsoft-authenticode.htm) -* [Comodo](https://www.comodo.com/landing/ssl-certificate/authenticode-signature/) -* [GoDaddy](https://au.godaddy.com/web-security/code-signing-certificate) -* Amongst others, please shop around to find one that suits your needs, Google - is your friend 😄 +Electron Forge is the recommended way to sign your app as well as your `Squirrel.Windows` +and `WiX MSI` installers. Instructions for Azure Trusted Signing can be found +[here][forge-trusted-signing]. -There are a number of tools for signing your packaged app: +#### Using Electron Builder -- [`electron-winstaller`] will generate an installer for windows and sign it for - you -- [`electron-forge`] can sign installers it generates through the - Squirrel.Windows or MSI targets. -- [`electron-builder`] can sign some of its windows targets +The Electron Builder documentation for Azure Trusted Signing can be found +[here][builder-trusted-signing]. -## Windows Store +### Signing Windows Store applications -See the [Windows Store Guide]. +See the [Windows Store Guide][]. -[Apple Developer Program]: https://developer.apple.com/programs/ -[`electron-builder`]: https://github.com/electron-userland/electron-builder -[`electron-forge`]: https://github.com/electron-userland/electron-forge -[`electron-osx-sign`]: https://github.com/electron-userland/electron-osx-sign -[`electron-packager`]: https://github.com/electron/electron-packager -[`electron-notarize`]: https://github.com/electron/electron-notarize +[apple developer program]: https://developer.apple.com/programs/ +[`@electron/osx-sign`]: https://github.com/electron/osx-sign +[`@electron/packager`]: https://github.com/electron/packager +[`@electron/notarize`]: https://github.com/electron/notarize +[`@electron/windows-sign`]: https://github.com/electron/windows-sign [`electron-winstaller`]: https://github.com/electron/windows-installer -[Xcode]: https://developer.apple.com/xcode -[signing certificates]: https://github.com/electron/electron-osx-sign/wiki/1.-Getting-Started#certificates -[Mac App Store Guide]: mac-app-store-submission-guide.md -[Windows Store Guide]: windows-store-guide.md +[`electron-wix-msi`]: https://github.com/electron-userland/electron-wix-msi +[xcode]: https://developer.apple.com/xcode +[signing certificates]: https://developer.apple.com/support/certificates/ +[mac app store guide]: ./mac-app-store-submission-guide.md +[windows store guide]: ./windows-store-guide.md +[maker-squirrel]: https://www.electronforge.io/config/makers/squirrel.windows +[maker-msi]: https://www.electronforge.io/config/makers/wix-msi +[azure trusted signing]: https://azure.microsoft.com/en-us/products/trusted-signing +[forge-trusted-signing]: https://www.electronforge.io/guides/code-signing/code-signing-windows#using-azure-trusted-signing +[builder-trusted-signing]: https://www.electron.build/code-signing-win#using-azure-trusted-signing-beta diff --git a/docs/tutorial/context-isolation.md b/docs/tutorial/context-isolation.md index 1320c1affd26c..389db0cc9fd27 100644 --- a/docs/tutorial/context-isolation.md +++ b/docs/tutorial/context-isolation.md @@ -4,39 +4,38 @@ Context Isolation is a feature that ensures that both your `preload` scripts and Electron's internal logic run in a separate context to the website you load in a [`webContents`](../api/web-contents.md). This is important for security purposes as it helps prevent the website from accessing Electron internals or the powerful APIs your preload script has access to. -This means that the `window` object that your preload script has access to is actually a **different** object than the website would have access to. For example, if you set `window.hello = 'wave'` in your preload script and context isolation is enabled `window.hello` will be undefined if the website tries to access it. +This means that the `window` object that your preload script has access to is actually a **different** object than the website would have access to. For example, if you set `window.hello = 'wave'` in your preload script and context isolation is enabled, `window.hello` will be undefined if the website tries to access it. -Every single application should have context isolation enabled and from Electron 12 it will be enabled by default. - -## How do I enable it? - -From Electron 12, it will be enabled by default. For lower versions it is an option in the `webPreferences` option when constructing `new BrowserWindow`'s. - -```javascript -const mainWindow = new BrowserWindow({ - webPreferences: { - contextIsolation: true - } -}) -``` +Context isolation has been enabled by default since Electron 12, and it is a recommended security setting for _all applications_. ## Migration -> I used to provide APIs from my preload script using `window.X = apiObject` now what? +> Without context isolation, I used to provide APIs from my preload script using `window.X = apiObject`. Now what? -Exposing APIs from your preload script to the loaded website is a common usecase and there is a dedicated module in Electron to help you do this in a painless way. +### Before: context isolation disabled -**Before: With context isolation disabled** +Exposing APIs from your preload script to a loaded website in the renderer process is a common use-case. With context isolation disabled, your preload script would share a common global `window` object with the renderer. You could then attach arbitrary properties to a preload script: -```javascript +```js title='preload.js' @ts-nocheck +// preload with contextIsolation disabled window.myAPI = { doAThing: () => {} } ``` -**After: With context isolation enabled** +The `doAThing()` function could then be used directly in the renderer process: + +```js title='renderer.js' @ts-nocheck +// use the exposed API in the renderer +window.myAPI.doAThing() +``` -```javascript +### After: context isolation enabled + +There is a dedicated module in Electron to help you do this in a painless way. The [`contextBridge`](../api/context-bridge.md) module can be used to **safely** expose APIs from your preload script's isolated context to the context the website is running in. The API will also be accessible from the website on `window.myAPI` just like it was before. + +```js title='preload.js' +// preload with contextIsolation enabled const { contextBridge } = require('electron') contextBridge.exposeInMainWorld('myAPI', { @@ -44,26 +43,63 @@ contextBridge.exposeInMainWorld('myAPI', { }) ``` -The [`contextBridge`](../api/context-bridge.md) module can be used to **safely** expose APIs from the isolated context your preload script runs in to the context the website is running in. The API will also be accessible from the website on `window.myAPI` just like it was before. +```js title='renderer.js' @ts-nocheck +// use the exposed API in the renderer +window.myAPI.doAThing() +``` -You should read the `contextBridge` documentation linked above to fully understand its limitations. For instance you can't send custom prototypes or symbols over the bridge. +Please read the `contextBridge` documentation linked above to fully understand its limitations. For instance, you can't send custom prototypes or symbols over the bridge. -## Security Considerations +## Security considerations -Just enabling `contextIsolation` and using `contextBridge` does not automatically mean that everything you do is safe. For instance this code is **unsafe**. +Just enabling `contextIsolation` and using `contextBridge` does not automatically mean that everything you do is safe. For instance, this code is **unsafe**. -```javascript +```js title='preload.js' // ❌ Bad code contextBridge.exposeInMainWorld('myAPI', { send: ipcRenderer.send }) ``` -It directly exposes a powerful API without any kind of argument filtering. This would allow any website to send arbitrary IPC messages which you do not want to be possible. The correct way to expose IPC-based APIs would instead be to provide one method per IPC message. +It directly exposes a powerful API without any kind of argument filtering. This would allow any website to send arbitrary IPC messages, which you do not want to be possible. The correct way to expose IPC-based APIs would instead be to provide one method per IPC message. -```javascript +```js title='preload.js' // ✅ Good code contextBridge.exposeInMainWorld('myAPI', { loadPreferences: () => ipcRenderer.invoke('load-prefs') }) ``` + +## Usage with TypeScript + +If you're building your Electron app with TypeScript, you'll want to add types to your APIs exposed over the context bridge. The renderer's `window` object won't have the correct typings unless you extend the types with a [declaration file][]. + +For example, given this `preload.ts` script: + +```ts title='preload.ts' +contextBridge.exposeInMainWorld('electronAPI', { + loadPreferences: () => ipcRenderer.invoke('load-prefs') +}) +``` + +You can create a `interface.d.ts` declaration file and globally augment the `Window` interface: + +```ts title='interface.d.ts' @ts-noisolate +export interface IElectronAPI { + loadPreferences: () => Promise, +} + +declare global { + interface Window { + electronAPI: IElectronAPI + } +} +``` + +Doing so will ensure that the TypeScript compiler will know about the `electronAPI` property on your global `window` object when writing scripts in your renderer process: + +```ts title='renderer.ts' +window.electronAPI.loadPreferences() +``` + +[declaration file]: https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html diff --git a/docs/tutorial/context-menu.md b/docs/tutorial/context-menu.md new file mode 100644 index 0000000000000..99563d8ef96ec --- /dev/null +++ b/docs/tutorial/context-menu.md @@ -0,0 +1,69 @@ +--- +title: Context Menu +description: Configure cross-platform native OS menus with the Menu API. +slug: context-menu +hide_title: true +--- + +# Context Menu + +Context menus are pop-up menus that appear when right-clicking (or pressing a shortcut +such as Shift + F10 on Windows) somewhere in an app's interface. + +No context menu will appear by default in Electron. However, context menus can be created by using +the [`menu.popup`](../api/menu.md#menupopupoptions) function on an instance of the +[Menu](../api/menu.md) class. You will need to listen for specific context menu events and set up +the trigger for `menu.popup` manually. + +There are two ways of listening for context menu events in Electron: either via the main process +through [webContents](../api/web-contents.md) or in the renderer process via the +[`contextmenu`](https://developer.mozilla.org/en-US/docs/Web/API/Element/contextmenu_event) web event. + +## Using the `context-menu` event (main) + +Whenever a right-click is detected within the bounds of a specific `WebContents` instance, a +[`context-menu`](../api/web-contents.md#event-context-menu) event is triggered. The `params` object +passed to the listener provides an extensive list of attributes to distinguish which type of element +is receiving the event. + +For example, if you want to provide a context menu for links, check for the `linkURL` parameter. +If you want to check for editable elements such as ` + + + + diff --git a/spec/fixtures/crash-cases/worker-multiple-destroy/index.js b/spec/fixtures/crash-cases/worker-multiple-destroy/index.js new file mode 100644 index 0000000000000..621609b9acdde --- /dev/null +++ b/spec/fixtures/crash-cases/worker-multiple-destroy/index.js @@ -0,0 +1,38 @@ +const { app, BrowserWindow } = require('electron'); + +async function createWindow() { + const mainWindow = new BrowserWindow({ + webPreferences: { + nodeIntegrationInWorker: true + } + }); + + let loads = 1; + mainWindow.webContents.on('did-finish-load', async () => { + if (loads === 2) { + process.exit(0); + } else { + loads++; + await mainWindow.webContents.executeJavaScript('addPaintWorklet()'); + await mainWindow.webContents.executeJavaScript('location.reload()'); + } + }); + + mainWindow.webContents.on('render-process-gone', () => { + process.exit(1); + }); + + await mainWindow.loadFile('index.html'); +} + +app.whenReady().then(() => { + createWindow(); + + app.on('activate', () => { + if (BrowserWindow.getAllWindows().length === 0) createWindow(); + }); +}); + +app.on('window-all-closed', () => { + if (process.platform !== 'darwin') app.quit(); +}); diff --git a/spec/fixtures/crash-cases/worker-multiple-destroy/worklet.js b/spec/fixtures/crash-cases/worker-multiple-destroy/worklet.js new file mode 100644 index 0000000000000..399d47778be21 --- /dev/null +++ b/spec/fixtures/crash-cases/worker-multiple-destroy/worklet.js @@ -0,0 +1,20 @@ +/* global registerPaint */ + +class CheckerboardPainter { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + paint(ctx, geom, properties) { + const colors = ['red', 'green', 'blue']; + const size = 32; + for (let y = 0; y < geom.height / size; y++) { + for (let x = 0; x < geom.width / size; x++) { + const color = colors[(x + y) % colors.length]; + ctx.beginPath(); + ctx.fillStyle = color; + ctx.rect(x * size, y * size, size, size); + ctx.fill(); + } + } + } +} + +registerPaint('checkerboard', CheckerboardPainter); diff --git a/spec/fixtures/crash-cases/wrappable-gc-weak-callback-emit/index.js b/spec/fixtures/crash-cases/wrappable-gc-weak-callback-emit/index.js new file mode 100644 index 0000000000000..c2019251aa908 --- /dev/null +++ b/spec/fixtures/crash-cases/wrappable-gc-weak-callback-emit/index.js @@ -0,0 +1,29 @@ +const { app, WebContentsView } = require('electron'); + +const v8 = require('node:v8'); + +// Force V8 to schedule incremental-marking finalization steps as foreground +// tasks on every allocation. Those tasks run inside V8's +// DisallowJavascriptExecutionScope. Prior to the fix in +// shell/common/gin_helper/wrappable.cc, gin_helper::SecondWeakCallback would +// `delete` the Wrappable synchronously inside that scope, and Wrappables +// whose destructors emit JS events (WebContents emits 'will-destroy' / +// 'destroyed') would crash with "Invoke in DisallowJavascriptExecutionScope". +// +// Regression test for https://github.com/electron/electron/issues/47420. +v8.setFlagsFromString('--stress-incremental-marking'); + +app.whenReady().then(() => { + // Leak several WebContentsView instances so at least one wrapper's + // collection lands in a foreground GC task during app.quit()'s uv_run + // drain. Three is enough for the crash to reproduce 10/10 on a Linux + // testing build before the fix. + // eslint-disable-next-line no-new + new WebContentsView(); + // eslint-disable-next-line no-new + new WebContentsView(); + // eslint-disable-next-line no-new + new WebContentsView(); + + app.quit(); +}); diff --git a/spec-main/fixtures/devtools-extensions/bad-manifest/manifest.json b/spec/fixtures/devtools-extensions/bad-manifest/manifest.json similarity index 100% rename from spec-main/fixtures/devtools-extensions/bad-manifest/manifest.json rename to spec/fixtures/devtools-extensions/bad-manifest/manifest.json diff --git a/spec-main/fixtures/devtools-extensions/foo/_locales/en/messages.json b/spec/fixtures/devtools-extensions/foo/_locales/en/messages.json similarity index 100% rename from spec-main/fixtures/devtools-extensions/foo/_locales/en/messages.json rename to spec/fixtures/devtools-extensions/foo/_locales/en/messages.json diff --git a/spec-main/fixtures/devtools-extensions/foo/devtools.js b/spec/fixtures/devtools-extensions/foo/devtools.js similarity index 100% rename from spec-main/fixtures/devtools-extensions/foo/devtools.js rename to spec/fixtures/devtools-extensions/foo/devtools.js diff --git a/spec-main/fixtures/devtools-extensions/foo/foo.html b/spec/fixtures/devtools-extensions/foo/foo.html similarity index 100% rename from spec-main/fixtures/devtools-extensions/foo/foo.html rename to spec/fixtures/devtools-extensions/foo/foo.html diff --git a/spec-main/fixtures/devtools-extensions/foo/index.html b/spec/fixtures/devtools-extensions/foo/index.html similarity index 100% rename from spec-main/fixtures/devtools-extensions/foo/index.html rename to spec/fixtures/devtools-extensions/foo/index.html diff --git a/spec-main/fixtures/devtools-extensions/foo/manifest.json b/spec/fixtures/devtools-extensions/foo/manifest.json similarity index 100% rename from spec-main/fixtures/devtools-extensions/foo/manifest.json rename to spec/fixtures/devtools-extensions/foo/manifest.json diff --git a/spec/fixtures/devtools-extensions/foo/panel.js b/spec/fixtures/devtools-extensions/foo/panel.js new file mode 100644 index 0000000000000..a64f2aa12b496 --- /dev/null +++ b/spec/fixtures/devtools-extensions/foo/panel.js @@ -0,0 +1,71 @@ +/* global chrome */ +function testStorageClear(callback) { + chrome.storage.sync.clear(function () { + chrome.storage.sync.get(null, function (syncItems) { + chrome.storage.local.clear(function () { + chrome.storage.local.get(null, function (localItems) { + callback(syncItems, localItems); + }); + }); + }); + }); +} + +function testStorageRemove(callback) { + chrome.storage.sync.remove('bar', function () { + chrome.storage.sync.get({ foo: 'baz' }, function (syncItems) { + chrome.storage.local.remove(['hello'], function () { + chrome.storage.local.get(null, function (localItems) { + callback(syncItems, localItems); + }); + }); + }); + }); +} + +function testStorageSet(callback) { + chrome.storage.sync.set({ foo: 'bar', bar: 'foo' }, function () { + chrome.storage.sync.get({ foo: 'baz', bar: 'fooo' }, function (syncItems) { + chrome.storage.local.set({ hello: 'world', world: 'hello' }, function () { + chrome.storage.local.get(null, function (localItems) { + callback(syncItems, localItems); + }); + }); + }); + }); +} + +function testStorage(callback) { + testStorageSet(function (syncForSet, localForSet) { + testStorageRemove(function (syncForRemove, localForRemove) { + testStorageClear(function (syncForClear, localForClear) { + callback(syncForSet, localForSet, syncForRemove, localForRemove, syncForClear, localForClear); + }); + }); + }); +} + +testStorage(function (syncForSet, localForSet, syncForRemove, localForRemove, syncForClear, localForClear) { + setTimeout(() => { + const message = JSON.stringify({ + runtimeId: chrome.runtime.id, + tabId: chrome.devtools.inspectedWindow.tabId, + i18nString: chrome.i18n.getMessage('foo', ['bar', 'baz']), + storageItems: { + local: { + set: localForSet, + remove: localForRemove, + clear: localForClear + }, + sync: { + set: syncForSet, + remove: syncForRemove, + clear: syncForClear + } + } + }); + + const sendMessage = `require('electron').ipcRenderer.send('answer', ${message})`; + window.chrome.devtools.inspectedWindow.eval(sendMessage, function () {}); + }); +}); diff --git a/spec/fixtures/dogs-running.txt b/spec/fixtures/dogs-running.txt new file mode 100644 index 0000000000000..66d80ebc6def2 --- /dev/null +++ b/spec/fixtures/dogs-running.txt @@ -0,0 +1 @@ +Dogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs runningDogs running \ No newline at end of file diff --git a/spec/fixtures/esm/dynamic.mjs b/spec/fixtures/esm/dynamic.mjs new file mode 100644 index 0000000000000..32b6508d70ff7 --- /dev/null +++ b/spec/fixtures/esm/dynamic.mjs @@ -0,0 +1,4 @@ +const { app } = await import('electron'); +const { exitWithApp } = await import('./exit.mjs'); + +exitWithApp(app); diff --git a/spec/fixtures/esm/electron-modules/import-common.mjs b/spec/fixtures/esm/electron-modules/import-common.mjs new file mode 100644 index 0000000000000..65474c0328645 --- /dev/null +++ b/spec/fixtures/esm/electron-modules/import-common.mjs @@ -0,0 +1,8 @@ +process.on('uncaughtException', (err) => { + console.error(err); + process.exit(1); +}); + +const { net } = await import('electron/common'); + +process.exit(net !== undefined ? 0 : 1); diff --git a/spec/fixtures/esm/electron-modules/import-lol.mjs b/spec/fixtures/esm/electron-modules/import-lol.mjs new file mode 100644 index 0000000000000..b6060325b6817 --- /dev/null +++ b/spec/fixtures/esm/electron-modules/import-lol.mjs @@ -0,0 +1,8 @@ +process.on('uncaughtException', (err) => { + console.error(err); + process.exit(1); +}); + +const { net } = await import('electron/lol'); + +process.exit(net !== undefined ? 0 : 1); diff --git a/spec/fixtures/esm/electron-modules/import-main.mjs b/spec/fixtures/esm/electron-modules/import-main.mjs new file mode 100644 index 0000000000000..216b90abdbc2d --- /dev/null +++ b/spec/fixtures/esm/electron-modules/import-main.mjs @@ -0,0 +1,8 @@ +process.on('uncaughtException', (err) => { + console.error(err); + process.exit(1); +}); + +const { net } = await import('electron/main'); + +process.exit(net !== undefined ? 0 : 1); diff --git a/spec/fixtures/esm/electron-modules/import-renderer.mjs b/spec/fixtures/esm/electron-modules/import-renderer.mjs new file mode 100644 index 0000000000000..d85084ddc585f --- /dev/null +++ b/spec/fixtures/esm/electron-modules/import-renderer.mjs @@ -0,0 +1,8 @@ +process.on('uncaughtException', (err) => { + console.error(err); + process.exit(1); +}); + +const { net } = await import('electron/renderer'); + +process.exit(net !== undefined ? 0 : 1); diff --git a/spec/fixtures/esm/electron-modules/import-utility.mjs b/spec/fixtures/esm/electron-modules/import-utility.mjs new file mode 100644 index 0000000000000..b3c429c629b21 --- /dev/null +++ b/spec/fixtures/esm/electron-modules/import-utility.mjs @@ -0,0 +1,8 @@ +process.on('uncaughtException', (err) => { + console.error(err); + process.exit(1); +}); + +const { net } = await import('electron/utility'); + +process.exit(net !== undefined ? 0 : 1); diff --git a/spec/fixtures/esm/empty.html b/spec/fixtures/esm/empty.html new file mode 100644 index 0000000000000..40816a2b5a975 --- /dev/null +++ b/spec/fixtures/esm/empty.html @@ -0,0 +1 @@ +Hi \ No newline at end of file diff --git a/spec/fixtures/esm/entrypoint.mjs b/spec/fixtures/esm/entrypoint.mjs new file mode 100644 index 0000000000000..38617204fb28b --- /dev/null +++ b/spec/fixtures/esm/entrypoint.mjs @@ -0,0 +1,4 @@ +import * as electron from 'electron'; + +console.log('ESM Launch, ready:', electron.app.isReady()); +process.exit(0); diff --git a/spec/fixtures/esm/exit.mjs b/spec/fixtures/esm/exit.mjs new file mode 100644 index 0000000000000..0728e5a943e28 --- /dev/null +++ b/spec/fixtures/esm/exit.mjs @@ -0,0 +1,4 @@ +export function exitWithApp(app) { + console.log('Exit with app, ready:', app.isReady()); + process.exit(0); +} diff --git a/spec/fixtures/esm/import-meta/index.html b/spec/fixtures/esm/import-meta/index.html new file mode 100644 index 0000000000000..6899ed0c0b2ed --- /dev/null +++ b/spec/fixtures/esm/import-meta/index.html @@ -0,0 +1,15 @@ + + + + + + + Hello World! + + +

Hello World!

+ We are using Node.js , + Chromium , + and Electron . + + diff --git a/spec/fixtures/esm/import-meta/main.mjs b/spec/fixtures/esm/import-meta/main.mjs new file mode 100644 index 0000000000000..c853aac8cc6dd --- /dev/null +++ b/spec/fixtures/esm/import-meta/main.mjs @@ -0,0 +1,34 @@ +import { app, BrowserWindow } from 'electron'; + +import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +async function createWindow() { + const mainWindow = new BrowserWindow({ + show: false, + webPreferences: { + preload: fileURLToPath(new URL('preload.mjs', import.meta.url)), + sandbox: false, + contextIsolation: false + } + }); + + await mainWindow.loadFile('index.html'); + + const importMetaPreload = await mainWindow.webContents.executeJavaScript('window.importMetaPath'); + const expected = join(dirname(fileURLToPath(import.meta.url)), 'preload.mjs'); + + process.exit(importMetaPreload === expected ? 0 : 1); +} + +app.whenReady().then(() => { + createWindow(); + + app.on('activate', function () { + if (BrowserWindow.getAllWindows().length === 0) createWindow(); + }); +}); + +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit(); +}); diff --git a/spec/fixtures/esm/import-meta/package.json b/spec/fixtures/esm/import-meta/package.json new file mode 100644 index 0000000000000..13ef5537eb992 --- /dev/null +++ b/spec/fixtures/esm/import-meta/package.json @@ -0,0 +1,4 @@ +{ + "main": "main.mjs", + "type": "module" +} diff --git a/spec/fixtures/esm/import-meta/preload.mjs b/spec/fixtures/esm/import-meta/preload.mjs new file mode 100644 index 0000000000000..365d09c7135fe --- /dev/null +++ b/spec/fixtures/esm/import-meta/preload.mjs @@ -0,0 +1,3 @@ +import { fileURLToPath } from 'node:url'; + +window.importMetaPath = fileURLToPath(import.meta.url); diff --git a/spec/fixtures/esm/local.mjs b/spec/fixtures/esm/local.mjs new file mode 100644 index 0000000000000..7d658310b0d95 --- /dev/null +++ b/spec/fixtures/esm/local.mjs @@ -0,0 +1,3 @@ +export function add(a, b) { + return a + b; +} diff --git a/spec/fixtures/esm/package/index.mjs b/spec/fixtures/esm/package/index.mjs new file mode 100644 index 0000000000000..08c3109ef016a --- /dev/null +++ b/spec/fixtures/esm/package/index.mjs @@ -0,0 +1,4 @@ +import * as electron from 'electron'; + +console.log('ESM Package Launch, ready:', electron.app.isReady()); +process.exit(0); diff --git a/spec/fixtures/esm/package/package.json b/spec/fixtures/esm/package/package.json new file mode 100644 index 0000000000000..84f117c275347 --- /dev/null +++ b/spec/fixtures/esm/package/package.json @@ -0,0 +1,4 @@ +{ + "main": "index.mjs", + "type": "module" +} diff --git a/spec/fixtures/esm/pre-app-ready-apis.mjs b/spec/fixtures/esm/pre-app-ready-apis.mjs new file mode 100644 index 0000000000000..5c815b5c74e9a --- /dev/null +++ b/spec/fixtures/esm/pre-app-ready-apis.mjs @@ -0,0 +1,9 @@ +import * as electron from 'electron'; + +try { + electron.app.disableHardwareAcceleration(); +} catch { + process.exit(1); +} + +process.exit(0); diff --git a/spec/fixtures/esm/top-level-await.mjs b/spec/fixtures/esm/top-level-await.mjs new file mode 100644 index 0000000000000..d18c33fa4560b --- /dev/null +++ b/spec/fixtures/esm/top-level-await.mjs @@ -0,0 +1,7 @@ +import * as electron from 'electron'; + +// Cheeky delay +await new Promise((resolve) => setTimeout(resolve, 500)); + +console.log('Top level await, ready:', electron.app.isReady()); +process.exit(0); diff --git a/spec/fixtures/extensions/chrome-action-fail/background.js b/spec/fixtures/extensions/chrome-action-fail/background.js new file mode 100644 index 0000000000000..d662e230555c8 --- /dev/null +++ b/spec/fixtures/extensions/chrome-action-fail/background.js @@ -0,0 +1,28 @@ +/* global chrome */ + +const handleRequest = async (request, sender, sendResponse) => { + const { method } = request; + const tabId = sender.tab.id; + + switch (method) { + case 'isEnabled': { + chrome.action.isEnabled(tabId).then(sendResponse); + break; + } + + case 'setIcon': { + chrome.action.setIcon({ tabId, imageData: {} }).then(sendResponse); + break; + } + + case 'getBadgeText': { + chrome.action.getBadgeText({ tabId }).then(sendResponse); + break; + } + } +}; + +chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + handleRequest(request, sender, sendResponse); + return true; +}); diff --git a/spec/fixtures/extensions/chrome-action-fail/main.js b/spec/fixtures/extensions/chrome-action-fail/main.js new file mode 100644 index 0000000000000..d050061267f4e --- /dev/null +++ b/spec/fixtures/extensions/chrome-action-fail/main.js @@ -0,0 +1,30 @@ +/* global chrome */ + +chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + sendResponse(request); +}); + +const testMap = { + isEnabled() { + chrome.runtime.sendMessage({ method: 'isEnabled' }, (response) => { + console.log(JSON.stringify(response)); + }); + }, + setIcon() { + chrome.runtime.sendMessage({ method: 'setIcon' }, (response) => { + console.log(JSON.stringify(response)); + }); + }, + getBadgeText() { + chrome.runtime.sendMessage({ method: 'getBadgeText' }, (response) => { + console.log(JSON.stringify(response)); + }); + } +}; + +const dispatchTest = (event) => { + const { method, args = [] } = JSON.parse(event.data); + testMap[method](...args); +}; + +window.addEventListener('message', dispatchTest, false); diff --git a/spec/fixtures/extensions/chrome-action-fail/manifest.json b/spec/fixtures/extensions/chrome-action-fail/manifest.json new file mode 100644 index 0000000000000..d1041d47ac802 --- /dev/null +++ b/spec/fixtures/extensions/chrome-action-fail/manifest.json @@ -0,0 +1,19 @@ +{ + "name": "Action popup demo", + "version": "1.0", + "manifest_version": 3, + "background": { + "service_worker": "background.js" + }, + "content_scripts": [ + { + "matches": [""], + "js": ["main.js"], + "run_at": "document_start" + } + ], + "action": { + "default_title": "Click Me", + "default_popup": "popup.html" + } +} \ No newline at end of file diff --git a/spec/fixtures/extensions/chrome-action-fail/popup.html b/spec/fixtures/extensions/chrome-action-fail/popup.html new file mode 100644 index 0000000000000..d5865f3c0cffd --- /dev/null +++ b/spec/fixtures/extensions/chrome-action-fail/popup.html @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file diff --git a/spec/fixtures/extensions/chrome-api/background.js b/spec/fixtures/extensions/chrome-api/background.js new file mode 100644 index 0000000000000..e3f2129a1bc0a --- /dev/null +++ b/spec/fixtures/extensions/chrome-api/background.js @@ -0,0 +1,34 @@ +/* global chrome */ + +chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { + const { method, args = [] } = message; + const tabId = sender.tab.id; + + switch (method) { + case 'sendMessage': { + const [message] = args; + chrome.tabs.sendMessage(tabId, { message, tabId }, undefined, sendResponse); + break; + } + + case 'executeScript': { + const [code] = args; + chrome.tabs.executeScript(tabId, { code }, ([result]) => sendResponse(result)); + break; + } + + case 'connectTab': { + const [name] = args; + const port = chrome.tabs.connect(tabId, { name }); + port.postMessage('howdy'); + break; + } + + case 'update': { + const [tabId, props] = args; + chrome.tabs.update(tabId, props, sendResponse); + } + } + // Respond asynchronously + return true; +}); diff --git a/spec/fixtures/extensions/chrome-api/main.js b/spec/fixtures/extensions/chrome-api/main.js new file mode 100644 index 0000000000000..007f0d89900f2 --- /dev/null +++ b/spec/fixtures/extensions/chrome-api/main.js @@ -0,0 +1,53 @@ +/* global chrome */ + +chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { + sendResponse(message); +}); + +const testMap = { + connect() { + let success = false; + try { + chrome.runtime.connect(chrome.runtime.id); + chrome.runtime.connect(chrome.runtime.id, { name: 'content-script' }); + chrome.runtime.connect({ name: 'content-script' }); + success = true; + } finally { + console.log(JSON.stringify(success)); + } + }, + getManifest() { + const manifest = chrome.runtime.getManifest(); + console.log(JSON.stringify(manifest)); + }, + sendMessage(message) { + chrome.runtime.sendMessage({ method: 'sendMessage', args: [message] }, (response) => { + console.log(JSON.stringify(response)); + }); + }, + executeScript(code) { + chrome.runtime.sendMessage({ method: 'executeScript', args: [code] }, (response) => { + console.log(JSON.stringify(response)); + }); + }, + connectTab(name) { + chrome.runtime.onConnect.addListener((port) => { + port.onMessage.addListener((message) => { + console.log([port.name, message].join()); + }); + }); + chrome.runtime.sendMessage({ method: 'connectTab', args: [name] }); + }, + update(tabId, props) { + chrome.runtime.sendMessage({ method: 'update', args: [tabId, props] }, (response) => { + console.log(JSON.stringify(response)); + }); + } +}; + +const dispatchTest = (event) => { + const { method, args = [] } = JSON.parse(event.data); + testMap[method](...args); +}; + +window.addEventListener('message', dispatchTest, false); diff --git a/spec-main/fixtures/extensions/chrome-api/manifest.json b/spec/fixtures/extensions/chrome-api/manifest.json similarity index 100% rename from spec-main/fixtures/extensions/chrome-api/manifest.json rename to spec/fixtures/extensions/chrome-api/manifest.json diff --git a/spec/fixtures/extensions/chrome-i18n/v2/_locales/en/messages.json b/spec/fixtures/extensions/chrome-i18n/v2/_locales/en/messages.json new file mode 100644 index 0000000000000..5b784b3e25da8 --- /dev/null +++ b/spec/fixtures/extensions/chrome-i18n/v2/_locales/en/messages.json @@ -0,0 +1,6 @@ +{ + "extName": { + "message": "chrome-i18n", + "description": "Extension name." + } +} diff --git a/spec/fixtures/extensions/chrome-i18n/v2/main.js b/spec/fixtures/extensions/chrome-i18n/v2/main.js new file mode 100644 index 0000000000000..49aabd0b5f862 --- /dev/null +++ b/spec/fixtures/extensions/chrome-i18n/v2/main.js @@ -0,0 +1,33 @@ +/* global chrome */ + +function evalInMainWorld(fn) { + const script = document.createElement('script'); + script.textContent = `((${fn})())`; + document.documentElement.appendChild(script); +} + +async function exec(name) { + let result; + switch (name) { + case 'getMessage': + result = { + id: chrome.i18n.getMessage('@@extension_id'), + name: chrome.i18n.getMessage('extName') + }; + break; + case 'getAcceptLanguages': + result = await new Promise((resolve) => chrome.i18n.getAcceptLanguages(resolve)); + break; + } + + const funcStr = `() => { require('electron').ipcRenderer.send('success', ${JSON.stringify(result)}) }`; + evalInMainWorld(funcStr); +} + +window.addEventListener('message', (event) => { + exec(event.data.name); +}); + +evalInMainWorld(() => { + window.exec = (name) => window.postMessage({ name }); +}); diff --git a/spec-main/fixtures/extensions/chrome-i18n/manifest.json b/spec/fixtures/extensions/chrome-i18n/v2/manifest.json similarity index 100% rename from spec-main/fixtures/extensions/chrome-i18n/manifest.json rename to spec/fixtures/extensions/chrome-i18n/v2/manifest.json diff --git a/spec/fixtures/extensions/chrome-i18n/v3/_locales/es/messages.json b/spec/fixtures/extensions/chrome-i18n/v3/_locales/es/messages.json new file mode 100644 index 0000000000000..088a39cc522d8 --- /dev/null +++ b/spec/fixtures/extensions/chrome-i18n/v3/_locales/es/messages.json @@ -0,0 +1,6 @@ +{ + "extName": { + "message": "Hola mundo!!", + "description": "Nombre de extensión" + } +} \ No newline at end of file diff --git a/spec/fixtures/extensions/chrome-i18n/v3/main.js b/spec/fixtures/extensions/chrome-i18n/v3/main.js new file mode 100644 index 0000000000000..527138954d133 --- /dev/null +++ b/spec/fixtures/extensions/chrome-i18n/v3/main.js @@ -0,0 +1,36 @@ +/* global chrome */ + +chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + sendResponse(request); +}); + +const map = { + getAcceptLanguages() { + chrome.i18n.getAcceptLanguages().then((languages) => { + console.log(JSON.stringify(languages)); + }); + }, + getMessage() { + const message = chrome.i18n.getMessage('extName'); + console.log(JSON.stringify(message)); + }, + getUILanguage() { + const language = chrome.i18n.getUILanguage(); + console.log(JSON.stringify(language)); + }, + async detectLanguage(texts) { + const result = []; + for (const text of texts) { + const language = await chrome.i18n.detectLanguage(text); + result.push(language); + } + console.log(JSON.stringify(result)); + } +}; + +const dispatchTest = (event) => { + const { method, args = [] } = JSON.parse(event.data); + map[method](...args); +}; + +window.addEventListener('message', dispatchTest, false); diff --git a/spec/fixtures/extensions/chrome-i18n/v3/manifest.json b/spec/fixtures/extensions/chrome-i18n/v3/manifest.json new file mode 100644 index 0000000000000..e7ae09d39b405 --- /dev/null +++ b/spec/fixtures/extensions/chrome-i18n/v3/manifest.json @@ -0,0 +1,17 @@ +{ + "name": "chrome-i18n", + "version": "1.0", + "default_locale": "es", + "content_scripts": [ + { + "matches": [ + "" + ], + "js": [ + "main.js" + ], + "run_at": "document_start" + } + ], + "manifest_version": 3 +} diff --git a/spec-main/fixtures/extensions/chrome-runtime/background.js b/spec/fixtures/extensions/chrome-runtime/background.js similarity index 100% rename from spec-main/fixtures/extensions/chrome-runtime/background.js rename to spec/fixtures/extensions/chrome-runtime/background.js diff --git a/spec/fixtures/extensions/chrome-runtime/main.js b/spec/fixtures/extensions/chrome-runtime/main.js new file mode 100644 index 0000000000000..1603d7f75b468 --- /dev/null +++ b/spec/fixtures/extensions/chrome-runtime/main.js @@ -0,0 +1,39 @@ +/* global chrome */ + +function evalInMainWorld(fn) { + const script = document.createElement('script'); + script.textContent = `((${fn})())`; + document.documentElement.appendChild(script); +} + +async function exec(name) { + let result; + switch (name) { + case 'getManifest': + result = chrome.runtime.getManifest(); + break; + case 'id': + result = chrome.runtime.id; + break; + case 'getURL': + result = chrome.runtime.getURL('main.js'); + break; + case 'getPlatformInfo': { + result = await new Promise((resolve) => { + chrome.runtime.sendMessage(name, resolve); + }); + break; + } + } + + const funcStr = `() => { require('electron').ipcRenderer.send('success', ${JSON.stringify(result)}) }`; + evalInMainWorld(funcStr); +} + +window.addEventListener('message', (event) => { + exec(event.data.name); +}); + +evalInMainWorld(() => { + window.exec = (name) => window.postMessage({ name }); +}); diff --git a/spec-main/fixtures/extensions/chrome-runtime/manifest.json b/spec/fixtures/extensions/chrome-runtime/manifest.json similarity index 100% rename from spec-main/fixtures/extensions/chrome-runtime/manifest.json rename to spec/fixtures/extensions/chrome-runtime/manifest.json diff --git a/spec/fixtures/extensions/chrome-scripting/background.js b/spec/fixtures/extensions/chrome-scripting/background.js new file mode 100644 index 0000000000000..f5643d1cfb5d7 --- /dev/null +++ b/spec/fixtures/extensions/chrome-scripting/background.js @@ -0,0 +1,79 @@ +/* global chrome */ + +const handleRequest = async (request, sender, sendResponse) => { + const { method } = request; + const tabId = sender.tab.id; + + switch (method) { + case 'executeScript': { + chrome.scripting + .executeScript({ + target: { tabId }, + function: () => { + document.title = 'HEY HEY HEY'; + return document.title; + } + }) + .then(() => { + console.log('success'); + }) + .catch((err) => { + console.log('error', err); + }); + break; + } + + case 'globalParams': { + await chrome.scripting.executeScript({ + target: { tabId }, + func: () => { + chrome.scripting.globalParams.changed = true; + }, + world: 'ISOLATED' + }); + + const results = await chrome.scripting.executeScript({ + target: { tabId }, + func: () => JSON.stringify(chrome.scripting.globalParams), + world: 'ISOLATED' + }); + + const result = JSON.parse(results[0].result); + + sendResponse(result); + break; + } + + case 'registerContentScripts': { + await chrome.scripting.registerContentScripts([ + { + id: 'session-script', + js: ['content.js'], + persistAcrossSessions: false, + matches: [''], + runAt: 'document_start' + } + ]); + + chrome.scripting.getRegisteredContentScripts().then(sendResponse); + break; + } + + case 'insertCSS': { + chrome.scripting + .insertCSS({ + target: { tabId }, + css: 'body { background-color: red; }' + }) + .then(() => { + sendResponse({ success: true }); + }); + break; + } + } +}; + +chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + handleRequest(request, sender, sendResponse); + return true; +}); diff --git a/docs/fiddles/media/screenshot/.keep b/spec/fixtures/extensions/chrome-scripting/content.js similarity index 100% rename from docs/fiddles/media/screenshot/.keep rename to spec/fixtures/extensions/chrome-scripting/content.js diff --git a/spec/fixtures/extensions/chrome-scripting/main.js b/spec/fixtures/extensions/chrome-scripting/main.js new file mode 100644 index 0000000000000..1265b279aa8c5 --- /dev/null +++ b/spec/fixtures/extensions/chrome-scripting/main.js @@ -0,0 +1,35 @@ +/* global chrome */ + +chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + sendResponse(request); +}); + +const map = { + executeScript() { + chrome.runtime.sendMessage({ method: 'executeScript' }, (response) => { + console.log(JSON.stringify(response)); + }); + }, + registerContentScripts() { + chrome.runtime.sendMessage({ method: 'registerContentScripts' }, (response) => { + console.log(JSON.stringify(response)); + }); + }, + insertCSS() { + chrome.runtime.sendMessage({ method: 'insertCSS' }, (response) => { + console.log(JSON.stringify(response)); + }); + }, + globalParams() { + chrome.runtime.sendMessage({ method: 'globalParams' }, (response) => { + console.log(JSON.stringify(response)); + }); + } +}; + +const dispatchTest = (event) => { + const { method, args = [] } = JSON.parse(event.data); + map[method](...args); +}; + +window.addEventListener('message', dispatchTest, false); diff --git a/spec/fixtures/extensions/chrome-scripting/manifest.json b/spec/fixtures/extensions/chrome-scripting/manifest.json new file mode 100644 index 0000000000000..54620e70b8597 --- /dev/null +++ b/spec/fixtures/extensions/chrome-scripting/manifest.json @@ -0,0 +1,17 @@ +{ + "name": "execute-script", + "version": "1.0", + "permissions": [ + "scripting" + ], + "host_permissions": [""], + "content_scripts": [{ + "matches": [ ""], + "js": ["main.js"], + "run_at": "document_start" + }], + "background": { + "service_worker": "background.js" + }, + "manifest_version": 3 +} \ No newline at end of file diff --git a/spec/fixtures/extensions/chrome-storage/main.js b/spec/fixtures/extensions/chrome-storage/main.js new file mode 100644 index 0000000000000..dbe26e6f0e329 --- /dev/null +++ b/spec/fixtures/extensions/chrome-storage/main.js @@ -0,0 +1,8 @@ +/* global chrome */ +chrome.storage.local.set({ key: 'value' }, () => { + chrome.storage.local.get(['key'], ({ key }) => { + const script = document.createElement('script'); + script.textContent = `require('electron').ipcRenderer.send('storage-success', ${JSON.stringify(key)})`; + document.documentElement.appendChild(script); + }); +}); diff --git a/spec-main/fixtures/extensions/chrome-storage/manifest.json b/spec/fixtures/extensions/chrome-storage/manifest.json similarity index 100% rename from spec-main/fixtures/extensions/chrome-storage/manifest.json rename to spec/fixtures/extensions/chrome-storage/manifest.json diff --git a/spec/fixtures/extensions/chrome-tabs/api-async/background.js b/spec/fixtures/extensions/chrome-tabs/api-async/background.js new file mode 100644 index 0000000000000..5b6a0d1b9e822 --- /dev/null +++ b/spec/fixtures/extensions/chrome-tabs/api-async/background.js @@ -0,0 +1,70 @@ +/* global chrome */ + +const handleRequest = async (request, sender, sendResponse) => { + const { method, args = [] } = request; + const tabId = sender.tab.id; + + switch (method) { + case 'getZoom': { + chrome.tabs.getZoom(tabId).then(sendResponse); + break; + } + + case 'setZoom': { + const [zoom] = args; + chrome.tabs.setZoom(tabId, zoom).then(async () => { + const updatedZoom = await chrome.tabs.getZoom(tabId); + sendResponse(updatedZoom); + }); + break; + } + + case 'getZoomSettings': { + chrome.tabs.getZoomSettings(tabId).then(sendResponse); + break; + } + + case 'setZoomSettings': { + const [settings] = args; + chrome.tabs.setZoomSettings(tabId, { mode: settings.mode }).then(async () => { + const zoomSettings = await chrome.tabs.getZoomSettings(tabId); + sendResponse(zoomSettings); + }); + break; + } + + case 'get': { + chrome.tabs.get(tabId).then(sendResponse); + break; + } + + case 'query': { + const [params] = args; + chrome.tabs.query(params).then(sendResponse); + break; + } + + case 'reload': { + chrome.tabs.reload(tabId).then(() => { + sendResponse({ status: 'reloaded' }); + }); + break; + } + + case 'update': { + const [params] = args; + try { + const response = await chrome.tabs.update(tabId, params); + sendResponse(response); + } catch (error) { + sendResponse({ error: error.message }); + } + break; + } + } +}; + +chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + handleRequest(request, sender, sendResponse); + return true; +}); diff --git a/spec/fixtures/extensions/chrome-tabs/api-async/main.js b/spec/fixtures/extensions/chrome-tabs/api-async/main.js new file mode 100644 index 0000000000000..b65c9614af74f --- /dev/null +++ b/spec/fixtures/extensions/chrome-tabs/api-async/main.js @@ -0,0 +1,55 @@ +/* global chrome */ + +chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + sendResponse(request); +}); + +const testMap = { + getZoomSettings() { + chrome.runtime.sendMessage({ method: 'getZoomSettings' }, (response) => { + console.log(JSON.stringify(response)); + }); + }, + setZoomSettings(settings) { + chrome.runtime.sendMessage({ method: 'setZoomSettings', args: [settings] }, (response) => { + console.log(JSON.stringify(response)); + }); + }, + query(params) { + chrome.runtime.sendMessage({ method: 'query', args: [params] }, (response) => { + console.log(JSON.stringify(response)); + }); + }, + getZoom() { + chrome.runtime.sendMessage({ method: 'getZoom', args: [] }, (response) => { + console.log(JSON.stringify(response)); + }); + }, + setZoom(zoom) { + chrome.runtime.sendMessage({ method: 'setZoom', args: [zoom] }, (response) => { + console.log(JSON.stringify(response)); + }); + }, + get() { + chrome.runtime.sendMessage({ method: 'get' }, (response) => { + console.log(JSON.stringify(response)); + }); + }, + reload() { + chrome.runtime.sendMessage({ method: 'reload' }, (response) => { + console.log(JSON.stringify(response)); + }); + }, + update(params) { + chrome.runtime.sendMessage({ method: 'update', args: [params] }, (response) => { + console.log(JSON.stringify(response)); + }); + } +}; + +const dispatchTest = (event) => { + const { method, args = [] } = JSON.parse(event.data); + testMap[method](...args); +}; + +window.addEventListener('message', dispatchTest, false); diff --git a/spec/fixtures/extensions/chrome-tabs/api-async/manifest.json b/spec/fixtures/extensions/chrome-tabs/api-async/manifest.json new file mode 100644 index 0000000000000..d0a208cd06fcf --- /dev/null +++ b/spec/fixtures/extensions/chrome-tabs/api-async/manifest.json @@ -0,0 +1,16 @@ +{ + "name": "api-async", + "version": "1.0", + "content_scripts": [ + { + "matches": [ ""], + "js": ["main.js"], + "run_at": "document_start" + } + ], + "permissions": ["tabs"], + "background": { + "service_worker": "background.js" + }, + "manifest_version": 3 +} diff --git a/spec/fixtures/extensions/chrome-tabs/no-privileges/background.js b/spec/fixtures/extensions/chrome-tabs/no-privileges/background.js new file mode 100644 index 0000000000000..d586b455a1cc1 --- /dev/null +++ b/spec/fixtures/extensions/chrome-tabs/no-privileges/background.js @@ -0,0 +1,6 @@ +/* global chrome */ + +chrome.runtime.onMessage.addListener((_request, sender, sendResponse) => { + chrome.tabs.get(sender.tab.id).then(sendResponse); + return true; +}); diff --git a/spec/fixtures/extensions/chrome-tabs/no-privileges/main.js b/spec/fixtures/extensions/chrome-tabs/no-privileges/main.js new file mode 100644 index 0000000000000..d3486897b1605 --- /dev/null +++ b/spec/fixtures/extensions/chrome-tabs/no-privileges/main.js @@ -0,0 +1,15 @@ +/* global chrome */ + +chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + sendResponse(request); +}); + +window.addEventListener( + 'message', + () => { + chrome.runtime.sendMessage({}, (response) => { + console.log(JSON.stringify(response)); + }); + }, + false +); diff --git a/spec/fixtures/extensions/chrome-tabs/no-privileges/manifest.json b/spec/fixtures/extensions/chrome-tabs/no-privileges/manifest.json new file mode 100644 index 0000000000000..f920c8bc0e20a --- /dev/null +++ b/spec/fixtures/extensions/chrome-tabs/no-privileges/manifest.json @@ -0,0 +1,19 @@ +{ + "name": "no-privileges", + "version": "1.0", + "content_scripts": [ + { + "matches": [ + "" + ], + "js": [ + "main.js" + ], + "run_at": "document_start" + } + ], + "background": { + "service_worker": "background.js" + }, + "manifest_version": 3 +} \ No newline at end of file diff --git a/spec/fixtures/extensions/chrome-webRequest-wss/background.js b/spec/fixtures/extensions/chrome-webRequest-wss/background.js new file mode 100644 index 0000000000000..80c92dde34290 --- /dev/null +++ b/spec/fixtures/extensions/chrome-webRequest-wss/background.js @@ -0,0 +1,12 @@ +/* global chrome */ + +chrome.webRequest.onBeforeSendHeaders.addListener( + (details) => { + if (details.requestHeaders) { + details.requestHeaders.foo = 'bar'; + } + return { cancel: false, requestHeaders: details.requestHeaders }; + }, + { urls: ['*://127.0.0.1:*/'] }, + ['blocking'] +); diff --git a/spec/fixtures/extensions/chrome-webRequest-wss/manifest.json b/spec/fixtures/extensions/chrome-webRequest-wss/manifest.json new file mode 100644 index 0000000000000..c1723d2118850 --- /dev/null +++ b/spec/fixtures/extensions/chrome-webRequest-wss/manifest.json @@ -0,0 +1,10 @@ +{ + "name": "chrome-webRequest", + "version": "1.0", + "background": { + "scripts": ["background.js"], + "persistent": true + }, + "permissions": ["webRequest", "webRequestBlocking", ""], + "manifest_version": 2 +} diff --git a/spec/fixtures/extensions/chrome-webRequest/background.js b/spec/fixtures/extensions/chrome-webRequest/background.js new file mode 100644 index 0000000000000..fb2d2a472a5f7 --- /dev/null +++ b/spec/fixtures/extensions/chrome-webRequest/background.js @@ -0,0 +1,10 @@ +/* global chrome */ + +chrome.webRequest.onBeforeRequest.addListener( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + (details) => { + return { cancel: true }; + }, + { urls: ['*://127.0.0.1:*/'] }, + ['blocking'] +); diff --git a/spec/fixtures/extensions/chrome-webRequest/manifest.json b/spec/fixtures/extensions/chrome-webRequest/manifest.json new file mode 100644 index 0000000000000..c1723d2118850 --- /dev/null +++ b/spec/fixtures/extensions/chrome-webRequest/manifest.json @@ -0,0 +1,10 @@ +{ + "name": "chrome-webRequest", + "version": "1.0", + "background": { + "scripts": ["background.js"], + "persistent": true + }, + "permissions": ["webRequest", "webRequestBlocking", ""], + "manifest_version": 2 +} diff --git a/spec-main/fixtures/extensions/content-script-document-end/end.js b/spec/fixtures/extensions/content-script-document-end/end.js similarity index 100% rename from spec-main/fixtures/extensions/content-script-document-end/end.js rename to spec/fixtures/extensions/content-script-document-end/end.js diff --git a/spec/fixtures/extensions/content-script-document-end/manifest.json b/spec/fixtures/extensions/content-script-document-end/manifest.json new file mode 100644 index 0000000000000..cd2ce51be9d7b --- /dev/null +++ b/spec/fixtures/extensions/content-script-document-end/manifest.json @@ -0,0 +1,13 @@ +{ + "name": "document-end", + "version": "1.0", + "description": "", + "content_scripts": [ + { + "matches": [""], + "js": ["end.js"], + "run_at": "document_end" + } + ], + "manifest_version": 2 +} diff --git a/spec-main/fixtures/extensions/content-script-document-idle/idle.js b/spec/fixtures/extensions/content-script-document-idle/idle.js similarity index 100% rename from spec-main/fixtures/extensions/content-script-document-idle/idle.js rename to spec/fixtures/extensions/content-script-document-idle/idle.js diff --git a/spec/fixtures/extensions/content-script-document-idle/manifest.json b/spec/fixtures/extensions/content-script-document-idle/manifest.json new file mode 100644 index 0000000000000..bd2bb5fcebca3 --- /dev/null +++ b/spec/fixtures/extensions/content-script-document-idle/manifest.json @@ -0,0 +1,13 @@ +{ + "name": "document-idle", + "version": "1.0", + "description": "", + "content_scripts": [ + { + "matches": [""], + "js": ["idle.js"], + "run_at": "document_idle" + } + ], + "manifest_version": 2 +} diff --git a/spec/fixtures/extensions/content-script-document-start/manifest.json b/spec/fixtures/extensions/content-script-document-start/manifest.json new file mode 100644 index 0000000000000..9b58263d1fe6d --- /dev/null +++ b/spec/fixtures/extensions/content-script-document-start/manifest.json @@ -0,0 +1,13 @@ +{ + "name": "document-start", + "version": "1.0", + "description": "", + "content_scripts": [ + { + "matches": [""], + "js": ["start.js"], + "run_at": "document_start" + } + ], + "manifest_version": 2 +} diff --git a/spec-main/fixtures/extensions/content-script-document-start/start.js b/spec/fixtures/extensions/content-script-document-start/start.js similarity index 100% rename from spec-main/fixtures/extensions/content-script-document-start/start.js rename to spec/fixtures/extensions/content-script-document-start/start.js diff --git a/spec-main/fixtures/extensions/content-script/all_frames-disabled.css b/spec/fixtures/extensions/content-script/all_frames-disabled.css similarity index 100% rename from spec-main/fixtures/extensions/content-script/all_frames-disabled.css rename to spec/fixtures/extensions/content-script/all_frames-disabled.css diff --git a/spec-main/fixtures/extensions/content-script/all_frames-enabled.css b/spec/fixtures/extensions/content-script/all_frames-enabled.css similarity index 100% rename from spec-main/fixtures/extensions/content-script/all_frames-enabled.css rename to spec/fixtures/extensions/content-script/all_frames-enabled.css diff --git a/spec/fixtures/extensions/content-script/all_frames-preload.js b/spec/fixtures/extensions/content-script/all_frames-preload.js new file mode 100644 index 0000000000000..f7d4547864f27 --- /dev/null +++ b/spec/fixtures/extensions/content-script/all_frames-preload.js @@ -0,0 +1,14 @@ +const { ipcRenderer, webFrame } = require('electron'); + +if (process.isMainFrame) { + // https://github.com/electron/electron/issues/17252 + ipcRenderer.on('executeJavaScriptInFrame', (event, frameToken, code, responseId) => { + const frame = webFrame.findFrameByToken(frameToken); + if (!frame) { + throw new Error(`Can't find frame for frame token ${frameToken}`); + } + frame.executeJavaScript(code, false).then((result) => { + event.sender.send(`executeJavaScriptInFrame_${responseId}`, result); + }); + }); +} diff --git a/spec-main/fixtures/extensions/content-script/frame-with-frame.html b/spec/fixtures/extensions/content-script/frame-with-frame.html similarity index 100% rename from spec-main/fixtures/extensions/content-script/frame-with-frame.html rename to spec/fixtures/extensions/content-script/frame-with-frame.html diff --git a/spec-main/fixtures/extensions/content-script/frame.html b/spec/fixtures/extensions/content-script/frame.html similarity index 100% rename from spec-main/fixtures/extensions/content-script/frame.html rename to spec/fixtures/extensions/content-script/frame.html diff --git a/spec-main/fixtures/extensions/content-script/manifest.json b/spec/fixtures/extensions/content-script/manifest.json similarity index 100% rename from spec-main/fixtures/extensions/content-script/manifest.json rename to spec/fixtures/extensions/content-script/manifest.json diff --git a/spec/fixtures/extensions/custom-protocol-panel/extension/devtools.html b/spec/fixtures/extensions/custom-protocol-panel/extension/devtools.html new file mode 100644 index 0000000000000..c70108940c714 --- /dev/null +++ b/spec/fixtures/extensions/custom-protocol-panel/extension/devtools.html @@ -0,0 +1,7 @@ + + + + + + + diff --git a/spec/fixtures/extensions/custom-protocol-panel/extension/devtools.js b/spec/fixtures/extensions/custom-protocol-panel/extension/devtools.js new file mode 100644 index 0000000000000..8083941686a72 --- /dev/null +++ b/spec/fixtures/extensions/custom-protocol-panel/extension/devtools.js @@ -0,0 +1,4 @@ +/* global chrome */ +chrome.devtools.panels.create('ELECTRON TEST PANEL', '', 'panel.html'); + +console.log('ELECTRON TEST PANEL created'); diff --git a/spec/fixtures/extensions/custom-protocol-panel/extension/manifest.json b/spec/fixtures/extensions/custom-protocol-panel/extension/manifest.json new file mode 100644 index 0000000000000..db8f32aab90f9 --- /dev/null +++ b/spec/fixtures/extensions/custom-protocol-panel/extension/manifest.json @@ -0,0 +1,6 @@ +{ + "name": "custom-protocol-panel", + "version": "1.0", + "devtools_page": "devtools.html", + "manifest_version": 3 +} diff --git a/spec/fixtures/extensions/custom-protocol-panel/extension/panel.html b/spec/fixtures/extensions/custom-protocol-panel/extension/panel.html new file mode 100644 index 0000000000000..6c34a03ff9241 --- /dev/null +++ b/spec/fixtures/extensions/custom-protocol-panel/extension/panel.html @@ -0,0 +1,4 @@ + + + DevTools panel + diff --git a/spec/fixtures/extensions/custom-protocol-panel/main.js b/spec/fixtures/extensions/custom-protocol-panel/main.js new file mode 100644 index 0000000000000..184e8d77e4880 --- /dev/null +++ b/spec/fixtures/extensions/custom-protocol-panel/main.js @@ -0,0 +1,45 @@ +const { app, BrowserWindow, protocol, session } = require('electron/main'); + +const { once } = require('node:events'); +const path = require('node:path'); + +const html = '

EMPTY PAGE

'; +const scheme = 'custom'; + +protocol.registerSchemesAsPrivileged([ + { + scheme, + privileges: { + standard: true, + allowExtensions: true + } + } +]); + +app.whenReady().then(async () => { + const ses = session.defaultSession; + + ses.protocol.handle( + scheme, + () => + new Response(html, { + headers: { 'Content-Type': 'text/html' } + }) + ); + + await ses.extensions.loadExtension(path.join(__dirname, 'extension')); + + const win = new BrowserWindow(); + + win.webContents.openDevTools(); + await once(win.webContents, 'devtools-opened'); + + win.devToolsWebContents.on('console-message', ({ message }) => { + if (message === 'ELECTRON TEST PANEL created') { + console.log(message); + app.quit(); + } + }); + + await win.loadURL(`${scheme}://app/`); +}); diff --git a/spec/fixtures/extensions/custom-protocol/extension/background.js b/spec/fixtures/extensions/custom-protocol/extension/background.js new file mode 100644 index 0000000000000..11abd3d99cf3a --- /dev/null +++ b/spec/fixtures/extensions/custom-protocol/extension/background.js @@ -0,0 +1,7 @@ +/* global chrome */ +chrome.runtime.onMessage.addListener((_message, sender, reply) => { + reply({ + text: 'MESSAGE RECEIVED', + senderTabId: sender.tab && sender.tab.id + }); +}); diff --git a/spec/fixtures/extensions/custom-protocol/extension/content_script.js b/spec/fixtures/extensions/custom-protocol/extension/content_script.js new file mode 100644 index 0000000000000..60098e6a689f0 --- /dev/null +++ b/spec/fixtures/extensions/custom-protocol/extension/content_script.js @@ -0,0 +1,5 @@ +/* global chrome */ +chrome.runtime.sendMessage({ text: 'hello from content script' }, (response) => { + if (!response || !response.text) return; + document.title = response.text; +}); diff --git a/spec/fixtures/extensions/custom-protocol/extension/manifest.json b/spec/fixtures/extensions/custom-protocol/extension/manifest.json new file mode 100644 index 0000000000000..25447fec0708c --- /dev/null +++ b/spec/fixtures/extensions/custom-protocol/extension/manifest.json @@ -0,0 +1,15 @@ +{ + "name": "custom-protocol", + "version": "1.0", + "background": { + "service_worker": "background.js" + }, + "content_scripts": [ + { + "matches": [""], + "js": ["content_script.js"], + "run_at": "document_start" + } + ], + "manifest_version": 3 +} diff --git a/spec/fixtures/extensions/custom-protocol/main.js b/spec/fixtures/extensions/custom-protocol/main.js new file mode 100644 index 0000000000000..5c6c803579294 --- /dev/null +++ b/spec/fixtures/extensions/custom-protocol/main.js @@ -0,0 +1,39 @@ +const { app, BrowserWindow, protocol, session } = require('electron/main'); + +const path = require('node:path'); + +const html = '

EMPTY PAGE

'; +const scheme = 'example'; + +protocol.registerSchemesAsPrivileged([ + { + scheme, + privileges: { + standard: true, + allowExtensions: true + } + } +]); + +app.whenReady().then(async () => { + const ses = session.defaultSession; + + ses.protocol.handle( + scheme, + () => + new Response(html, { + headers: { 'Content-Type': 'text/html' } + }) + ); + + await ses.extensions.loadExtension(path.join(__dirname, 'extension')); + + const win = new BrowserWindow(); + + win.on('page-title-updated', (_event, title) => { + console.log(`Title: ${title}`); + app.quit(); + }); + + await win.loadURL(`${scheme}://app/`); +}); diff --git a/spec-main/fixtures/extensions/devtools-extension/foo.html b/spec/fixtures/extensions/devtools-extension/foo.html similarity index 100% rename from spec-main/fixtures/extensions/devtools-extension/foo.html rename to spec/fixtures/extensions/devtools-extension/foo.html diff --git a/spec/fixtures/extensions/devtools-extension/foo.js b/spec/fixtures/extensions/devtools-extension/foo.js new file mode 100644 index 0000000000000..30ba014abc5ca --- /dev/null +++ b/spec/fixtures/extensions/devtools-extension/foo.js @@ -0,0 +1,2 @@ +/* global chrome */ +chrome.devtools.panels.create('Foo', 'icon.png', 'index.html'); diff --git a/spec-main/fixtures/extensions/devtools-extension/index.html b/spec/fixtures/extensions/devtools-extension/index.html similarity index 100% rename from spec-main/fixtures/extensions/devtools-extension/index.html rename to spec/fixtures/extensions/devtools-extension/index.html diff --git a/spec/fixtures/extensions/devtools-extension/index.js b/spec/fixtures/extensions/devtools-extension/index.js new file mode 100644 index 0000000000000..ff0c1cb69c457 --- /dev/null +++ b/spec/fixtures/extensions/devtools-extension/index.js @@ -0,0 +1,4 @@ +/* global chrome */ +chrome.devtools.inspectedWindow.eval('require("electron").ipcRenderer.send("winning")', (result, exc) => { + console.log(result, exc); +}); diff --git a/spec-main/fixtures/extensions/devtools-extension/manifest.json b/spec/fixtures/extensions/devtools-extension/manifest.json similarity index 100% rename from spec-main/fixtures/extensions/devtools-extension/manifest.json rename to spec/fixtures/extensions/devtools-extension/manifest.json diff --git a/spec/fixtures/extensions/host-permissions/malformed/manifest.json b/spec/fixtures/extensions/host-permissions/malformed/manifest.json new file mode 100644 index 0000000000000..0e4ce8c20271e --- /dev/null +++ b/spec/fixtures/extensions/host-permissions/malformed/manifest.json @@ -0,0 +1,9 @@ +{ + "name": "malformed", + "version": "0.1", + "manifest_version": 3, + "description": "Extension with invalid host_permissions", + "host_permissions": [ + "malformed_host" + ] +} \ No newline at end of file diff --git a/spec/fixtures/extensions/host-permissions/privileged-tab-info/background.js b/spec/fixtures/extensions/host-permissions/privileged-tab-info/background.js new file mode 100644 index 0000000000000..7725abe038b66 --- /dev/null +++ b/spec/fixtures/extensions/host-permissions/privileged-tab-info/background.js @@ -0,0 +1,6 @@ +/* global chrome */ + +chrome.runtime.onMessage.addListener((_request, _sender, sendResponse) => { + chrome.tabs.query({}).then(sendResponse); + return true; +}); diff --git a/spec/fixtures/extensions/host-permissions/privileged-tab-info/main.js b/spec/fixtures/extensions/host-permissions/privileged-tab-info/main.js new file mode 100644 index 0000000000000..0f823f7240346 --- /dev/null +++ b/spec/fixtures/extensions/host-permissions/privileged-tab-info/main.js @@ -0,0 +1,15 @@ +/* global chrome */ + +chrome.runtime.onMessage.addListener((request, _sender, sendResponse) => { + sendResponse(request); +}); + +window.addEventListener( + 'message', + () => { + chrome.runtime.sendMessage({ method: 'query' }, (response) => { + console.log(JSON.stringify(response)); + }); + }, + false +); diff --git a/spec/fixtures/extensions/host-permissions/privileged-tab-info/manifest.json b/spec/fixtures/extensions/host-permissions/privileged-tab-info/manifest.json new file mode 100644 index 0000000000000..55dfe2696d740 --- /dev/null +++ b/spec/fixtures/extensions/host-permissions/privileged-tab-info/manifest.json @@ -0,0 +1,14 @@ +{ + "name": "privileged-tab-info", + "version": "0.1", + "manifest_version": 3, + "content_scripts": [{ + "matches": [ ""], + "js": ["main.js"], + "run_at": "document_start" + }], + "host_permissions": ["http://*/*"], + "background": { + "service_worker": "background.js" + } +} \ No newline at end of file diff --git a/spec/fixtures/extensions/lazy-background-page/background.js b/spec/fixtures/extensions/lazy-background-page/background.js new file mode 100644 index 0000000000000..a954e7fa882e0 --- /dev/null +++ b/spec/fixtures/extensions/lazy-background-page/background.js @@ -0,0 +1,5 @@ +/* global chrome */ +chrome.runtime.onMessage.addListener((message, sender, reply) => { + window.receivedMessage = message; + reply({ message, sender }); +}); diff --git a/spec/fixtures/extensions/lazy-background-page/content_script.js b/spec/fixtures/extensions/lazy-background-page/content_script.js new file mode 100644 index 0000000000000..938c908e44a2b --- /dev/null +++ b/spec/fixtures/extensions/lazy-background-page/content_script.js @@ -0,0 +1,6 @@ +/* global chrome */ +chrome.runtime.sendMessage({ some: 'message' }, (response) => { + const script = document.createElement('script'); + script.textContent = `require('electron').ipcRenderer.send('bg-page-message-response', ${JSON.stringify(response)})`; + document.documentElement.appendChild(script); +}); diff --git a/spec-main/fixtures/extensions/lazy-background-page/get-background-page.js b/spec/fixtures/extensions/lazy-background-page/get-background-page.js similarity index 77% rename from spec-main/fixtures/extensions/lazy-background-page/get-background-page.js rename to spec/fixtures/extensions/lazy-background-page/get-background-page.js index a54c8391f513e..10aeab0cdfca4 100644 --- a/spec-main/fixtures/extensions/lazy-background-page/get-background-page.js +++ b/spec/fixtures/extensions/lazy-background-page/get-background-page.js @@ -2,6 +2,6 @@ window.completionPromise = new Promise((resolve) => { window.completionPromiseResolve = resolve; }); -chrome.runtime.sendMessage({ some: 'message' }, (response) => { +chrome.runtime.sendMessage({ some: 'message' }, () => { window.completionPromiseResolve(chrome.extension.getBackgroundPage().receivedMessage); }); diff --git a/spec-main/fixtures/extensions/lazy-background-page/manifest.json b/spec/fixtures/extensions/lazy-background-page/manifest.json similarity index 100% rename from spec-main/fixtures/extensions/lazy-background-page/manifest.json rename to spec/fixtures/extensions/lazy-background-page/manifest.json diff --git a/spec-main/fixtures/extensions/lazy-background-page/page-get-background.html b/spec/fixtures/extensions/lazy-background-page/page-get-background.html similarity index 100% rename from spec-main/fixtures/extensions/lazy-background-page/page-get-background.html rename to spec/fixtures/extensions/lazy-background-page/page-get-background.html diff --git a/spec-main/fixtures/extensions/lazy-background-page/page-runtime-get-background.html b/spec/fixtures/extensions/lazy-background-page/page-runtime-get-background.html similarity index 100% rename from spec-main/fixtures/extensions/lazy-background-page/page-runtime-get-background.html rename to spec/fixtures/extensions/lazy-background-page/page-runtime-get-background.html diff --git a/spec-main/fixtures/extensions/lazy-background-page/runtime-get-background-page.js b/spec/fixtures/extensions/lazy-background-page/runtime-get-background-page.js similarity index 79% rename from spec-main/fixtures/extensions/lazy-background-page/runtime-get-background-page.js rename to spec/fixtures/extensions/lazy-background-page/runtime-get-background-page.js index 59716d5501dd4..199476999c64a 100644 --- a/spec-main/fixtures/extensions/lazy-background-page/runtime-get-background-page.js +++ b/spec/fixtures/extensions/lazy-background-page/runtime-get-background-page.js @@ -2,7 +2,7 @@ window.completionPromise = new Promise((resolve) => { window.completionPromiseResolve = resolve; }); -chrome.runtime.sendMessage({ some: 'message' }, (response) => { +chrome.runtime.sendMessage({ some: 'message' }, () => { chrome.runtime.getBackgroundPage((bgPage) => { window.completionPromiseResolve(bgPage.receivedMessage); }); diff --git a/spec/fixtures/extensions/load-error/manifest.json b/spec/fixtures/extensions/load-error/manifest.json new file mode 100644 index 0000000000000..29a9cd7975e3d --- /dev/null +++ b/spec/fixtures/extensions/load-error/manifest.json @@ -0,0 +1,8 @@ +{ + "name": "load-error", + "version": "1.0", + "icons": { + "16": "/images/error.png" + }, + "manifest_version": 2 +} diff --git a/spec/fixtures/extensions/minimum-chrome-version/main.js b/spec/fixtures/extensions/minimum-chrome-version/main.js new file mode 100644 index 0000000000000..d58117c501c1e --- /dev/null +++ b/spec/fixtures/extensions/minimum-chrome-version/main.js @@ -0,0 +1 @@ +document.documentElement.style.backgroundColor = 'blue'; diff --git a/spec/fixtures/extensions/minimum-chrome-version/manifest.json b/spec/fixtures/extensions/minimum-chrome-version/manifest.json new file mode 100644 index 0000000000000..c65bced2f5f38 --- /dev/null +++ b/spec/fixtures/extensions/minimum-chrome-version/manifest.json @@ -0,0 +1,14 @@ +{ + "name": "chrome-too-low-version", + "version": "1.0", + "minimum_chrome_version": "999", + "content_scripts": [ + { + "matches": [""], + "js": ["main.js"], + "run_at": "document_start" + } + ], + "permissions": ["storage"], + "manifest_version": 3 +} diff --git a/spec/fixtures/extensions/missing-manifest/main.js b/spec/fixtures/extensions/missing-manifest/main.js new file mode 100644 index 0000000000000..d1e760d7b9d07 --- /dev/null +++ b/spec/fixtures/extensions/missing-manifest/main.js @@ -0,0 +1 @@ +console.log('oh no where is my manifest'); diff --git a/spec/fixtures/extensions/mv3-service-worker/background.js b/spec/fixtures/extensions/mv3-service-worker/background.js new file mode 100644 index 0000000000000..411f03f8fbbb4 --- /dev/null +++ b/spec/fixtures/extensions/mv3-service-worker/background.js @@ -0,0 +1,7 @@ +/* global chrome */ + +chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => { + if (message === 'fetch-confirmation') { + sendResponse({ message: 'Hello from background.js' }); + } +}); diff --git a/spec/fixtures/extensions/mv3-service-worker/main.js b/spec/fixtures/extensions/mv3-service-worker/main.js new file mode 100644 index 0000000000000..9c1ee6f4b7271 --- /dev/null +++ b/spec/fixtures/extensions/mv3-service-worker/main.js @@ -0,0 +1,17 @@ +/* global chrome */ + +chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { + sendResponse(message); +}); + +window.addEventListener( + 'message', + (event) => { + if (event.data === 'fetch-confirmation') { + chrome.runtime.sendMessage('fetch-confirmation', (response) => { + console.log(JSON.stringify(response)); + }); + } + }, + false +); diff --git a/spec/fixtures/extensions/mv3-service-worker/manifest.json b/spec/fixtures/extensions/mv3-service-worker/manifest.json new file mode 100644 index 0000000000000..e18a207e45cb9 --- /dev/null +++ b/spec/fixtures/extensions/mv3-service-worker/manifest.json @@ -0,0 +1,20 @@ +{ + "name": "MV3 Service Worker", + "description": "Test for extension service worker support.", + "version": "1.0", + "manifest_version": 3, + "content_scripts": [ + { + "matches": [ + "" + ], + "js": [ + "main.js" + ], + "run_at": "document_start" + } + ], + "background": { + "service_worker": "background.js" + } +} diff --git a/docs/fiddles/menus/customize-menus/.keep b/spec/fixtures/extensions/persistent-background-page/background.js similarity index 100% rename from docs/fiddles/menus/customize-menus/.keep rename to spec/fixtures/extensions/persistent-background-page/background.js diff --git a/spec-main/fixtures/extensions/persistent-background-page/manifest.json b/spec/fixtures/extensions/persistent-background-page/manifest.json similarity index 100% rename from spec-main/fixtures/extensions/persistent-background-page/manifest.json rename to spec/fixtures/extensions/persistent-background-page/manifest.json diff --git a/spec-main/fixtures/extensions/red-bg/main.js b/spec/fixtures/extensions/red-bg/main.js similarity index 100% rename from spec-main/fixtures/extensions/red-bg/main.js rename to spec/fixtures/extensions/red-bg/main.js diff --git a/spec-main/fixtures/extensions/red-bg/manifest.json b/spec/fixtures/extensions/red-bg/manifest.json similarity index 100% rename from spec-main/fixtures/extensions/red-bg/manifest.json rename to spec/fixtures/extensions/red-bg/manifest.json diff --git a/spec/fixtures/extensions/tabs-cross-session/background.js b/spec/fixtures/extensions/tabs-cross-session/background.js new file mode 100644 index 0000000000000..979a0f6cc4058 --- /dev/null +++ b/spec/fixtures/extensions/tabs-cross-session/background.js @@ -0,0 +1,45 @@ +/* global chrome */ + +const handleRequest = async (request, sender, sendResponse) => { + const { method, tabId, args = [] } = request; + + try { + switch (method) { + case 'get': { + const tab = await chrome.tabs.get(tabId); + sendResponse({ ok: true, result: tab }); + break; + } + case 'update': { + const tab = await chrome.tabs.update(tabId, args[0]); + sendResponse({ ok: true, result: tab }); + break; + } + case 'reload': { + await chrome.tabs.reload(tabId); + sendResponse({ ok: true }); + break; + } + case 'executeScript': { + const results = await chrome.scripting.executeScript({ + target: { tabId }, + func: () => document.title + }); + sendResponse({ ok: true, result: results }); + break; + } + case 'sendMessage': { + const response = await chrome.tabs.sendMessage(tabId, args[0]); + sendResponse({ ok: true, result: response }); + break; + } + } + } catch (error) { + sendResponse({ ok: false, error: error.message }); + } +}; + +chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + handleRequest(request, sender, sendResponse); + return true; +}); diff --git a/spec/fixtures/extensions/tabs-cross-session/main.js b/spec/fixtures/extensions/tabs-cross-session/main.js new file mode 100644 index 0000000000000..6328650f43174 --- /dev/null +++ b/spec/fixtures/extensions/tabs-cross-session/main.js @@ -0,0 +1,11 @@ +/* global chrome */ + +window.addEventListener( + 'message', + (event) => { + chrome.runtime.sendMessage(JSON.parse(event.data), (response) => { + console.log(JSON.stringify(response)); + }); + }, + false +); diff --git a/spec/fixtures/extensions/tabs-cross-session/manifest.json b/spec/fixtures/extensions/tabs-cross-session/manifest.json new file mode 100644 index 0000000000000..289d813e5739c --- /dev/null +++ b/spec/fixtures/extensions/tabs-cross-session/manifest.json @@ -0,0 +1,17 @@ +{ + "name": "tabs-cross-session", + "version": "1.0", + "manifest_version": 3, + "permissions": ["tabs", "scripting"], + "host_permissions": [""], + "content_scripts": [ + { + "matches": [""], + "js": ["main.js"], + "run_at": "document_start" + } + ], + "background": { + "service_worker": "background.js" + } +} diff --git a/spec-main/fixtures/extensions/ui-page/bare-page.html b/spec/fixtures/extensions/ui-page/bare-page.html similarity index 100% rename from spec-main/fixtures/extensions/ui-page/bare-page.html rename to spec/fixtures/extensions/ui-page/bare-page.html diff --git a/spec-main/fixtures/extensions/ui-page/manifest.json b/spec/fixtures/extensions/ui-page/manifest.json similarity index 100% rename from spec-main/fixtures/extensions/ui-page/manifest.json rename to spec/fixtures/extensions/ui-page/manifest.json diff --git a/spec-main/fixtures/extensions/ui-page/page-get-background.html b/spec/fixtures/extensions/ui-page/page-get-background.html similarity index 100% rename from spec-main/fixtures/extensions/ui-page/page-get-background.html rename to spec/fixtures/extensions/ui-page/page-get-background.html diff --git a/spec-main/fixtures/extensions/ui-page/page-script-load.html b/spec/fixtures/extensions/ui-page/page-script-load.html similarity index 100% rename from spec-main/fixtures/extensions/ui-page/page-script-load.html rename to spec/fixtures/extensions/ui-page/page-script-load.html diff --git a/spec-main/fixtures/extensions/ui-page/script.js b/spec/fixtures/extensions/ui-page/script.js similarity index 100% rename from spec-main/fixtures/extensions/ui-page/script.js rename to spec/fixtures/extensions/ui-page/script.js diff --git a/spec/fixtures/file-system/persist.txt b/spec/fixtures/file-system/persist.txt new file mode 100644 index 0000000000000..4750e51cc1a56 --- /dev/null +++ b/spec/fixtures/file-system/persist.txt @@ -0,0 +1 @@ +hello persist \ No newline at end of file diff --git a/spec/fixtures/file-system/test-perms.html b/spec/fixtures/file-system/test-perms.html new file mode 100644 index 0000000000000..24a4787d257cc --- /dev/null +++ b/spec/fixtures/file-system/test-perms.html @@ -0,0 +1,30 @@ + + + + + + Hello World! + + + + + + + \ No newline at end of file diff --git a/spec/fixtures/file-system/test.txt b/spec/fixtures/file-system/test.txt new file mode 100644 index 0000000000000..95d09f2b10159 --- /dev/null +++ b/spec/fixtures/file-system/test.txt @@ -0,0 +1 @@ +hello world \ No newline at end of file diff --git a/spec/fixtures/hello.txt b/spec/fixtures/hello.txt new file mode 100644 index 0000000000000..3b18e512dba79 --- /dev/null +++ b/spec/fixtures/hello.txt @@ -0,0 +1 @@ +hello world diff --git a/spec/fixtures/log-test.js b/spec/fixtures/log-test.js new file mode 100644 index 0000000000000..840b66791e2dd --- /dev/null +++ b/spec/fixtures/log-test.js @@ -0,0 +1,3 @@ +const binding = process._linkedBinding('electron_common_testing'); +binding.log(1, 'CHILD_PROCESS_TEST_LOG'); +binding.log(1, `CHILD_PROCESS_DESTINATION_${binding.getLoggingDestination()}`); diff --git a/spec/fixtures/module/access-blink-apis.js b/spec/fixtures/module/access-blink-apis.js index 625451dac3b52..9b0970bae5d18 100644 --- a/spec/fixtures/module/access-blink-apis.js +++ b/spec/fixtures/module/access-blink-apis.js @@ -2,8 +2,8 @@ window.delayed = true; global.getGlobalNames = () => { return Object.getOwnPropertyNames(global) - .filter(key => typeof global[key] === 'function') - .filter(key => key !== 'WebView') + .filter((key) => typeof global[key] === 'function') + .filter((key) => key !== 'WebView') .sort(); }; diff --git a/spec/fixtures/module/asar.js b/spec/fixtures/module/asar.js index 6a973ad386045..7b196e533943f 100644 --- a/spec/fixtures/module/asar.js +++ b/spec/fixtures/module/asar.js @@ -1,4 +1,5 @@ -const fs = require('fs'); +const fs = require('node:fs'); + process.on('message', function (file) { process.send(fs.readFileSync(file).toString()); }); diff --git a/spec/fixtures/module/check-arguments.js b/spec/fixtures/module/check-arguments.js index 8a5ef8dde197d..dccbe2d314b04 100644 --- a/spec/fixtures/module/check-arguments.js +++ b/spec/fixtures/module/check-arguments.js @@ -1,4 +1,5 @@ const { ipcRenderer } = require('electron'); + window.onload = function () { ipcRenderer.send('answer', process.argv); }; diff --git a/spec/fixtures/module/create_socket.js b/spec/fixtures/module/create_socket.js index d5eca125a541e..abcc0e66be20d 100644 --- a/spec/fixtures/module/create_socket.js +++ b/spec/fixtures/module/create_socket.js @@ -1,4 +1,5 @@ -const net = require('net'); +const net = require('node:net'); + const server = net.createServer(function () {}); server.listen(process.argv[2]); process.exit(0); diff --git a/spec-main/fixtures/module/declare-buffer.js b/spec/fixtures/module/declare-buffer.js similarity index 100% rename from spec-main/fixtures/module/declare-buffer.js rename to spec/fixtures/module/declare-buffer.js diff --git a/spec-main/fixtures/module/declare-global.js b/spec/fixtures/module/declare-global.js similarity index 100% rename from spec-main/fixtures/module/declare-global.js rename to spec/fixtures/module/declare-global.js diff --git a/spec-main/fixtures/module/declare-process.js b/spec/fixtures/module/declare-process.js similarity index 100% rename from spec-main/fixtures/module/declare-process.js rename to spec/fixtures/module/declare-process.js diff --git a/spec/fixtures/module/echo-renamed.js b/spec/fixtures/module/echo-renamed.js new file mode 100644 index 0000000000000..d81f922c21f67 --- /dev/null +++ b/spec/fixtures/module/echo-renamed.js @@ -0,0 +1,7 @@ +let echo; +try { + echo = require('@electron-ci/echo'); +} catch { + process.exit(1); +} +process.exit(echo(0)); diff --git a/spec/fixtures/module/echo.js b/spec/fixtures/module/echo.js new file mode 100644 index 0000000000000..56ba812a0d994 --- /dev/null +++ b/spec/fixtures/module/echo.js @@ -0,0 +1,7 @@ +process.on('uncaughtException', function (err) { + process.send(err.message); +}); + +const echo = require('@electron-ci/echo'); + +process.send(echo('ok')); diff --git a/spec/fixtures/module/fail.js b/spec/fixtures/module/fail.js new file mode 100644 index 0000000000000..6cee2e1e79a14 --- /dev/null +++ b/spec/fixtures/module/fail.js @@ -0,0 +1 @@ +process.exit(1); diff --git a/spec/fixtures/module/fork_ping.js b/spec/fixtures/module/fork_ping.js index e9b28bde1d61c..857211280d23c 100644 --- a/spec/fixtures/module/fork_ping.js +++ b/spec/fixtures/module/fork_ping.js @@ -1,10 +1,12 @@ -const path = require('path'); +const childProcess = require('node:child_process'); +const path = require('node:path'); process.on('uncaughtException', function (error) { process.send(error.stack); }); -const child = require('child_process').fork(path.join(__dirname, '/ping.js')); +const child = childProcess.fork(path.join(__dirname, '/ping.js')); + process.on('message', function (msg) { child.send(msg); }); diff --git a/spec/fixtures/module/hello-child.js b/spec/fixtures/module/hello-child.js index a40ab2165751b..77fcd20cc2123 100644 --- a/spec/fixtures/module/hello-child.js +++ b/spec/fixtures/module/hello-child.js @@ -1,5 +1,5 @@ class Hello { - say () { + say() { return 'hi child window'; } } diff --git a/spec/fixtures/module/hello.js b/spec/fixtures/module/hello.js index 49d2cb827ef29..f678ba5970cfa 100644 --- a/spec/fixtures/module/hello.js +++ b/spec/fixtures/module/hello.js @@ -1,5 +1,5 @@ class Hello { - say () { + say() { return 'hi'; } } diff --git a/spec/fixtures/module/inspector-binding.js b/spec/fixtures/module/inspector-binding.js index 64a5986e8c75a..f127ca623e473 100644 --- a/spec/fixtures/module/inspector-binding.js +++ b/spec/fixtures/module/inspector-binding.js @@ -1,9 +1,9 @@ -const inspector = require('inspector'); -const path = require('path'); -const { pathToFileURL } = require('url'); +const inspector = require('node:inspector'); +const path = require('node:path'); +const { pathToFileURL } = require('node:url'); // This test case will set a breakpoint 4 lines below -function debuggedFunction () { +function debuggedFunction() { let i; let accum = 0; for (i = 0; i < 5; i++) { @@ -14,23 +14,27 @@ function debuggedFunction () { let scopeCallback = null; -function checkScope (session, scopeId) { - session.post('Runtime.getProperties', { - objectId: scopeId, - ownProperties: false, - accessorPropertiesOnly: false, - generatePreview: true - }, scopeCallback); +function checkScope(session, scopeId) { + session.post( + 'Runtime.getProperties', + { + objectId: scopeId, + ownProperties: false, + accessorPropertiesOnly: false, + generatePreview: true + }, + scopeCallback + ); } -function debuggerPausedCallback (session, notification) { +function debuggerPausedCallback(session, notification) { const params = notification.params; const callFrame = params.callFrames[0]; const scopeId = callFrame.scopeChain[0].object.objectId; checkScope(session, scopeId); } -function testSampleDebugSession () { +function testSampleDebugSession() { let cur = 0; const failures = []; const expects = { @@ -45,17 +49,17 @@ function testSampleDebugSession () { actual = v.value.value; expected = expects[v.name][i]; if (actual !== expected) { - failures.push(`Iteration ${i} variable: ${v.name} ` + - `expected: ${expected} actual: ${actual}`); + failures.push(`Iteration ${i} variable: ${v.name} ` + `expected: ${expected} actual: ${actual}`); } } }; const session = new inspector.Session(); session.connect(); - session.on('Debugger.paused', - (notification) => debuggerPausedCallback(session, notification)); + session.on('Debugger.paused', (notification) => debuggerPausedCallback(session, notification)); let cbAsSecondArgCalled = false; - session.post('Debugger.enable', () => { cbAsSecondArgCalled = true; }); + session.post('Debugger.enable', () => { + cbAsSecondArgCalled = true; + }); session.post('Debugger.setBreakpointByUrl', { lineNumber: 9, url: pathToFileURL(path.resolve(__dirname, __filename)).toString(), @@ -69,7 +73,7 @@ function testSampleDebugSession () { process.send({ cmd: 'assert', debuggerEnabled: cbAsSecondArgCalled, - success: (cur === 5) && (failures.length === 0) + success: cur === 5 && failures.length === 0 }); } diff --git a/spec/fixtures/module/isolated-ping.js b/spec/fixtures/module/isolated-ping.js index 90392e46fe4de..e7d5980d53566 100644 --- a/spec/fixtures/module/isolated-ping.js +++ b/spec/fixtures/module/isolated-ping.js @@ -1,2 +1,3 @@ const { ipcRenderer } = require('electron'); + ipcRenderer.send('pong'); diff --git a/spec/fixtures/module/module-paths.js b/spec/fixtures/module/module-paths.js new file mode 100644 index 0000000000000..fc5d6cb1ca91b --- /dev/null +++ b/spec/fixtures/module/module-paths.js @@ -0,0 +1,3 @@ +const Module = require('node:module'); + +process.send(Module._nodeModulePaths(process.resourcesPath + '/test.js')); diff --git a/spec/fixtures/module/no-asar.js b/spec/fixtures/module/no-asar.js index 8835a22c42d1e..0835fea403b01 100644 --- a/spec/fixtures/module/no-asar.js +++ b/spec/fixtures/module/no-asar.js @@ -1,5 +1,5 @@ -const fs = require('fs'); -const path = require('path'); +const fs = require('node:fs'); +const path = require('node:path'); const stats = fs.statSync(path.join(__dirname, '..', 'test.asar', 'a.asar')); diff --git a/spec/fixtures/module/preload-context.js b/spec/fixtures/module/preload-context.js index 4dbc3a9a58d3b..cdbee53986943 100644 --- a/spec/fixtures/module/preload-context.js +++ b/spec/fixtures/module/preload-context.js @@ -1,4 +1,4 @@ -var test = 'test' // eslint-disable-line +var test = 'test'; // eslint-disable-line no-var,@typescript-eslint/no-unused-vars const types = { require: typeof require, diff --git a/spec/fixtures/module/preload-disable-remote.js b/spec/fixtures/module/preload-disable-remote.js deleted file mode 100644 index 9b6b96cbf28f5..0000000000000 --- a/spec/fixtures/module/preload-disable-remote.js +++ /dev/null @@ -1,8 +0,0 @@ -setImmediate(function () { - try { - const { remote } = require('electron'); - console.log(JSON.stringify(typeof remote)); - } catch (e) { - console.log(e.message); - } -}); diff --git a/spec/fixtures/module/preload-electron.js b/spec/fixtures/module/preload-electron.js new file mode 100644 index 0000000000000..9b3482f5df220 --- /dev/null +++ b/spec/fixtures/module/preload-electron.js @@ -0,0 +1 @@ +window.electron = require('electron'); diff --git a/spec/fixtures/module/preload-error-syntax.js b/spec/fixtures/module/preload-error-syntax.js index bf9c543fb191a..40a32acc47e25 100644 --- a/spec/fixtures/module/preload-error-syntax.js +++ b/spec/fixtures/module/preload-error-syntax.js @@ -1,2 +1,2 @@ // eslint-disable-next-line -foobar +foobar; diff --git a/spec/fixtures/module/preload-eventemitter.js b/spec/fixtures/module/preload-eventemitter.js new file mode 100644 index 0000000000000..e0c74a97b7bcc --- /dev/null +++ b/spec/fixtures/module/preload-eventemitter.js @@ -0,0 +1,11 @@ +(function () { + const { EventEmitter } = require('node:events'); + const emitter = new EventEmitter(); + const rendererEventEmitterProperties = []; + let currentObj = emitter; + do { + rendererEventEmitterProperties.push(...Object.getOwnPropertyNames(currentObj)); + } while ((currentObj = Object.getPrototypeOf(currentObj))); + const { ipcRenderer } = require('electron'); + ipcRenderer.send('answer', rendererEventEmitterProperties); +})(); diff --git a/spec/fixtures/module/preload-ipc-ping-pong.js b/spec/fixtures/module/preload-ipc-ping-pong.js deleted file mode 100644 index 41d4c75382230..0000000000000 --- a/spec/fixtures/module/preload-ipc-ping-pong.js +++ /dev/null @@ -1,9 +0,0 @@ -const { ipcRenderer } = require('electron'); - -ipcRenderer.on('ping', function (event, payload) { - ipcRenderer.sendTo(event.senderId, 'pong', payload); -}); - -ipcRenderer.on('ping-æøåü', function (event, payload) { - ipcRenderer.sendTo(event.senderId, 'pong-æøåü', payload); -}); diff --git a/spec/fixtures/module/preload-ipc.js b/spec/fixtures/module/preload-ipc.js index 390fa920dfa09..465b7152edeee 100644 --- a/spec/fixtures/module/preload-ipc.js +++ b/spec/fixtures/module/preload-ipc.js @@ -1,4 +1,5 @@ const { ipcRenderer } = require('electron'); + ipcRenderer.on('ping', function (event, message) { ipcRenderer.sendToHost('pong', message); }); diff --git a/spec/fixtures/module/preload-pdf-loaded-in-nested-subframe.js b/spec/fixtures/module/preload-pdf-loaded-in-nested-subframe.js deleted file mode 100644 index e72a4a4058db4..0000000000000 --- a/spec/fixtures/module/preload-pdf-loaded-in-nested-subframe.js +++ /dev/null @@ -1,15 +0,0 @@ -const { ipcRenderer } = require('electron'); - -document.addEventListener('DOMContentLoaded', (event) => { - const outerFrame = document.querySelector('#outer-frame'); - if (outerFrame) { - outerFrame.onload = function () { - const pdframe = outerFrame.contentWindow.document.getElementById('pdf-frame'); - if (pdframe) { - pdframe.contentWindow.addEventListener('pdf-loaded', (event) => { - ipcRenderer.send('pdf-loaded', event.detail); - }); - } - }; - } -}); diff --git a/spec/fixtures/module/preload-pdf-loaded-in-subframe.js b/spec/fixtures/module/preload-pdf-loaded-in-subframe.js deleted file mode 100644 index dd7a7aaa42d6d..0000000000000 --- a/spec/fixtures/module/preload-pdf-loaded-in-subframe.js +++ /dev/null @@ -1,10 +0,0 @@ -const { ipcRenderer } = require('electron'); - -document.addEventListener('DOMContentLoaded', (event) => { - const subframe = document.querySelector('#pdf-frame'); - if (subframe) { - subframe.contentWindow.addEventListener('pdf-loaded', (event) => { - ipcRenderer.send('pdf-loaded', event.detail); - }); - } -}); diff --git a/spec/fixtures/module/preload-pdf-loaded.js b/spec/fixtures/module/preload-pdf-loaded.js deleted file mode 100644 index aa5c8fb4ffac6..0000000000000 --- a/spec/fixtures/module/preload-pdf-loaded.js +++ /dev/null @@ -1,5 +0,0 @@ -const { ipcRenderer } = require('electron'); - -window.addEventListener('pdf-loaded', function (event) { - ipcRenderer.send('pdf-loaded', event.detail); -}); diff --git a/spec/fixtures/module/preload-sandbox.js b/spec/fixtures/module/preload-sandbox.js new file mode 100644 index 0000000000000..dec192b687ec4 --- /dev/null +++ b/spec/fixtures/module/preload-sandbox.js @@ -0,0 +1,70 @@ +(function () { + const { setImmediate } = require('node:timers'); + const { ipcRenderer } = require('electron'); + window.ipcRenderer = ipcRenderer; + window.setImmediate = setImmediate; + window.require = require; + + function invoke(code) { + try { + return code(); + } catch { + return null; + } + } + + process.once('loaded', () => { + ipcRenderer.send('process-loaded'); + }); + + if (location.protocol === 'file:') { + window.test = 'preload'; + window.process = process; + if (process.env.sandboxmain) { + window.test = { + osSandbox: !process.argv.includes('--no-sandbox'), + hasCrash: typeof process.crash === 'function', + hasHang: typeof process.hang === 'function', + creationTime: invoke(() => process.getCreationTime()), + heapStatistics: invoke(() => process.getHeapStatistics()), + blinkMemoryInfo: invoke(() => process.getBlinkMemoryInfo()), + processMemoryInfo: invoke(() => (process.getProcessMemoryInfo() ? {} : null)), + systemMemoryInfo: invoke(() => process.getSystemMemoryInfo()), + systemVersion: invoke(() => process.getSystemVersion()), + cpuUsage: invoke(() => process.getCPUUsage()), + uptime: invoke(() => process.uptime()), + // eslint-disable-next-line unicorn/prefer-node-protocol + nodeEvents: invoke(() => require('events') === require('node:events')), + // eslint-disable-next-line unicorn/prefer-node-protocol + nodeTimers: invoke(() => require('timers') === require('node:timers')), + // eslint-disable-next-line unicorn/prefer-node-protocol + nodeUrl: invoke(() => require('url') === require('node:url')), + env: process.env, + execPath: process.execPath, + pid: process.pid, + arch: process.arch, + platform: process.platform, + sandboxed: process.sandboxed, + contextIsolated: process.contextIsolated, + type: process.type, + version: process.version, + versions: process.versions, + contextId: process.contextId + }; + } + } else if (location.href !== 'about:blank') { + addEventListener('DOMContentLoaded', () => { + ipcRenderer.on('touch-the-opener', () => { + let errorMessage = null; + try { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const openerDoc = opener.document; + } catch (error) { + errorMessage = error.message; + } + ipcRenderer.send('answer', errorMessage); + }); + ipcRenderer.send('child-loaded', window.opener == null, document.body.innerHTML, location.href); + }); + } +})(); diff --git a/spec/fixtures/module/preload.js b/spec/fixtures/module/preload.js index aa7bba4cae8f0..3db67d9bde9b1 100644 --- a/spec/fixtures/module/preload.js +++ b/spec/fixtures/module/preload.js @@ -1,6 +1,7 @@ const types = { require: typeof require, module: typeof module, + exports: typeof exports, process: typeof process, Buffer: typeof Buffer }; diff --git a/spec-main/fixtures/module/print-crash-parameters.js b/spec/fixtures/module/print-crash-parameters.js similarity index 100% rename from spec-main/fixtures/module/print-crash-parameters.js rename to spec/fixtures/module/print-crash-parameters.js diff --git a/spec/fixtures/module/run-as-node.js b/spec/fixtures/module/run-as-node.js index fc15cb54ef778..dba0d0cd7042f 100644 --- a/spec/fixtures/module/run-as-node.js +++ b/spec/fixtures/module/run-as-node.js @@ -1,5 +1,7 @@ -console.log(JSON.stringify({ - stdoutType: process.stdout._type, - processType: typeof process.type, - window: typeof window -})); +console.log( + JSON.stringify({ + stdoutType: process.stdout._type, + processType: typeof process.type, + window: typeof window + }) +); diff --git a/spec/fixtures/module/send-later.js b/spec/fixtures/module/send-later.js index 5b4a22097275c..feef5d903aeff 100644 --- a/spec/fixtures/module/send-later.js +++ b/spec/fixtures/module/send-later.js @@ -1,4 +1,5 @@ const { ipcRenderer } = require('electron'); + window.onload = function () { ipcRenderer.send('answer', typeof window.process, typeof window.Buffer); }; diff --git a/spec-main/fixtures/module/test.coffee b/spec/fixtures/module/test.coffee similarity index 100% rename from spec-main/fixtures/module/test.coffee rename to spec/fixtures/module/test.coffee diff --git a/spec/fixtures/module/uv-dlopen.js b/spec/fixtures/module/uv-dlopen.js new file mode 100644 index 0000000000000..2f1e3413f3255 --- /dev/null +++ b/spec/fixtures/module/uv-dlopen.js @@ -0,0 +1 @@ +require('@electron-ci/uv-dlopen'); diff --git a/spec/fixtures/native-addon/dialog-helper/.gitignore b/spec/fixtures/native-addon/dialog-helper/.gitignore new file mode 100644 index 0000000000000..41912cdec36b3 --- /dev/null +++ b/spec/fixtures/native-addon/dialog-helper/.gitignore @@ -0,0 +1,7 @@ +/node_modules +/build +*.swp +*.log +*~ +.node-version +package-lock.json diff --git a/spec/fixtures/native-addon/dialog-helper/binding.gyp b/spec/fixtures/native-addon/dialog-helper/binding.gyp new file mode 100644 index 0000000000000..42e80baf7e006 --- /dev/null +++ b/spec/fixtures/native-addon/dialog-helper/binding.gyp @@ -0,0 +1,23 @@ +{ + 'targets': [ + { + 'target_name': 'dialog_helper', + 'conditions': [ + ['OS=="mac"', { + 'sources': [ + 'src/main.cc', + 'src/dialog_helper_mac.mm', + ], + 'libraries': [ + '$(SDKROOT)/System/Library/Frameworks/AppKit.framework', + ], + 'xcode_settings': { + 'OTHER_CFLAGS': ['-fobjc-arc'], + }, + }, { + 'type': 'none', + }], + ], + } + ] +} diff --git a/spec/fixtures/native-addon/dialog-helper/lib/index.js b/spec/fixtures/native-addon/dialog-helper/lib/index.js new file mode 100644 index 0000000000000..c29ce0115a1fa --- /dev/null +++ b/spec/fixtures/native-addon/dialog-helper/lib/index.js @@ -0,0 +1,2 @@ +const binding = require('../build/Release/dialog_helper.node'); +module.exports = binding; diff --git a/spec/fixtures/native-addon/dialog-helper/package.json b/spec/fixtures/native-addon/dialog-helper/package.json new file mode 100644 index 0000000000000..9e86071aa51b5 --- /dev/null +++ b/spec/fixtures/native-addon/dialog-helper/package.json @@ -0,0 +1,10 @@ +{ + "name": "@electron-ci/dialog-helper", + "version": "0.0.1", + "main": "./lib/index.js", + "private": true, + "licenses": "MIT", + "scripts": { + "install": "node-gyp configure && node-gyp build" + } +} diff --git a/spec/fixtures/native-addon/dialog-helper/src/dialog_helper.h b/spec/fixtures/native-addon/dialog-helper/src/dialog_helper.h new file mode 100644 index 0000000000000..af317369b0b3e --- /dev/null +++ b/spec/fixtures/native-addon/dialog-helper/src/dialog_helper.h @@ -0,0 +1,68 @@ +#ifndef SRC_DIALOG_HELPER_H_ +#define SRC_DIALOG_HELPER_H_ + +#include +#include + +namespace dialog_helper { + +struct DialogInfo { + // "message-box", "open-dialog", "save-dialog", or "none" + std::string type; + // Button titles for message boxes + std::string buttons; // JSON array string, e.g. '["OK","Cancel"]' + // Message text (NSAlert messageText or panel title) + std::string message; + // Detail / informative text (NSAlert informativeText) + std::string detail; + // Checkbox (suppression button) label, empty if none + std::string checkbox_label; + // Whether the checkbox is checked + bool checkbox_checked = false; + + // File dialog properties (open/save panels) + std::string prompt; // Button label (NSSavePanel prompt) + std::string panel_message; // Panel message text (NSSavePanel message) + std::string directory; // Current directory URL path + + // NSSavePanel-specific properties + std::string name_field_label; // Label for the name field + std::string name_field_value; // Current value of the name field + bool shows_tag_field = true; + + // NSOpenPanel-specific properties + bool can_choose_files = false; + bool can_choose_directories = false; + bool allows_multiple_selection = false; + + // Shared panel properties (open and save) + bool shows_hidden_files = false; + bool resolves_aliases = true; + bool treats_packages_as_directories = false; + bool can_create_directories = false; +}; + +// Get information about the sheet dialog attached to the window identified +// by the given native handle buffer (NSView* on macOS). +DialogInfo GetDialogInfo(char* handle, size_t size); + +// Click a button at the given index on an NSAlert sheet attached to the window. +// Returns true if a message box was found and the button was clicked. +bool ClickMessageBoxButton(char* handle, size_t size, int button_index); + +// Toggle the checkbox (suppression button) on an NSAlert sheet. +// Returns true if a checkbox was found and clicked. +bool ClickCheckbox(char* handle, size_t size); + +// Cancel the file dialog (NSOpenPanel/NSSavePanel) sheet attached to the window. +// Returns true if a file dialog was found and cancelled. +bool CancelFileDialog(char* handle, size_t size); + +// Accept the file dialog sheet attached to the window. +// For save dialogs, |filename| is set in the name field before accepting. +// Returns true if a file dialog was found and accepted. +bool AcceptFileDialog(char* handle, size_t size, const std::string& filename); + +} // namespace dialog_helper + +#endif // SRC_DIALOG_HELPER_H_ diff --git a/spec/fixtures/native-addon/dialog-helper/src/dialog_helper_mac.mm b/spec/fixtures/native-addon/dialog-helper/src/dialog_helper_mac.mm new file mode 100644 index 0000000000000..3647e9728b469 --- /dev/null +++ b/spec/fixtures/native-addon/dialog-helper/src/dialog_helper_mac.mm @@ -0,0 +1,320 @@ +#include "dialog_helper.h" + +#import + +namespace { + +// Extract the NSWindow* from the native handle buffer. +// The buffer contains an NSView* (the content view of the window). +NSWindow* GetNSWindowFromHandle(char* handle, size_t size) { + if (size != sizeof(void*)) + return nil; + // Read the raw pointer from the buffer, then bridge to ARC. + void* raw = *reinterpret_cast(handle); + NSView* view = (__bridge NSView*)raw; + if (!view || ![view isKindOfClass:[NSView class]]) + return nil; + return [view window]; +} + +} // namespace + +namespace dialog_helper { + +DialogInfo GetDialogInfo(char* handle, size_t size) { + DialogInfo info; + info.type = "none"; + + NSWindow* window = GetNSWindowFromHandle(handle, size); + if (!window) + return info; + + NSWindow* sheet = [window attachedSheet]; + if (!sheet) + return info; + + // NSOpenPanel is a subclass of NSSavePanel, so check NSOpenPanel first. + if ([sheet isKindOfClass:[NSOpenPanel class]]) { + info.type = "open-dialog"; + NSOpenPanel* panel = (NSOpenPanel*)sheet; + info.message = [[panel title] UTF8String] ?: ""; + info.prompt = [[panel prompt] UTF8String] ?: ""; + info.panel_message = [[panel message] UTF8String] ?: ""; + if ([panel directoryURL]) + info.directory = [[[panel directoryURL] path] UTF8String] ?: ""; + info.can_choose_files = [panel canChooseFiles]; + info.can_choose_directories = [panel canChooseDirectories]; + info.allows_multiple_selection = [panel allowsMultipleSelection]; + info.shows_hidden_files = [panel showsHiddenFiles]; + info.resolves_aliases = [panel resolvesAliases]; + info.treats_packages_as_directories = [panel treatsFilePackagesAsDirectories]; + info.can_create_directories = [panel canCreateDirectories]; + return info; + } + + if ([sheet isKindOfClass:[NSSavePanel class]]) { + info.type = "save-dialog"; + NSSavePanel* panel = (NSSavePanel*)sheet; + info.message = [[panel title] UTF8String] ?: ""; + info.prompt = [[panel prompt] UTF8String] ?: ""; + info.panel_message = [[panel message] UTF8String] ?: ""; + if ([panel directoryURL]) + info.directory = [[[panel directoryURL] path] UTF8String] ?: ""; + info.name_field_label = [[panel nameFieldLabel] UTF8String] ?: ""; + info.name_field_value = [[panel nameFieldStringValue] UTF8String] ?: ""; + info.shows_tag_field = [panel showsTagField]; + info.shows_hidden_files = [panel showsHiddenFiles]; + info.treats_packages_as_directories = + [panel treatsFilePackagesAsDirectories]; + info.can_create_directories = [panel canCreateDirectories]; + return info; + } + + // For NSAlert, the sheet window is not an NSSavePanel. + // Check if it contains typical NSAlert button structure. + // NSAlert's window contains buttons as subviews in its content view. + NSView* contentView = [sheet contentView]; + NSMutableArray* buttons = [NSMutableArray array]; + + // Recursively find all NSButton instances in the view hierarchy. + NSMutableArray* stack = + [NSMutableArray arrayWithObject:contentView]; + while ([stack count] > 0) { + NSView* current = [stack lastObject]; + [stack removeLastObject]; + if ([current isKindOfClass:[NSButton class]]) { + NSButton* btn = (NSButton*)current; + // Filter to push-type buttons (not checkboxes, radio buttons, etc.) + if ([btn bezelStyle] == NSBezelStyleRounded || + [btn bezelStyle] == NSBezelStyleRegularSquare) { + [buttons addObject:btn]; + } + } + for (NSView* subview in [current subviews]) { + [stack addObject:subview]; + } + } + + if ([buttons count] > 0) { + info.type = "message-box"; + + // Sort buttons by tag to maintain the order they were added. + [buttons sortUsingComparator:^NSComparisonResult(NSButton* a, NSButton* b) { + if ([a tag] < [b tag]) + return NSOrderedAscending; + if ([a tag] > [b tag]) + return NSOrderedDescending; + return NSOrderedSame; + }]; + + std::string btn_json = "["; + for (NSUInteger i = 0; i < [buttons count]; i++) { + if (i > 0) + btn_json += ","; + btn_json += "\""; + NSString* title = [[buttons objectAtIndex:i] title]; + btn_json += [title UTF8String] ?: ""; + btn_json += "\""; + } + btn_json += "]"; + info.buttons = btn_json; + + // NSAlert's content view contains static NSTextFields for message and + // detail text. The first non-editable text field with content is the + // message; the second is the detail (informative text). + int text_field_index = 0; + // Walk all subviews (non-recursive — NSAlert places labels directly). + for (NSView* subview in [contentView subviews]) { + if ([subview isKindOfClass:[NSTextField class]]) { + NSTextField* field = (NSTextField*)subview; + if (![field isEditable] && [[field stringValue] length] > 0) { + if (text_field_index == 0) { + info.message = [[field stringValue] UTF8String]; + } else if (text_field_index == 1) { + info.detail = [[field stringValue] UTF8String]; + } + text_field_index++; + } + } + } + + // Check for the suppression (checkbox) button. + // NSAlert's suppression button is a non-bordered NSButton, unlike + // push buttons which are bordered. This reliably identifies it + // across macOS versions where the accessibility role may differ. + NSMutableArray* cbStack = + [NSMutableArray arrayWithObject:contentView]; + while ([cbStack count] > 0) { + NSView* current = [cbStack lastObject]; + [cbStack removeLastObject]; + if ([current isKindOfClass:[NSButton class]]) { + NSButton* btn = (NSButton*)current; + if (![btn isBordered]) { + NSString* title = [btn title]; + if (title && [title length] > 0) { + info.checkbox_label = [title UTF8String]; + info.checkbox_checked = + ([btn state] == NSControlStateValueOn); + } + } + } + for (NSView* sub in [current subviews]) { + [cbStack addObject:sub]; + } + } + } + + return info; +} + +bool ClickMessageBoxButton(char* handle, size_t size, int button_index) { + NSWindow* window = GetNSWindowFromHandle(handle, size); + if (!window) + return false; + + NSWindow* sheet = [window attachedSheet]; + if (!sheet) + return false; + + // Find buttons in the sheet, sorted by tag. + NSView* contentView = [sheet contentView]; + NSMutableArray* buttons = [NSMutableArray array]; + + NSMutableArray* stack = + [NSMutableArray arrayWithObject:contentView]; + while ([stack count] > 0) { + NSView* current = [stack lastObject]; + [stack removeLastObject]; + if ([current isKindOfClass:[NSButton class]]) { + NSButton* btn = (NSButton*)current; + if ([btn bezelStyle] == NSBezelStyleRounded || + [btn bezelStyle] == NSBezelStyleRegularSquare) { + [buttons addObject:btn]; + } + } + for (NSView* subview in [current subviews]) { + [stack addObject:subview]; + } + } + + [buttons sortUsingComparator:^NSComparisonResult(NSButton* a, NSButton* b) { + if ([a tag] < [b tag]) + return NSOrderedAscending; + if ([a tag] > [b tag]) + return NSOrderedDescending; + return NSOrderedSame; + }]; + + if (button_index < 0 || button_index >= (int)[buttons count]) + return false; + + NSButton* target = [buttons objectAtIndex:button_index]; + [target performClick:nil]; + return true; +} + +bool ClickCheckbox(char* handle, size_t size) { + NSWindow* window = GetNSWindowFromHandle(handle, size); + if (!window) + return false; + + NSWindow* sheet = [window attachedSheet]; + if (!sheet) + return false; + + // Find the suppression/checkbox button — it is a non-bordered NSButton, + // unlike the push buttons which are bordered. + NSView* contentView = [sheet contentView]; + NSMutableArray* stack = + [NSMutableArray arrayWithObject:contentView]; + while ([stack count] > 0) { + NSView* current = [stack lastObject]; + [stack removeLastObject]; + if ([current isKindOfClass:[NSButton class]]) { + NSButton* btn = (NSButton*)current; + if (![btn isBordered] && [[btn title] length] > 0) { + [btn performClick:nil]; + return true; + } + } + for (NSView* subview in [current subviews]) { + [stack addObject:subview]; + } + } + + return false; +} + +bool CancelFileDialog(char* handle, size_t size) { + NSWindow* window = GetNSWindowFromHandle(handle, size); + if (!window) + return false; + + NSWindow* sheet = [window attachedSheet]; + if (!sheet) + return false; + + // sheet is the NSSavePanel/NSOpenPanel window itself when presented as a + // sheet. We need to find the actual panel object. On macOS, when an + // NSSavePanel is run as a sheet, [window attachedSheet] returns the panel's + // window. The panel can be retrieved because NSSavePanel IS the window. + if ([sheet isKindOfClass:[NSSavePanel class]]) { + NSSavePanel* panel = (NSSavePanel*)sheet; + [panel cancel:nil]; + return true; + } + + // If it's not a recognized panel type, try ending the sheet directly. + [NSApp endSheet:sheet returnCode:NSModalResponseCancel]; + return true; +} + +bool AcceptFileDialog(char* handle, size_t size, const std::string& filename) { + NSWindow* window = GetNSWindowFromHandle(handle, size); + if (!window) + return false; + + NSWindow* sheet = [window attachedSheet]; + if (!sheet) + return false; + + if (![sheet isKindOfClass:[NSSavePanel class]]) + return false; + + NSSavePanel* panel = (NSSavePanel*)sheet; + + // Set the filename if provided (for save dialogs). + if (!filename.empty()) { + NSString* name = [NSString stringWithUTF8String:filename.c_str()]; + [panel setNameFieldStringValue:name]; + // Resign first responder to commit the name field edit. Without this, + // the panel may still use the previous value (e.g. "Untitled") when + // the accept button is clicked immediately after. + [sheet makeFirstResponder:nil]; + } + + NSView* contentView = [sheet contentView]; + + // Search for the default button (key equivalent "\r") in the view hierarchy. + NSMutableArray* stack = + [NSMutableArray arrayWithObject:contentView]; + while ([stack count] > 0) { + NSView* current = [stack lastObject]; + [stack removeLastObject]; + if ([current isKindOfClass:[NSButton class]]) { + NSButton* btn = (NSButton*)current; + if ([[btn keyEquivalent] isEqualToString:@"\r"]) { + [btn performClick:nil]; + return true; + } + } + for (NSView* subview in [current subviews]) { + [stack addObject:subview]; + } + } + + [NSApp endSheet:sheet returnCode:NSModalResponseOK]; + return true; +} + +} // namespace dialog_helper diff --git a/spec/fixtures/native-addon/dialog-helper/src/main.cc b/spec/fixtures/native-addon/dialog-helper/src/main.cc new file mode 100644 index 0000000000000..95a517564707b --- /dev/null +++ b/spec/fixtures/native-addon/dialog-helper/src/main.cc @@ -0,0 +1,231 @@ +#include +#include + +#include + +#include "dialog_helper.h" + +namespace { + +// Helper: extract (char* data, size_t length) from the first Buffer argument. +bool GetHandleArg(napi_env env, napi_callback_info info, size_t expected_argc, + napi_value* args, char** data, size_t* length) { + size_t argc = expected_argc; + napi_status status = napi_get_cb_info(env, info, &argc, args, NULL, NULL); + if (status != napi_ok || argc < 1) + return false; + + bool is_buffer; + status = napi_is_buffer(env, args[0], &is_buffer); + if (status != napi_ok || !is_buffer) { + napi_throw_error(env, NULL, "First argument must be a Buffer (native window handle)"); + return false; + } + + status = napi_get_buffer_info(env, args[0], (void**)data, length); + return status == napi_ok; +} + +napi_value GetDialogInfo(napi_env env, napi_callback_info info) { + napi_value args[1]; + char* data; + size_t length; + if (!GetHandleArg(env, info, 1, args, &data, &length)) + return NULL; + + dialog_helper::DialogInfo di = dialog_helper::GetDialogInfo(data, length); + + napi_value result; + napi_create_object(env, &result); + + // Message box properties + napi_value type_val; + napi_create_string_utf8(env, di.type.c_str(), di.type.size(), &type_val); + napi_set_named_property(env, result, "type", type_val); + + napi_value buttons_val; + napi_create_string_utf8(env, di.buttons.c_str(), di.buttons.size(), &buttons_val); + napi_set_named_property(env, result, "buttons", buttons_val); + + napi_value message_val; + napi_create_string_utf8(env, di.message.c_str(), di.message.size(), &message_val); + napi_set_named_property(env, result, "message", message_val); + + napi_value detail_val; + napi_create_string_utf8(env, di.detail.c_str(), di.detail.size(), &detail_val); + napi_set_named_property(env, result, "detail", detail_val); + + napi_value checkbox_label_val; + napi_create_string_utf8(env, di.checkbox_label.c_str(), + di.checkbox_label.size(), &checkbox_label_val); + napi_set_named_property(env, result, "checkboxLabel", checkbox_label_val); + + napi_value checkbox_checked_val; + napi_get_boolean(env, di.checkbox_checked, &checkbox_checked_val); + napi_set_named_property(env, result, "checkboxChecked", checkbox_checked_val); + + // File dialog properties + napi_value prompt_val; + napi_create_string_utf8(env, di.prompt.c_str(), di.prompt.size(), &prompt_val); + napi_set_named_property(env, result, "prompt", prompt_val); + + napi_value panel_message_val; + napi_create_string_utf8(env, di.panel_message.c_str(), + di.panel_message.size(), &panel_message_val); + napi_set_named_property(env, result, "panelMessage", panel_message_val); + + napi_value directory_val; + napi_create_string_utf8(env, di.directory.c_str(), di.directory.size(), + &directory_val); + napi_set_named_property(env, result, "directory", directory_val); + + // NSSavePanel-specific string/boolean properties + napi_value name_field_label_val; + napi_create_string_utf8(env, di.name_field_label.c_str(), + di.name_field_label.size(), &name_field_label_val); + napi_set_named_property(env, result, "nameFieldLabel", name_field_label_val); + + napi_value name_field_value_val; + napi_create_string_utf8(env, di.name_field_value.c_str(), + di.name_field_value.size(), &name_field_value_val); + napi_set_named_property(env, result, "nameFieldValue", name_field_value_val); + + napi_value shows_tag_field_val; + napi_get_boolean(env, di.shows_tag_field, &shows_tag_field_val); + napi_set_named_property(env, result, "showsTagField", shows_tag_field_val); + + // NSOpenPanel-specific properties + napi_value can_choose_files_val; + napi_get_boolean(env, di.can_choose_files, &can_choose_files_val); + napi_set_named_property(env, result, "canChooseFiles", can_choose_files_val); + + napi_value can_choose_dirs_val; + napi_get_boolean(env, di.can_choose_directories, &can_choose_dirs_val); + napi_set_named_property(env, result, "canChooseDirectories", + can_choose_dirs_val); + + napi_value allows_multi_val; + napi_get_boolean(env, di.allows_multiple_selection, &allows_multi_val); + napi_set_named_property(env, result, "allowsMultipleSelection", + allows_multi_val); + + // Shared panel properties (open and save) + napi_value shows_hidden_val; + napi_get_boolean(env, di.shows_hidden_files, &shows_hidden_val); + napi_set_named_property(env, result, "showsHiddenFiles", shows_hidden_val); + + napi_value resolves_aliases_val; + napi_get_boolean(env, di.resolves_aliases, &resolves_aliases_val); + napi_set_named_property(env, result, "resolvesAliases", resolves_aliases_val); + + napi_value treats_packages_val; + napi_get_boolean(env, di.treats_packages_as_directories, &treats_packages_val); + napi_set_named_property(env, result, "treatsPackagesAsDirectories", + treats_packages_val); + + napi_value can_create_dirs_val; + napi_get_boolean(env, di.can_create_directories, &can_create_dirs_val); + napi_set_named_property(env, result, "canCreateDirectories", + can_create_dirs_val); + + return result; +} + +napi_value ClickMessageBoxButton(napi_env env, napi_callback_info info) { + napi_value args[2]; + char* data; + size_t length; + if (!GetHandleArg(env, info, 2, args, &data, &length)) + return NULL; + + int32_t button_index; + napi_status status = napi_get_value_int32(env, args[1], &button_index); + if (status != napi_ok) { + napi_throw_error(env, NULL, "Second argument must be a number (button index)"); + return NULL; + } + + bool ok = dialog_helper::ClickMessageBoxButton(data, length, button_index); + + napi_value result; + napi_get_boolean(env, ok, &result); + return result; +} + +napi_value ClickCheckbox(napi_env env, napi_callback_info info) { + napi_value args[1]; + char* data; + size_t length; + if (!GetHandleArg(env, info, 1, args, &data, &length)) + return NULL; + + bool ok = dialog_helper::ClickCheckbox(data, length); + + napi_value result; + napi_get_boolean(env, ok, &result); + return result; +} + +napi_value CancelFileDialog(napi_env env, napi_callback_info info) { + napi_value args[1]; + char* data; + size_t length; + if (!GetHandleArg(env, info, 1, args, &data, &length)) + return NULL; + + bool ok = dialog_helper::CancelFileDialog(data, length); + + napi_value result; + napi_get_boolean(env, ok, &result); + return result; +} + +napi_value AcceptFileDialog(napi_env env, napi_callback_info info) { + napi_value args[2]; + char* data; + size_t length; + if (!GetHandleArg(env, info, 2, args, &data, &length)) + return NULL; + + std::string filename; + // Second argument (filename) is optional. + napi_valuetype vtype; + napi_typeof(env, args[1], &vtype); + if (vtype == napi_string) { + size_t str_len; + napi_get_value_string_utf8(env, args[1], NULL, 0, &str_len); + filename.resize(str_len); + napi_get_value_string_utf8(env, args[1], &filename[0], str_len + 1, + &str_len); + } + + bool ok = dialog_helper::AcceptFileDialog(data, length, filename); + + napi_value result; + napi_get_boolean(env, ok, &result); + return result; +} + +napi_value Init(napi_env env, napi_value exports) { + napi_property_descriptor descriptors[] = { + {"getDialogInfo", NULL, GetDialogInfo, NULL, NULL, NULL, + napi_enumerable, NULL}, + {"clickMessageBoxButton", NULL, ClickMessageBoxButton, NULL, NULL, NULL, + napi_enumerable, NULL}, + {"clickCheckbox", NULL, ClickCheckbox, NULL, NULL, NULL, + napi_enumerable, NULL}, + {"cancelFileDialog", NULL, CancelFileDialog, NULL, NULL, NULL, + napi_enumerable, NULL}, + {"acceptFileDialog", NULL, AcceptFileDialog, NULL, NULL, NULL, + napi_enumerable, NULL}, + }; + + napi_define_properties(env, exports, + sizeof(descriptors) / sizeof(*descriptors), + descriptors); + return exports; +} + +} // namespace + +NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) diff --git a/spec-main/fixtures/native-addon/echo/binding.cc b/spec/fixtures/native-addon/echo/binding.cc similarity index 100% rename from spec-main/fixtures/native-addon/echo/binding.cc rename to spec/fixtures/native-addon/echo/binding.cc diff --git a/spec-main/fixtures/native-addon/echo/binding.gyp b/spec/fixtures/native-addon/echo/binding.gyp similarity index 100% rename from spec-main/fixtures/native-addon/echo/binding.gyp rename to spec/fixtures/native-addon/echo/binding.gyp diff --git a/spec-main/fixtures/native-addon/echo/lib/echo.js b/spec/fixtures/native-addon/echo/lib/echo.js similarity index 100% rename from spec-main/fixtures/native-addon/echo/lib/echo.js rename to spec/fixtures/native-addon/echo/lib/echo.js diff --git a/spec/fixtures/native-addon/echo/package.json b/spec/fixtures/native-addon/echo/package.json new file mode 100644 index 0000000000000..d2028d65cfb91 --- /dev/null +++ b/spec/fixtures/native-addon/echo/package.json @@ -0,0 +1,8 @@ +{ + "name": "@electron-ci/echo", + "version": "0.0.1", + "main": "./lib/echo.js", + "scripts": { + "install": "node-gyp configure && node-gyp build" + } +} diff --git a/spec/fixtures/native-addon/external-ab/binding.cc b/spec/fixtures/native-addon/external-ab/binding.cc new file mode 100644 index 0000000000000..df1d52546c22b --- /dev/null +++ b/spec/fixtures/native-addon/external-ab/binding.cc @@ -0,0 +1,49 @@ +#include +#include +#include + +namespace { + +napi_value CreateBuffer(napi_env env, napi_callback_info info) { + v8::Isolate* isolate = v8::Isolate::TryGetCurrent(); + if (isolate == nullptr) { + return NULL; + } + + const size_t length = 4; + + uint8_t* data = new uint8_t[length]; + for (size_t i = 0; i < 4; i++) { + data[i] = static_cast(length); + } + + auto finalizer = [](char* data, void* hint) { + delete[] static_cast(reinterpret_cast(data)); + }; + + // NOTE: Buffer API is invoked directly rather than + // napi version to trigger the FATAL error from V8. + v8::MaybeLocal maybe = node::Buffer::New( + isolate, static_cast(reinterpret_cast(data)), length, + finalizer, nullptr); + + return reinterpret_cast(*maybe.ToLocalChecked()); +} + +napi_value Init(napi_env env, napi_value exports) { + napi_status status; + napi_property_descriptor descriptors[] = {{"createBuffer", NULL, CreateBuffer, + NULL, NULL, NULL, napi_default, + NULL}}; + + status = napi_define_properties( + env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors); + if (status != napi_ok) + return NULL; + + return exports; +} + +} // namespace + +NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) diff --git a/spec/fixtures/native-addon/external-ab/binding.gyp b/spec/fixtures/native-addon/external-ab/binding.gyp new file mode 100644 index 0000000000000..d8c4884bb9fef --- /dev/null +++ b/spec/fixtures/native-addon/external-ab/binding.gyp @@ -0,0 +1,10 @@ +{ + "targets": [ + { + "target_name": "external_ab", + "sources": [ + "binding.cc" + ] + } + ] +} diff --git a/spec/fixtures/native-addon/external-ab/lib/test-array-buffer.js b/spec/fixtures/native-addon/external-ab/lib/test-array-buffer.js new file mode 100644 index 0000000000000..ff2c1a8e72106 --- /dev/null +++ b/spec/fixtures/native-addon/external-ab/lib/test-array-buffer.js @@ -0,0 +1,5 @@ +'use strict'; + +const binding = require('../build/Release/external_ab.node'); + +binding.createBuffer(); diff --git a/spec/fixtures/native-addon/external-ab/package.json b/spec/fixtures/native-addon/external-ab/package.json new file mode 100644 index 0000000000000..45e66c31a5374 --- /dev/null +++ b/spec/fixtures/native-addon/external-ab/package.json @@ -0,0 +1,8 @@ +{ + "name": "@electron-ci/external-ab", + "version": "0.0.1", + "main": "./lib/test-array-buffer.js", + "scripts": { + "install": "node-gyp configure && node-gyp build" + } +} diff --git a/spec/fixtures/native-addon/is-valid-window/.gitignore b/spec/fixtures/native-addon/is-valid-window/.gitignore new file mode 100644 index 0000000000000..41912cdec36b3 --- /dev/null +++ b/spec/fixtures/native-addon/is-valid-window/.gitignore @@ -0,0 +1,7 @@ +/node_modules +/build +*.swp +*.log +*~ +.node-version +package-lock.json diff --git a/spec/fixtures/native-addon/is-valid-window/README.md b/spec/fixtures/native-addon/is-valid-window/README.md new file mode 100644 index 0000000000000..6727360b6adb0 --- /dev/null +++ b/spec/fixtures/native-addon/is-valid-window/README.md @@ -0,0 +1,8 @@ +# is-valid-window + +Validates if a pointer to window is valid. Used by Electron to validate the +result of `TopLevelWindow.getNativeWindowHandle`. + +## License + +Public domain. diff --git a/spec/fixtures/native-addon/is-valid-window/binding.gyp b/spec/fixtures/native-addon/is-valid-window/binding.gyp new file mode 100644 index 0000000000000..0de7c1f9d1719 --- /dev/null +++ b/spec/fixtures/native-addon/is-valid-window/binding.gyp @@ -0,0 +1,41 @@ +{ + 'target_defaults': { + 'conditions': [ + ['OS=="win"', { + 'msvs_disabled_warnings': [ + 4530, # C++ exception handler used, but unwind semantics are not enabled + 4506, # no definition for inline function + ], + }], + ], + }, + 'targets': [ + { + 'target_name': 'is_valid_window', + 'sources': [ + 'src/impl.h', + 'src/main.cc', + ], + 'conditions': [ + ['OS=="win"', { + 'sources': [ + 'src/impl_win.cc', + ], + }], + ['OS=="mac"', { + 'sources': [ + 'src/impl_darwin.mm', + ], + 'libraries': [ + '$(SDKROOT)/System/Library/Frameworks/AppKit.framework', + ], + }], + ['OS not in ["mac", "win"]', { + 'sources': [ + 'src/impl_posix.cc', + ], + }], + ], + } + ] +} diff --git a/spec/fixtures/native-addon/is-valid-window/lib/is-valid-window.js b/spec/fixtures/native-addon/is-valid-window/lib/is-valid-window.js new file mode 100644 index 0000000000000..e3154cbc3015f --- /dev/null +++ b/spec/fixtures/native-addon/is-valid-window/lib/is-valid-window.js @@ -0,0 +1 @@ +module.exports = require('../build/Release/is_valid_window.node').isValidWindow; diff --git a/spec/fixtures/native-addon/is-valid-window/package.json b/spec/fixtures/native-addon/is-valid-window/package.json new file mode 100644 index 0000000000000..51077b5f0f482 --- /dev/null +++ b/spec/fixtures/native-addon/is-valid-window/package.json @@ -0,0 +1,13 @@ +{ + "name": "@electron-ci/is-valid-window", + "version": "0.0.5", + "main": "./lib/is-valid-window.js", + "private": true, + "licenses": "MIT", + "dependencies": { + "nan": "2.x" + }, + "scripts": { + "install": "node-gyp configure && node-gyp build" + } +} diff --git a/spec/fixtures/native-addon/is-valid-window/src/impl.h b/spec/fixtures/native-addon/is-valid-window/src/impl.h new file mode 100644 index 0000000000000..b211ff05dc5d5 --- /dev/null +++ b/spec/fixtures/native-addon/is-valid-window/src/impl.h @@ -0,0 +1,12 @@ +#ifndef SRC_IMPL_H_ +#define SRC_IMPL_H_ + +#include + +namespace impl { + +bool IsValidWindow(char* handle, size_t size); + +} // namespace impl + +#endif // SRC_IMPL_H_ diff --git a/spec/fixtures/native-addon/is-valid-window/src/impl_darwin.mm b/spec/fixtures/native-addon/is-valid-window/src/impl_darwin.mm new file mode 100644 index 0000000000000..ef71aed16258d --- /dev/null +++ b/spec/fixtures/native-addon/is-valid-window/src/impl_darwin.mm @@ -0,0 +1,14 @@ +#include "impl.h" + +#include + +namespace impl { + +bool IsValidWindow(char* handle, size_t size) { + if (size != sizeof(NSView*)) + return false; + NSView* view = *reinterpret_cast(handle); + return [view isKindOfClass:[NSView class]]; +} + +} // namespace impl diff --git a/spec/fixtures/native-addon/is-valid-window/src/impl_posix.cc b/spec/fixtures/native-addon/is-valid-window/src/impl_posix.cc new file mode 100644 index 0000000000000..6c582b6ffb95f --- /dev/null +++ b/spec/fixtures/native-addon/is-valid-window/src/impl_posix.cc @@ -0,0 +1,9 @@ +#include "impl.h" + +namespace impl { + +bool IsValidWindow(char* handle, size_t size) { + return true; +} + +} // namespace impl diff --git a/spec/fixtures/native-addon/is-valid-window/src/impl_win.cc b/spec/fixtures/native-addon/is-valid-window/src/impl_win.cc new file mode 100644 index 0000000000000..91d272bdc5db1 --- /dev/null +++ b/spec/fixtures/native-addon/is-valid-window/src/impl_win.cc @@ -0,0 +1,14 @@ +#include "impl.h" + +#include + +namespace impl { + +bool IsValidWindow(char* handle, size_t size) { + if (size != sizeof(HWND)) + return false; + HWND window = *reinterpret_cast(handle); + return ::IsWindow(window); +} + +} // namespace impl diff --git a/spec/fixtures/native-addon/is-valid-window/src/main.cc b/spec/fixtures/native-addon/is-valid-window/src/main.cc new file mode 100644 index 0000000000000..b14e38b7d3d60 --- /dev/null +++ b/spec/fixtures/native-addon/is-valid-window/src/main.cc @@ -0,0 +1,56 @@ +#include +#include + +#include "impl.h" + +namespace { + +napi_value IsValidWindow(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value args[1], result; + napi_status status; + + status = napi_get_cb_info(env, info, &argc, args, NULL, NULL); + if (status != napi_ok) + return NULL; + + bool is_buffer; + status = napi_is_buffer(env, args[0], &is_buffer); + if (status != napi_ok) + return NULL; + + if (!is_buffer) { + napi_throw_error(env, NULL, "First argument must be Buffer"); + return NULL; + } + + char* data; + size_t length; + status = napi_get_buffer_info(env, args[0], (void**)&data, &length); + if (status != napi_ok) + return NULL; + + status = napi_get_boolean(env, impl::IsValidWindow(data, length), &result); + if (status != napi_ok) + return NULL; + + return result; +} + +napi_value Init(napi_env env, napi_value exports) { + napi_status status; + napi_property_descriptor descriptors[] = {{"isValidWindow", NULL, + IsValidWindow, NULL, NULL, NULL, + napi_default, NULL}}; + + status = napi_define_properties( + env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors); + if (status != napi_ok) + return NULL; + + return exports; +} + +} // namespace + +NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) diff --git a/spec/fixtures/native-addon/osr-gpu/binding.gyp b/spec/fixtures/native-addon/osr-gpu/binding.gyp new file mode 100644 index 0000000000000..21e840d0929e6 --- /dev/null +++ b/spec/fixtures/native-addon/osr-gpu/binding.gyp @@ -0,0 +1,16 @@ +{ + "targets": [ + { + "target_name": "osr-gpu", + "sources": ['napi_utils.h'], + "conditions": [ + ['OS=="win"', { + 'sources': ['binding_win.cc'], + 'link_settings': { + 'libraries': ['dxgi.lib', 'd3d11.lib', 'dxguid.lib'], + } + }], + ], + } + ] +} diff --git a/spec/fixtures/native-addon/osr-gpu/binding_win.cc b/spec/fixtures/native-addon/osr-gpu/binding_win.cc new file mode 100644 index 0000000000000..2545aade52156 --- /dev/null +++ b/spec/fixtures/native-addon/osr-gpu/binding_win.cc @@ -0,0 +1,197 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include "napi_utils.h" + +namespace { + +Microsoft::WRL::ComPtr device = nullptr; +Microsoft::WRL::ComPtr device1 = nullptr; +Microsoft::WRL::ComPtr context = nullptr; + +UINT cached_width = 0; +UINT cached_height = 0; +Microsoft::WRL::ComPtr cached_staging_texture = nullptr; + +napi_value ExtractPixels(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value args[1]; + napi_status status; + + status = napi_get_cb_info(env, info, &argc, args, NULL, NULL); + if (status != napi_ok) + return nullptr; + + if (argc != 1) { + napi_throw_error(env, nullptr, + "Wrong number of arguments, expected textureInfo"); + } + + auto textureInfo = args[0]; + + auto widgetType = NAPI_GET_PROPERTY_VALUE_STRING(textureInfo, "widgetType"); + auto pixelFormat = NAPI_GET_PROPERTY_VALUE_STRING(textureInfo, "pixelFormat"); + auto sharedTextureHandle = + NAPI_GET_PROPERTY_VALUE(textureInfo, "sharedTextureHandle"); + + size_t handleBufferSize; + uint8_t* handleBufferData; + napi_get_buffer_info(env, sharedTextureHandle, + reinterpret_cast(&handleBufferData), + &handleBufferSize); + + auto handle = *reinterpret_cast(handleBufferData); + std::cout << "ExtractPixels widgetType=" << widgetType + << " pixelFormat=" << pixelFormat + << " sharedTextureHandle=" << handle << std::endl; + + Microsoft::WRL::ComPtr shared_texture = nullptr; + HRESULT hr = + device1->OpenSharedResource1(handle, IID_PPV_ARGS(&shared_texture)); + if (FAILED(hr)) { + napi_throw_error(env, "osr-gpu", "Failed to open shared texture resource"); + return nullptr; + } + + // Extract the texture description + D3D11_TEXTURE2D_DESC desc; + shared_texture->GetDesc(&desc); + + // Cache the staging texture if it does not exist or size has changed + if (!cached_staging_texture || cached_width != desc.Width || + cached_height != desc.Height) { + if (cached_staging_texture) { + cached_staging_texture->Release(); + } + + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + desc.Usage = D3D11_USAGE_STAGING; + desc.BindFlags = 0; + desc.MiscFlags = 0; + + std::cout << "Create staging Texture2D width=" << desc.Width + << " height=" << desc.Height << std::endl; + hr = device->CreateTexture2D(&desc, nullptr, &cached_staging_texture); + if (FAILED(hr)) { + napi_throw_error(env, "osr-gpu", "Failed to create staging texture"); + return nullptr; + } + + cached_width = desc.Width; + cached_height = desc.Height; + } + + // Copy the shared texture to the staging texture + context->CopyResource(cached_staging_texture.Get(), shared_texture.Get()); + + // Calculate the size of the buffer needed to hold the pixel data + // 4 bytes per pixel + size_t bufferSize = desc.Width * desc.Height * 4; + + // Create a NAPI buffer to hold the pixel data + napi_value result; + void* resultData; + status = napi_create_buffer(env, bufferSize, &resultData, &result); + if (status != napi_ok) { + napi_throw_error(env, "osr-gpu", "Failed to create buffer"); + return nullptr; + } + + // Map the staging texture to read the pixel data + D3D11_MAPPED_SUBRESOURCE mappedResource; + hr = context->Map(cached_staging_texture.Get(), 0, D3D11_MAP_READ, 0, + &mappedResource); + if (FAILED(hr)) { + napi_throw_error(env, "osr-gpu", "Failed to map the staging texture"); + return nullptr; + } + + // Copy the pixel data from the mapped resource to the NAPI buffer + const uint8_t* srcData = static_cast(mappedResource.pData); + uint8_t* destData = static_cast(resultData); + for (UINT row = 0; row < desc.Height; ++row) { + memcpy(destData + row * desc.Width * 4, + srcData + row * mappedResource.RowPitch, desc.Width * 4); + } + + // Unmap the staging texture + context->Unmap(cached_staging_texture.Get(), 0); + return result; +} + +napi_value InitializeGpu(napi_env env, napi_callback_info info) { + HRESULT hr; + + // Feature levels supported + D3D_FEATURE_LEVEL feature_levels[] = {D3D_FEATURE_LEVEL_11_1}; + UINT num_feature_levels = ARRAYSIZE(feature_levels); + D3D_FEATURE_LEVEL feature_level; + + // This flag adds support for surfaces with a different color channel ordering + // than the default. It is required for compatibility with Direct2D. + UINT creation_flags = + D3D11_CREATE_DEVICE_BGRA_SUPPORT | D3D11_CREATE_DEVICE_DEBUG; + + // We need dxgi to share texture + Microsoft::WRL::ComPtr dxgi_factory = nullptr; + Microsoft::WRL::ComPtr adapter = nullptr; + hr = CreateDXGIFactory(IID_IDXGIFactory2, (void**)&dxgi_factory); + if (FAILED(hr)) { + napi_throw_error(env, "osr-gpu", "CreateDXGIFactory failed"); + return nullptr; + } + + hr = dxgi_factory->EnumAdapters(0, &adapter); + if (FAILED(hr)) { + napi_throw_error(env, "osr-gpu", "EnumAdapters failed"); + return nullptr; + } + + DXGI_ADAPTER_DESC adapter_desc; + adapter->GetDesc(&adapter_desc); + std::wcout << "Initializing DirectX with adapter: " + << adapter_desc.Description << std::endl; + + hr = D3D11CreateDevice(adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, + creation_flags, feature_levels, num_feature_levels, + D3D11_SDK_VERSION, &device, &feature_level, &context); + if (FAILED(hr)) { + napi_throw_error(env, "osr-gpu", "D3D11CreateDevice failed"); + return nullptr; + } + + hr = device->QueryInterface(IID_PPV_ARGS(&device1)); + if (FAILED(hr)) { + napi_throw_error(env, "osr-gpu", "Failed to open d3d11_1 device"); + return nullptr; + } + + return nullptr; +} + +napi_value Init(napi_env env, napi_value exports) { + napi_status status; + napi_property_descriptor descriptors[] = { + {"ExtractPixels", NULL, ExtractPixels, NULL, NULL, NULL, napi_default, + NULL}, + {"InitializeGpu", NULL, InitializeGpu, NULL, NULL, NULL, napi_default, + NULL}}; + + status = napi_define_properties( + env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors); + if (status != napi_ok) + return NULL; + + std::cout << "Initialized osr-gpu native module" << std::endl; + return exports; +} + +} // namespace + +NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) diff --git a/spec/fixtures/native-addon/osr-gpu/lib/osr-gpu.js b/spec/fixtures/native-addon/osr-gpu/lib/osr-gpu.js new file mode 100644 index 0000000000000..4f4ea51a8bec5 --- /dev/null +++ b/spec/fixtures/native-addon/osr-gpu/lib/osr-gpu.js @@ -0,0 +1 @@ +module.exports = require('../build/Release/osr-gpu.node'); diff --git a/spec/fixtures/native-addon/osr-gpu/napi_utils.h b/spec/fixtures/native-addon/osr-gpu/napi_utils.h new file mode 100644 index 0000000000000..40bcce30d9ad5 --- /dev/null +++ b/spec/fixtures/native-addon/osr-gpu/napi_utils.h @@ -0,0 +1,33 @@ +#define NAPI_CREATE_STRING(str) \ + [&]() { \ + napi_value value; \ + napi_create_string_utf8(env, str, NAPI_AUTO_LENGTH, &value); \ + return value; \ + }() + +#define NAPI_GET_PROPERTY_VALUE(obj, field) \ + [&]() { \ + napi_value value; \ + napi_get_property(env, obj, NAPI_CREATE_STRING(field), &value); \ + return value; \ + }() + +#define NAPI_GET_PROPERTY_VALUE_STRING(obj, field) \ + [&]() { \ + auto val = NAPI_GET_PROPERTY_VALUE(obj, field); \ + size_t size; \ + napi_get_value_string_utf8(env, val, nullptr, 0, &size); \ + char* buffer = new char[size + 1]; \ + napi_get_value_string_utf8(env, val, buffer, size + 1, &size); \ + return std::string(buffer); \ + }() + +#define NAPI_GET_PROPERTY_VALUE_BUFFER(obj, field) \ + [&]() { \ + auto val = NAPI_GET_PROPERTY_VALUE(obj, field); \ + size_t size; \ + napi_create_buffer(env, val, nullptr, 0, &size); \ + char* buffer = new char[size + 1]; \ + napi_get_value_string_utf8(env, val, buffer, size + 1, &size); \ + return std::string(buffer); \ + }() \ No newline at end of file diff --git a/spec/fixtures/native-addon/osr-gpu/package.json b/spec/fixtures/native-addon/osr-gpu/package.json new file mode 100644 index 0000000000000..e6974b1ccac19 --- /dev/null +++ b/spec/fixtures/native-addon/osr-gpu/package.json @@ -0,0 +1,9 @@ +{ + "name": "@electron-ci/osr-gpu", + "version": "0.0.1", + "main": "./lib/osr-gpu.js", + "private": true, + "scripts": { + "install": "node-gyp configure && node-gyp build" + } +} diff --git a/spec-main/fixtures/native-addon/uv-dlopen/binding.gyp b/spec/fixtures/native-addon/uv-dlopen/binding.gyp similarity index 100% rename from spec-main/fixtures/native-addon/uv-dlopen/binding.gyp rename to spec/fixtures/native-addon/uv-dlopen/binding.gyp diff --git a/spec/fixtures/native-addon/uv-dlopen/foo.cpp b/spec/fixtures/native-addon/uv-dlopen/foo.cpp new file mode 100644 index 0000000000000..7e2438f5006d2 --- /dev/null +++ b/spec/fixtures/native-addon/uv-dlopen/foo.cpp @@ -0,0 +1 @@ +extern "C" void foo() {} \ No newline at end of file diff --git a/spec/fixtures/native-addon/uv-dlopen/index.js b/spec/fixtures/native-addon/uv-dlopen/index.js new file mode 100644 index 0000000000000..c2761afc41578 --- /dev/null +++ b/spec/fixtures/native-addon/uv-dlopen/index.js @@ -0,0 +1,18 @@ +const path = require('node:path'); + +const testLoadLibrary = require('./build/Release/test_module'); + +const lib = (() => { + switch (process.platform) { + case 'linux': + return path.resolve(__dirname, 'build/Release/foo.so'); + case 'darwin': + return path.resolve(__dirname, 'build/Release/foo.dylib'); + case 'win32': + return path.resolve(__dirname, 'build/Release/libfoo.dll'); + default: + throw new Error('unsupported os'); + } +})(); + +testLoadLibrary(lib); diff --git a/spec-main/fixtures/native-addon/uv-dlopen/main.cpp b/spec/fixtures/native-addon/uv-dlopen/main.cpp similarity index 78% rename from spec-main/fixtures/native-addon/uv-dlopen/main.cpp rename to spec/fixtures/native-addon/uv-dlopen/main.cpp index 4d34850a6254c..5edef8a0ea627 100644 --- a/spec-main/fixtures/native-addon/uv-dlopen/main.cpp +++ b/spec/fixtures/native-addon/uv-dlopen/main.cpp @@ -8,22 +8,26 @@ napi_value TestLoadLibrary(napi_env env, napi_callback_info info) { napi_value argv; napi_status status; status = napi_get_cb_info(env, info, &argc, &argv, NULL, NULL); - if (status != napi_ok) napi_fatal_error(NULL, 0, NULL, 0); + if (status != napi_ok) + napi_fatal_error(NULL, 0, NULL, 0); char lib_path[256]; status = napi_get_value_string_utf8(env, argv, lib_path, 256, NULL); - if (status != napi_ok) napi_fatal_error(NULL, 0, NULL, 0); + if (status != napi_ok) + napi_fatal_error(NULL, 0, NULL, 0); uv_lib_t lib; auto uv_status = uv_dlopen(lib_path, &lib); if (uv_status == 0) { napi_value result; status = napi_get_boolean(env, true, &result); - if (status != napi_ok) napi_fatal_error(NULL, 0, NULL, 0); + if (status != napi_ok) + napi_fatal_error(NULL, 0, NULL, 0); return result; } else { status = napi_throw_error(env, NULL, uv_dlerror(&lib)); - if (status != napi_ok) napi_fatal_error(NULL, 0, NULL, 0); + if (status != napi_ok) + napi_fatal_error(NULL, 0, NULL, 0); } } diff --git a/spec/fixtures/native-addon/uv-dlopen/package.json b/spec/fixtures/native-addon/uv-dlopen/package.json new file mode 100644 index 0000000000000..90dcc00b53b95 --- /dev/null +++ b/spec/fixtures/native-addon/uv-dlopen/package.json @@ -0,0 +1,9 @@ +{ + "name": "@electron-ci/uv-dlopen", + "version": "0.0.1", + "main": "index.js", + "private": true, + "scripts": { + "install": "node-gyp configure && node-gyp build" + } +} diff --git a/spec/fixtures/no-proprietary-codecs.js b/spec/fixtures/no-proprietary-codecs.js index 0522847bb3ac1..9c8dbdde74dbf 100644 --- a/spec/fixtures/no-proprietary-codecs.js +++ b/spec/fixtures/no-proprietary-codecs.js @@ -5,7 +5,8 @@ // that does include proprietary codecs. const { app, BrowserWindow, ipcMain } = require('electron'); -const path = require('path'); + +const path = require('node:path'); const MEDIA_ERR_SRC_NOT_SUPPORTED = 4; const FIVE_MINUTES = 5 * 60 * 1000; @@ -16,12 +17,13 @@ app.whenReady().then(() => { window = new BrowserWindow({ show: false, webPreferences: { - nodeIntegration: true + nodeIntegration: true, + contextIsolation: false } }); - window.webContents.on('crashed', (event, killed) => { - console.log(`WebContents crashed (killed=${killed})`); + window.webContents.on('render-process-gone', (event, details) => { + console.log(`WebContents crashed ${JSON.stringify(details)}`); app.exit(1); }); diff --git a/spec/fixtures/pages/a.html b/spec/fixtures/pages/a.html index 675d81e97b724..060841461d40e 100644 --- a/spec/fixtures/pages/a.html +++ b/spec/fixtures/pages/a.html @@ -3,6 +3,7 @@ +
Hello World
+ + diff --git a/spec/fixtures/pages/basic-auth.html b/spec/fixtures/pages/basic-auth.html index ec9383ca4d083..9202396682b84 100644 --- a/spec/fixtures/pages/basic-auth.html +++ b/spec/fixtures/pages/basic-auth.html @@ -1,22 +1,21 @@ - diff --git a/spec/fixtures/pages/button.html b/spec/fixtures/pages/button.html new file mode 100644 index 0000000000000..79e2c06f56f71 --- /dev/null +++ b/spec/fixtures/pages/button.html @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/spec/fixtures/pages/cache-storage.html b/spec/fixtures/pages/cache-storage.html index 0b6717201e50e..e91cae61546e3 100644 --- a/spec/fixtures/pages/cache-storage.html +++ b/spec/fixtures/pages/cache-storage.html @@ -1,5 +1,5 @@ + + diff --git a/spec/fixtures/pages/datalist-text.html b/spec/fixtures/pages/datalist-text.html new file mode 100644 index 0000000000000..fc1d2c2801687 --- /dev/null +++ b/spec/fixtures/pages/datalist-text.html @@ -0,0 +1,15 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/spec/fixtures/pages/datalist-time.html b/spec/fixtures/pages/datalist-time.html new file mode 100644 index 0000000000000..f38766eb83bf7 --- /dev/null +++ b/spec/fixtures/pages/datalist-time.html @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/spec/fixtures/pages/dom-ready.html b/spec/fixtures/pages/dom-ready.html index 541852f9ab0c0..1d409eb9c6e84 100644 --- a/spec/fixtures/pages/dom-ready.html +++ b/spec/fixtures/pages/dom-ready.html @@ -1,8 +1,8 @@ - diff --git a/spec/fixtures/pages/draggable-page.html b/spec/fixtures/pages/draggable-page.html new file mode 100644 index 0000000000000..093d003bec790 --- /dev/null +++ b/spec/fixtures/pages/draggable-page.html @@ -0,0 +1,36 @@ + + + + + Draggable Page + + + + + + diff --git a/spec/fixtures/pages/fetch.html b/spec/fixtures/pages/fetch.html new file mode 100644 index 0000000000000..9e2ef6409579c --- /dev/null +++ b/spec/fixtures/pages/fetch.html @@ -0,0 +1,15 @@ + + + + + diff --git a/spec/fixtures/pages/file-input.html b/spec/fixtures/pages/file-input.html new file mode 100644 index 0000000000000..db3ffef5bdc29 --- /dev/null +++ b/spec/fixtures/pages/file-input.html @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/spec/fixtures/pages/flex-webview.html b/spec/fixtures/pages/flex-webview.html new file mode 100644 index 0000000000000..7d5369946c684 --- /dev/null +++ b/spec/fixtures/pages/flex-webview.html @@ -0,0 +1,15 @@ + diff --git a/spec/fixtures/pages/fullscreen-oopif.html b/spec/fixtures/pages/fullscreen-oopif.html index db9a24d77ff6c..70f487252386a 100644 --- a/spec/fixtures/pages/fullscreen-oopif.html +++ b/spec/fixtures/pages/fullscreen-oopif.html @@ -2,7 +2,7 @@ const { webFrame, ipcRenderer } = require('electron') document.addEventListener('fullscreenchange', () => { - ipcRenderer.send('fullscreenChange', webFrame.routingId) + ipcRenderer.send('fullscreenChange', webFrame.frameToken) }); window.addEventListener('message', ({ data }) => { diff --git a/spec/fixtures/pages/fullscreen.html b/spec/fixtures/pages/fullscreen.html index 4e5648e0194d2..ee8e403f43220 100644 --- a/spec/fixtures/pages/fullscreen.html +++ b/spec/fixtures/pages/fullscreen.html @@ -1 +1 @@ - + \ No newline at end of file diff --git a/spec/fixtures/pages/half-background-color.html b/spec/fixtures/pages/half-background-color.html new file mode 100644 index 0000000000000..07e5ccdcadf90 --- /dev/null +++ b/spec/fixtures/pages/half-background-color.html @@ -0,0 +1,20 @@ + + + + + + + + +
+ + diff --git a/spec/fixtures/pages/iframe-protocol.html b/spec/fixtures/pages/iframe-protocol.html new file mode 100644 index 0000000000000..a283115b19382 --- /dev/null +++ b/spec/fixtures/pages/iframe-protocol.html @@ -0,0 +1,11 @@ + + + + diff --git a/spec/fixtures/pages/iframe.html b/spec/fixtures/pages/iframe.html new file mode 100644 index 0000000000000..47b59ce0085b7 --- /dev/null +++ b/spec/fixtures/pages/iframe.html @@ -0,0 +1,27 @@ + + + + + iframe Host + + + + + + diff --git a/spec/fixtures/pages/jquery-3.6.0.min.js b/spec/fixtures/pages/jquery-3.6.0.min.js new file mode 100644 index 0000000000000..c4c6022f2982e --- /dev/null +++ b/spec/fixtures/pages/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 + + + + + + diff --git a/spec/fixtures/pages/key-events.html b/spec/fixtures/pages/key-events.html index 7402daf5e999f..c16c98bac2ed1 100644 --- a/spec/fixtures/pages/key-events.html +++ b/spec/fixtures/pages/key-events.html @@ -1,11 +1,17 @@ + diff --git a/spec/fixtures/pages/modal.html b/spec/fixtures/pages/modal.html new file mode 100644 index 0000000000000..28b9e6b2c95e2 --- /dev/null +++ b/spec/fixtures/pages/modal.html @@ -0,0 +1,26 @@ + + + + + +
+

+ +

+
+ + +
+
+
+ + + \ No newline at end of file diff --git a/spec/fixtures/pages/mouse-events.html b/spec/fixtures/pages/mouse-events.html new file mode 100644 index 0000000000000..51610f4a1e86e --- /dev/null +++ b/spec/fixtures/pages/mouse-events.html @@ -0,0 +1,20 @@ + + + + + + + + \ No newline at end of file diff --git a/spec/fixtures/pages/native-module.html b/spec/fixtures/pages/native-module.html index 78d928f2366c0..685b15d57d3c4 100644 --- a/spec/fixtures/pages/native-module.html +++ b/spec/fixtures/pages/native-module.html @@ -1,8 +1,8 @@ diff --git a/spec/fixtures/pages/navigate_in_page_and_wait.html b/spec/fixtures/pages/navigate_in_page_and_wait.html new file mode 100644 index 0000000000000..f582af55a5835 --- /dev/null +++ b/spec/fixtures/pages/navigate_in_page_and_wait.html @@ -0,0 +1,15 @@ + +
+ +
+ + + diff --git a/spec/fixtures/pages/navigation-history-anchor-in-page.html b/spec/fixtures/pages/navigation-history-anchor-in-page.html new file mode 100644 index 0000000000000..03406b81f2a39 --- /dev/null +++ b/spec/fixtures/pages/navigation-history-anchor-in-page.html @@ -0,0 +1,5 @@ + + + This is content. + + diff --git a/spec/fixtures/pages/overlay.html b/spec/fixtures/pages/overlay.html new file mode 100644 index 0000000000000..7ee96f59fd03e --- /dev/null +++ b/spec/fixtures/pages/overlay.html @@ -0,0 +1,84 @@ + + + + + + + + + +
+
+ Title goes here + +
+
+
+ + + diff --git a/spec-main/fixtures/pages/pdf-in-iframe.html b/spec/fixtures/pages/pdf-in-iframe.html similarity index 100% rename from spec-main/fixtures/pages/pdf-in-iframe.html rename to spec/fixtures/pages/pdf-in-iframe.html diff --git a/spec/fixtures/pages/send-after-node.html b/spec/fixtures/pages/send-after-node.html index 68f5a40b6707b..7a1ffa727cd9f 100644 --- a/spec/fixtures/pages/send-after-node.html +++ b/spec/fixtures/pages/send-after-node.html @@ -1,7 +1,7 @@ diff --git a/spec/fixtures/pages/service-worker/badge-index.html b/spec/fixtures/pages/service-worker/badge-index.html new file mode 100644 index 0000000000000..06df4b230387b --- /dev/null +++ b/spec/fixtures/pages/service-worker/badge-index.html @@ -0,0 +1,31 @@ + diff --git a/spec/fixtures/pages/service-worker/custom-scheme-index.html b/spec/fixtures/pages/service-worker/custom-scheme-index.html new file mode 100644 index 0000000000000..e5be928f04163 --- /dev/null +++ b/spec/fixtures/pages/service-worker/custom-scheme-index.html @@ -0,0 +1,21 @@ + diff --git a/docs/fiddles/menus/shortcuts/.keep b/spec/fixtures/pages/service-worker/empty.html similarity index 100% rename from docs/fiddles/menus/shortcuts/.keep rename to spec/fixtures/pages/service-worker/empty.html diff --git a/spec/fixtures/pages/service-worker/service-worker-badge.js b/spec/fixtures/pages/service-worker/service-worker-badge.js new file mode 100644 index 0000000000000..0f512f31e073a --- /dev/null +++ b/spec/fixtures/pages/service-worker/service-worker-badge.js @@ -0,0 +1,32 @@ +self.addEventListener('fetch', async function (event) { + const requestUrl = new URL(event.request.url); + let responseTxt; + if (requestUrl.pathname === '/echo' && event.request.headers.has('X-Mock-Response')) { + if (requestUrl.search === '?setBadge') { + if (navigator.setAppBadge()) { + try { + await navigator.setAppBadge(42); + responseTxt = 'SUCCESS setting app badge'; + await navigator.clearAppBadge(); + } catch (ex) { + responseTxt = 'ERROR setting app badge ' + ex; + } + } else { + responseTxt = 'ERROR navigator.setAppBadge is not available in ServiceWorker!'; + } + } else if (requestUrl.search === '?clearBadge') { + if (navigator.clearAppBadge()) { + try { + await navigator.clearAppBadge(); + responseTxt = 'SUCCESS clearing app badge'; + } catch (ex) { + responseTxt = 'ERROR clearing app badge ' + ex; + } + } else { + responseTxt = 'ERROR navigator.clearAppBadge is not available in ServiceWorker!'; + } + } + const mockResponse = new Response(responseTxt); + event.respondWith(mockResponse); + } +}); diff --git a/spec/fixtures/pages/service-worker/service-worker-intercepted.js b/spec/fixtures/pages/service-worker/service-worker-intercepted.js new file mode 100644 index 0000000000000..f0e9a78cfacd4 --- /dev/null +++ b/spec/fixtures/pages/service-worker/service-worker-intercepted.js @@ -0,0 +1,8 @@ +self.addEventListener('fetch', function (event) { + const requestUrl = new URL(event.request.url); + + if (requestUrl.pathname === '/echo' && event.request.headers.has('X-Mock-Response')) { + const mockResponse = new Response('Hello from serviceWorker intercepted!'); + event.respondWith(mockResponse); + } +}); diff --git a/spec/fixtures/pages/service-worker/service-worker.js b/spec/fixtures/pages/service-worker/service-worker.js index 1de4a9e4740eb..542011c89b811 100644 --- a/spec/fixtures/pages/service-worker/service-worker.js +++ b/spec/fixtures/pages/service-worker/service-worker.js @@ -1,8 +1,7 @@ self.addEventListener('fetch', function (event) { const requestUrl = new URL(event.request.url); - if (requestUrl.pathname === '/echo' && - event.request.headers.has('X-Mock-Response')) { + if (requestUrl.pathname === '/echo' && event.request.headers.has('X-Mock-Response')) { const mockResponse = new Response('Hello from serviceWorker!'); event.respondWith(mockResponse); } diff --git a/spec/fixtures/pages/service-worker/worker-no-node.js b/spec/fixtures/pages/service-worker/worker-no-node.js new file mode 100644 index 0000000000000..e22b7ca012cd8 --- /dev/null +++ b/spec/fixtures/pages/service-worker/worker-no-node.js @@ -0,0 +1,6 @@ +self.clients.matchAll({ includeUncontrolled: true }).then((clients) => { + if (!clients?.length) return; + + const msg = [typeof process, typeof setImmediate, typeof global, typeof Buffer].join(' '); + clients[0].postMessage(msg); +}); diff --git a/spec/fixtures/pages/shared_worker.html b/spec/fixtures/pages/shared_worker.html deleted file mode 100644 index 7a0d0757ab262..0000000000000 --- a/spec/fixtures/pages/shared_worker.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - diff --git a/spec/fixtures/pages/tab-focus-loop-elements.html b/spec/fixtures/pages/tab-focus-loop-elements.html index b10b6cba80796..16a91d2b36fe9 100644 --- a/spec/fixtures/pages/tab-focus-loop-elements.html +++ b/spec/fixtures/pages/tab-focus-loop-elements.html @@ -20,7 +20,7 @@
- +
diff --git a/spec/fixtures/pages/target-name.html b/spec/fixtures/pages/target-name.html deleted file mode 100644 index 0dc760d233f59..0000000000000 --- a/spec/fixtures/pages/target-name.html +++ /dev/null @@ -1,13 +0,0 @@ - - -link - - - diff --git a/spec/fixtures/pages/visibilitychange.html b/spec/fixtures/pages/visibilitychange.html index 0d4f07c46f933..3814475b5bdb5 100644 --- a/spec/fixtures/pages/visibilitychange.html +++ b/spec/fixtures/pages/visibilitychange.html @@ -3,10 +3,8 @@ diff --git a/spec-main/fixtures/pages/webview-devtools.html b/spec/fixtures/pages/webview-devtools.html similarity index 100% rename from spec-main/fixtures/pages/webview-devtools.html rename to spec/fixtures/pages/webview-devtools.html diff --git a/spec/fixtures/pages/webview-no-script.html b/spec/fixtures/pages/webview-no-script.html index 00b8f21bde70a..a7bece9a63371 100644 --- a/spec/fixtures/pages/webview-no-script.html +++ b/spec/fixtures/pages/webview-no-script.html @@ -1,5 +1,5 @@ - + diff --git a/spec/fixtures/pages/webview-trusted-types.html b/spec/fixtures/pages/webview-trusted-types.html new file mode 100644 index 0000000000000..328a2a3f4d3a1 --- /dev/null +++ b/spec/fixtures/pages/webview-trusted-types.html @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/spec/fixtures/pages/webview-will-navigate-in-frame.html b/spec/fixtures/pages/webview-will-navigate-in-frame.html new file mode 100644 index 0000000000000..63f921e724278 --- /dev/null +++ b/spec/fixtures/pages/webview-will-navigate-in-frame.html @@ -0,0 +1,12 @@ + + + + + diff --git a/spec/fixtures/pages/webview-zoom-change-persist-host.html b/spec/fixtures/pages/webview-zoom-change-persist-host.html new file mode 100644 index 0000000000000..6dd7787a6b9ca --- /dev/null +++ b/spec/fixtures/pages/webview-zoom-change-persist-host.html @@ -0,0 +1,31 @@ + + + + + + + + \ No newline at end of file diff --git a/spec/fixtures/pages/webview-zoom-factor.html b/spec/fixtures/pages/webview-zoom-factor.html index 006b416cfef58..354f114035d71 100644 --- a/spec/fixtures/pages/webview-zoom-factor.html +++ b/spec/fixtures/pages/webview-zoom-factor.html @@ -1,5 +1,5 @@ - + diff --git a/spec/fixtures/pages/webview.html b/spec/fixtures/pages/webview.html new file mode 100644 index 0000000000000..403672fffa16e --- /dev/null +++ b/spec/fixtures/pages/webview.html @@ -0,0 +1,26 @@ + + + + + webview Host + + + + + + diff --git a/spec/fixtures/pages/window-open-postMessage-driver.html b/spec/fixtures/pages/window-open-postMessage-driver.html index 89408b458458e..65f40417c74d0 100644 --- a/spec/fixtures/pages/window-open-postMessage-driver.html +++ b/spec/fixtures/pages/window-open-postMessage-driver.html @@ -1,5 +1,5 @@ + + diff --git a/spec/fixtures/pages/window-opener-targetOrigin.html b/spec/fixtures/pages/window-opener-targetOrigin.html index aa7e48ea0e862..b3304daca7dc0 100644 --- a/spec/fixtures/pages/window-opener-targetOrigin.html +++ b/spec/fixtures/pages/window-opener-targetOrigin.html @@ -1,19 +1,26 @@ + + diff --git a/spec/fixtures/pages/worker.html b/spec/fixtures/pages/worker.html index c84ef52065e02..95aceac6c08aa 100644 --- a/spec/fixtures/pages/worker.html +++ b/spec/fixtures/pages/worker.html @@ -4,7 +4,7 @@ const {ipcRenderer} = require('electron') let worker = new Worker(`../workers/worker_node.js`) worker.onmessage = function (event) { - ipcRenderer.sendToHost(event.data) + ipcRenderer.send('worker-result', event.data) worker.terminate() } diff --git a/spec/fixtures/pages/world-safe-preload-error.js b/spec/fixtures/pages/world-safe-preload-error.js index 160b37af7bf74..d3f2c8ce29116 100644 --- a/spec/fixtures/pages/world-safe-preload-error.js +++ b/spec/fixtures/pages/world-safe-preload-error.js @@ -1,10 +1,13 @@ const { ipcRenderer, webFrame } = require('electron'); -webFrame.executeJavaScript(`(() => { +webFrame + .executeJavaScript(`(() => { return Object(Symbol('a')); -})()`).catch((err) => { - // Considered safe if the object is constructed in this world - ipcRenderer.send('executejs-safe', err); -}).then(() => { - ipcRenderer.send('executejs-safe', null); -}); +})()`) + .catch((err) => { + // Considered safe if the object is constructed in this world + ipcRenderer.send('executejs-safe', err); + }) + .then(() => { + ipcRenderer.send('executejs-safe', null); + }); diff --git a/spec/fixtures/pages/world-safe-preload.js b/spec/fixtures/pages/world-safe-preload.js index 32f8be31bc878..f0cfd2cf0d1a9 100644 --- a/spec/fixtures/pages/world-safe-preload.js +++ b/spec/fixtures/pages/world-safe-preload.js @@ -1,8 +1,10 @@ const { ipcRenderer, webFrame } = require('electron'); -webFrame.executeJavaScript(`(() => { +webFrame + .executeJavaScript(`(() => { return {}; -})()`).then((obj) => { - // Considered safe if the object is constructed in this world - ipcRenderer.send('executejs-safe', obj.constructor === Object); -}); +})()`) + .then((obj) => { + // Considered safe if the object is constructed in this world + ipcRenderer.send('executejs-safe', obj.constructor === Object); + }); diff --git a/spec/fixtures/pages/zoom-factor.html b/spec/fixtures/pages/zoom-factor.html index c27b5ea495a4e..4c490bceeac69 100644 --- a/spec/fixtures/pages/zoom-factor.html +++ b/spec/fixtures/pages/zoom-factor.html @@ -1,8 +1,10 @@ diff --git a/spec/fixtures/preload-expose-ipc.js b/spec/fixtures/preload-expose-ipc.js new file mode 100644 index 0000000000000..4fcce68114dbb --- /dev/null +++ b/spec/fixtures/preload-expose-ipc.js @@ -0,0 +1,14 @@ +const { contextBridge, ipcRenderer } = require('electron'); + +// NOTE: Never do this in an actual app! Very insecure! +contextBridge.exposeInMainWorld('ipc', { + send(...args) { + return ipcRenderer.send(...args); + }, + sendSync(...args) { + return ipcRenderer.sendSync(...args); + }, + invoke(...args) { + return ipcRenderer.invoke(...args); + } +}); diff --git a/spec/fixtures/recursive-asar/a.asar b/spec/fixtures/recursive-asar/a.asar new file mode 100644 index 0000000000000..852f460b6d548 Binary files /dev/null and b/spec/fixtures/recursive-asar/a.asar differ diff --git a/spec/fixtures/recursive-asar/nested/hello.txt b/spec/fixtures/recursive-asar/nested/hello.txt new file mode 100644 index 0000000000000..ec68ffb2b629c --- /dev/null +++ b/spec/fixtures/recursive-asar/nested/hello.txt @@ -0,0 +1 @@ +goodbye! \ No newline at end of file diff --git a/spec/fixtures/recursive-asar/test.txt b/spec/fixtures/recursive-asar/test.txt new file mode 100644 index 0000000000000..05a682bd4e7c7 --- /dev/null +++ b/spec/fixtures/recursive-asar/test.txt @@ -0,0 +1 @@ +Hello! \ No newline at end of file diff --git a/spec/fixtures/release-notes/cache/electron-electron-commit-029127a8b6f7c511fca4612748ad5b50e43aadaa b/spec/fixtures/release-notes/cache/electron-electron-commit-029127a8b6f7c511fca4612748ad5b50e43aadaa new file mode 100644 index 0000000000000..21e88cd9e01bf --- /dev/null +++ b/spec/fixtures/release-notes/cache/electron-electron-commit-029127a8b6f7c511fca4612748ad5b50e43aadaa @@ -0,0 +1 @@ +{"status":200,"url":"https://api.github.com/repos/electron/electron/commits/029127a8b6f7c511fca4612748ad5b50e43aadaa/pulls","headers":{"accept-ranges":"bytes","access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","cache-control":"public, max-age=60, s-maxage=60","content-encoding":"gzip","content-length":"2717","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Fri, 20 Sep 2024 04:00:37 GMT","etag":"W/\"80e2d0edebd07c0cf53916bf23fee37544d3eb301e1a65595fff37115a465eae\"","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept,Accept-Encoding, Accept, X-Requested-With","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"C623:36E55D:247B2AD:4558739:66ECF364","x-ratelimit-limit":"60","x-ratelimit-remaining":"50","x-ratelimit-reset":"1726805543","x-ratelimit-resource":"core","x-ratelimit-used":"10","x-xss-protection":"0"},"data":[{"url":"https://api.github.com/repos/electron/electron/pulls/39745","id":1504592750,"node_id":"PR_kwDOAI8xS85ZrkNu","html_url":"https://github.com/electron/electron/pull/39745","diff_url":"https://github.com/electron/electron/pull/39745.diff","patch_url":"https://github.com/electron/electron/pull/39745.patch","issue_url":"https://api.github.com/repos/electron/electron/issues/39745","number":39745,"state":"closed","locked":false,"title":"chore: bump chromium to 118.0.5993.0 (main)","user":{"login":"electron-roller[bot]","id":84116207,"node_id":"MDM6Qm90ODQxMTYyMDc=","avatar_url":"https://avatars.githubusercontent.com/in/115177?v=4","gravatar_id":"","url":"https://api.github.com/users/electron-roller%5Bbot%5D","html_url":"https://github.com/apps/electron-roller","followers_url":"https://api.github.com/users/electron-roller%5Bbot%5D/followers","following_url":"https://api.github.com/users/electron-roller%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/electron-roller%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/electron-roller%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron-roller%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/electron-roller%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/electron-roller%5Bbot%5D/repos","events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/received_events","type":"Bot","site_admin":false},"body":"Updating Chromium to 118.0.5993.0.\n\nSee [all changes in 118.0.5991.0..118.0.5993.0](https://chromium.googlesource.com/chromium/src/+log/118.0.5991.0..118.0.5993.0?n=10000&pretty=fuller)\n\n\n\nNotes: Updated Chromium to 118.0.5993.0.","created_at":"2023-09-06T13:00:33Z","updated_at":"2023-09-06T23:28:42Z","closed_at":"2023-09-06T23:27:26Z","merged_at":"2023-09-06T23:27:26Z","merge_commit_sha":"029127a8b6f7c511fca4612748ad5b50e43aadaa","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":1034512799,"node_id":"MDU6TGFiZWwxMDM0NTEyNzk5","url":"https://api.github.com/repos/electron/electron/labels/semver/patch","name":"semver/patch","color":"6ac2dd","default":false,"description":"backwards-compatible bug fixes"},{"id":1243058793,"node_id":"MDU6TGFiZWwxMjQzMDU4Nzkz","url":"https://api.github.com/repos/electron/electron/labels/new-pr%20%F0%9F%8C%B1","name":"new-pr 🌱","color":"8af297","default":false,"description":"PR opened in the last 24 hours"},{"id":2968604945,"node_id":"MDU6TGFiZWwyOTY4NjA0OTQ1","url":"https://api.github.com/repos/electron/electron/labels/no-backport","name":"no-backport","color":"CB07C4","default":false,"description":""}],"milestone":null,"draft":false,"commits_url":"https://api.github.com/repos/electron/electron/pulls/39745/commits","review_comments_url":"https://api.github.com/repos/electron/electron/pulls/39745/comments","review_comment_url":"https://api.github.com/repos/electron/electron/pulls/comments{/number}","comments_url":"https://api.github.com/repos/electron/electron/issues/39745/comments","statuses_url":"https://api.github.com/repos/electron/electron/statuses/7ba0be830a247d916c05d2471c5ce214d2598476","head":{"label":"electron:roller/chromium/main","ref":"roller/chromium/main","sha":"7ba0be830a247d916c05d2471c5ce214d2598476","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"base":{"label":"electron:main","ref":"main","sha":"34b79c15c2f2de2fa514538b7ccb4b3c473808ae","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"_links":{"self":{"href":"https://api.github.com/repos/electron/electron/pulls/39745"},"html":{"href":"https://github.com/electron/electron/pull/39745"},"issue":{"href":"https://api.github.com/repos/electron/electron/issues/39745"},"comments":{"href":"https://api.github.com/repos/electron/electron/issues/39745/comments"},"review_comments":{"href":"https://api.github.com/repos/electron/electron/pulls/39745/comments"},"review_comment":{"href":"https://api.github.com/repos/electron/electron/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/electron/electron/pulls/39745/commits"},"statuses":{"href":"https://api.github.com/repos/electron/electron/statuses/7ba0be830a247d916c05d2471c5ce214d2598476"}},"author_association":"CONTRIBUTOR","auto_merge":null,"active_lock_reason":null}]} \ No newline at end of file diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-commit-0600420bac25439fc2067d51c6aaa4ee11770577 b/spec/fixtures/release-notes/cache/electron-electron-commit-0600420bac25439fc2067d51c6aaa4ee11770577 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-commit-0600420bac25439fc2067d51c6aaa4ee11770577 rename to spec/fixtures/release-notes/cache/electron-electron-commit-0600420bac25439fc2067d51c6aaa4ee11770577 diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-commit-2955c67c4ea712fa22773ac9113709fc952bfd49 b/spec/fixtures/release-notes/cache/electron-electron-commit-2955c67c4ea712fa22773ac9113709fc952bfd49 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-commit-2955c67c4ea712fa22773ac9113709fc952bfd49 rename to spec/fixtures/release-notes/cache/electron-electron-commit-2955c67c4ea712fa22773ac9113709fc952bfd49 diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-commit-2fad53e66b1a2cb6f7dad88fe9bb62d7a461fe98 b/spec/fixtures/release-notes/cache/electron-electron-commit-2fad53e66b1a2cb6f7dad88fe9bb62d7a461fe98 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-commit-2fad53e66b1a2cb6f7dad88fe9bb62d7a461fe98 rename to spec/fixtures/release-notes/cache/electron-electron-commit-2fad53e66b1a2cb6f7dad88fe9bb62d7a461fe98 diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-commit-467409458e716c68b35fa935d556050ca6bed1c4 b/spec/fixtures/release-notes/cache/electron-electron-commit-467409458e716c68b35fa935d556050ca6bed1c4 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-commit-467409458e716c68b35fa935d556050ca6bed1c4 rename to spec/fixtures/release-notes/cache/electron-electron-commit-467409458e716c68b35fa935d556050ca6bed1c4 diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-commit-61dc1c88fd34a3e8fff80c80ed79d0455970e610 b/spec/fixtures/release-notes/cache/electron-electron-commit-61dc1c88fd34a3e8fff80c80ed79d0455970e610 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-commit-61dc1c88fd34a3e8fff80c80ed79d0455970e610 rename to spec/fixtures/release-notes/cache/electron-electron-commit-61dc1c88fd34a3e8fff80c80ed79d0455970e610 diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-commit-89eb309d0b22bd4aec058ffaf983e81e56a5c378 b/spec/fixtures/release-notes/cache/electron-electron-commit-89eb309d0b22bd4aec058ffaf983e81e56a5c378 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-commit-89eb309d0b22bd4aec058ffaf983e81e56a5c378 rename to spec/fixtures/release-notes/cache/electron-electron-commit-89eb309d0b22bd4aec058ffaf983e81e56a5c378 diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-commit-8bc0c92137f4a77dc831ca644a86a3e48b51a11e b/spec/fixtures/release-notes/cache/electron-electron-commit-8bc0c92137f4a77dc831ca644a86a3e48b51a11e similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-commit-8bc0c92137f4a77dc831ca644a86a3e48b51a11e rename to spec/fixtures/release-notes/cache/electron-electron-commit-8bc0c92137f4a77dc831ca644a86a3e48b51a11e diff --git a/spec/fixtures/release-notes/cache/electron-electron-commit-8f7a48879ef8633a76279803637cdee7f7c6cd4f b/spec/fixtures/release-notes/cache/electron-electron-commit-8f7a48879ef8633a76279803637cdee7f7c6cd4f new file mode 100644 index 0000000000000..ef8d9b637caed --- /dev/null +++ b/spec/fixtures/release-notes/cache/electron-electron-commit-8f7a48879ef8633a76279803637cdee7f7c6cd4f @@ -0,0 +1 @@ +{"status":200,"url":"https://api.github.com/repos/electron/electron/commits/8f7a48879ef8633a76279803637cdee7f7c6cd4f/pulls","headers":{"accept-ranges":"bytes","access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","cache-control":"public, max-age=60, s-maxage=60","content-encoding":"gzip","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Fri, 20 Sep 2024 04:00:38 GMT","etag":"W/\"fc25a1c4edee51c7c227cdb578189b0196dfeea4976c22509630ee1fc0b75919\"","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","transfer-encoding":"chunked","vary":"Accept,Accept-Encoding, Accept, X-Requested-With","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"C623:36E55D:247B7DF:45590F1:66ECF366","x-ratelimit-limit":"60","x-ratelimit-remaining":"43","x-ratelimit-reset":"1726805543","x-ratelimit-resource":"core","x-ratelimit-used":"17","x-xss-protection":"0"},"data":[{"url":"https://api.github.com/repos/electron/electron/pulls/40076","id":1539965204,"node_id":"PR_kwDOAI8xS85bygEU","html_url":"https://github.com/electron/electron/pull/40076","diff_url":"https://github.com/electron/electron/pull/40076.diff","patch_url":"https://github.com/electron/electron/pull/40076.patch","issue_url":"https://api.github.com/repos/electron/electron/issues/40076","number":40076,"state":"closed","locked":false,"title":"chore: bump chromium to 119.0.6045.0 (main)","user":{"login":"electron-roller[bot]","id":84116207,"node_id":"MDM6Qm90ODQxMTYyMDc=","avatar_url":"https://avatars.githubusercontent.com/in/115177?v=4","gravatar_id":"","url":"https://api.github.com/users/electron-roller%5Bbot%5D","html_url":"https://github.com/apps/electron-roller","followers_url":"https://api.github.com/users/electron-roller%5Bbot%5D/followers","following_url":"https://api.github.com/users/electron-roller%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/electron-roller%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/electron-roller%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron-roller%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/electron-roller%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/electron-roller%5Bbot%5D/repos","events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/received_events","type":"Bot","site_admin":false},"body":"Updating Chromium to 119.0.6045.0.\r\n\r\nSee [all changes in 119.0.6043.0..119.0.6045.0](https://chromium.googlesource.com/chromium/src/+log/119.0.6043.0..119.0.6045.0?n=10000&pretty=fuller)\r\n\r\n\r\n\r\nNotes: Updated Chromium to 119.0.6045.0.","created_at":"2023-10-03T13:00:35Z","updated_at":"2023-10-06T00:56:09Z","closed_at":"2023-10-05T23:59:40Z","merged_at":"2023-10-05T23:59:40Z","merge_commit_sha":"8f7a48879ef8633a76279803637cdee7f7c6cd4f","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":1034512799,"node_id":"MDU6TGFiZWwxMDM0NTEyNzk5","url":"https://api.github.com/repos/electron/electron/labels/semver/patch","name":"semver/patch","color":"6ac2dd","default":false,"description":"backwards-compatible bug fixes"},{"id":1648234711,"node_id":"MDU6TGFiZWwxNjQ4MjM0NzEx","url":"https://api.github.com/repos/electron/electron/labels/roller/pause","name":"roller/pause","color":"fbca04","default":false,"description":""},{"id":2968604945,"node_id":"MDU6TGFiZWwyOTY4NjA0OTQ1","url":"https://api.github.com/repos/electron/electron/labels/no-backport","name":"no-backport","color":"CB07C4","default":false,"description":""}],"milestone":null,"draft":false,"commits_url":"https://api.github.com/repos/electron/electron/pulls/40076/commits","review_comments_url":"https://api.github.com/repos/electron/electron/pulls/40076/comments","review_comment_url":"https://api.github.com/repos/electron/electron/pulls/comments{/number}","comments_url":"https://api.github.com/repos/electron/electron/issues/40076/comments","statuses_url":"https://api.github.com/repos/electron/electron/statuses/6a695f015bac8388dc450b46f548288bff58a433","head":{"label":"electron:roller/chromium/main","ref":"roller/chromium/main","sha":"6a695f015bac8388dc450b46f548288bff58a433","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"base":{"label":"electron:main","ref":"main","sha":"3392d9a2e74973960ca516adc1c1684e03f78414","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"_links":{"self":{"href":"https://api.github.com/repos/electron/electron/pulls/40076"},"html":{"href":"https://github.com/electron/electron/pull/40076"},"issue":{"href":"https://api.github.com/repos/electron/electron/issues/40076"},"comments":{"href":"https://api.github.com/repos/electron/electron/issues/40076/comments"},"review_comments":{"href":"https://api.github.com/repos/electron/electron/pulls/40076/comments"},"review_comment":{"href":"https://api.github.com/repos/electron/electron/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/electron/electron/pulls/40076/commits"},"statuses":{"href":"https://api.github.com/repos/electron/electron/statuses/6a695f015bac8388dc450b46f548288bff58a433"}},"author_association":"CONTRIBUTOR","auto_merge":null,"active_lock_reason":null}]} \ No newline at end of file diff --git a/spec/fixtures/release-notes/cache/electron-electron-commit-9d0e6d09f0be0abbeae46dd3d66afd96d2daacaa b/spec/fixtures/release-notes/cache/electron-electron-commit-9d0e6d09f0be0abbeae46dd3d66afd96d2daacaa new file mode 100644 index 0000000000000..eb9fbc660d103 --- /dev/null +++ b/spec/fixtures/release-notes/cache/electron-electron-commit-9d0e6d09f0be0abbeae46dd3d66afd96d2daacaa @@ -0,0 +1 @@ +{"status":200,"url":"https://api.github.com/repos/electron/electron/commits/9d0e6d09f0be0abbeae46dd3d66afd96d2daacaa/pulls","headers":{"accept-ranges":"bytes","access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","cache-control":"public, max-age=60, s-maxage=60","content-encoding":"gzip","content-length":"2667","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Fri, 20 Sep 2024 04:00:37 GMT","etag":"W/\"1467bf4bc68e3bbb5c598d01f59d72ae71f38c1e45f7a20c7397ada84fbbb80c\"","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept,Accept-Encoding, Accept, X-Requested-With","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"C623:36E55D:247B4A7:4558AB7:66ECF365","x-ratelimit-limit":"60","x-ratelimit-remaining":"48","x-ratelimit-reset":"1726805543","x-ratelimit-resource":"core","x-ratelimit-used":"12","x-xss-protection":"0"},"data":[{"url":"https://api.github.com/repos/electron/electron/pulls/40045","id":1535161486,"node_id":"PR_kwDOAI8xS85bgLSO","html_url":"https://github.com/electron/electron/pull/40045","diff_url":"https://github.com/electron/electron/pull/40045.diff","patch_url":"https://github.com/electron/electron/pull/40045.patch","issue_url":"https://api.github.com/repos/electron/electron/issues/40045","number":40045,"state":"closed","locked":false,"title":"chore: bump chromium to 119.0.6043.0 (main)","user":{"login":"electron-roller[bot]","id":84116207,"node_id":"MDM6Qm90ODQxMTYyMDc=","avatar_url":"https://avatars.githubusercontent.com/in/115177?v=4","gravatar_id":"","url":"https://api.github.com/users/electron-roller%5Bbot%5D","html_url":"https://github.com/apps/electron-roller","followers_url":"https://api.github.com/users/electron-roller%5Bbot%5D/followers","following_url":"https://api.github.com/users/electron-roller%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/electron-roller%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/electron-roller%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron-roller%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/electron-roller%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/electron-roller%5Bbot%5D/repos","events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/received_events","type":"Bot","site_admin":false},"body":"Updating Chromium to 119.0.6043.0.\n\nSee [all changes in 119.0.6029.0..119.0.6043.0](https://chromium.googlesource.com/chromium/src/+log/119.0.6029.0..119.0.6043.0?n=10000&pretty=fuller)\n\n\n\nNotes: Updated Chromium to 119.0.6043.0.","created_at":"2023-09-29T05:27:06Z","updated_at":"2023-10-02T22:01:11Z","closed_at":"2023-10-02T22:01:07Z","merged_at":"2023-10-02T22:01:07Z","merge_commit_sha":"9d0e6d09f0be0abbeae46dd3d66afd96d2daacaa","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":1034512799,"node_id":"MDU6TGFiZWwxMDM0NTEyNzk5","url":"https://api.github.com/repos/electron/electron/labels/semver/patch","name":"semver/patch","color":"6ac2dd","default":false,"description":"backwards-compatible bug fixes"},{"id":1648234711,"node_id":"MDU6TGFiZWwxNjQ4MjM0NzEx","url":"https://api.github.com/repos/electron/electron/labels/roller/pause","name":"roller/pause","color":"fbca04","default":false,"description":""},{"id":2968604945,"node_id":"MDU6TGFiZWwyOTY4NjA0OTQ1","url":"https://api.github.com/repos/electron/electron/labels/no-backport","name":"no-backport","color":"CB07C4","default":false,"description":""}],"milestone":null,"draft":false,"commits_url":"https://api.github.com/repos/electron/electron/pulls/40045/commits","review_comments_url":"https://api.github.com/repos/electron/electron/pulls/40045/comments","review_comment_url":"https://api.github.com/repos/electron/electron/pulls/comments{/number}","comments_url":"https://api.github.com/repos/electron/electron/issues/40045/comments","statuses_url":"https://api.github.com/repos/electron/electron/statuses/6fcb6a8d7ffc0b57f8d161bbdd9ff87a3dd5e934","head":{"label":"electron:roller/chromium/main","ref":"roller/chromium/main","sha":"6fcb6a8d7ffc0b57f8d161bbdd9ff87a3dd5e934","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"base":{"label":"electron:main","ref":"main","sha":"503ae86ab216406485bf437969da8c56266c3346","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"_links":{"self":{"href":"https://api.github.com/repos/electron/electron/pulls/40045"},"html":{"href":"https://github.com/electron/electron/pull/40045"},"issue":{"href":"https://api.github.com/repos/electron/electron/issues/40045"},"comments":{"href":"https://api.github.com/repos/electron/electron/issues/40045/comments"},"review_comments":{"href":"https://api.github.com/repos/electron/electron/pulls/40045/comments"},"review_comment":{"href":"https://api.github.com/repos/electron/electron/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/electron/electron/pulls/40045/commits"},"statuses":{"href":"https://api.github.com/repos/electron/electron/statuses/6fcb6a8d7ffc0b57f8d161bbdd9ff87a3dd5e934"}},"author_association":"CONTRIBUTOR","auto_merge":null,"active_lock_reason":null}]} \ No newline at end of file diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-commit-a6ff42c190cb5caf8f3e217748e49183a951491b b/spec/fixtures/release-notes/cache/electron-electron-commit-a6ff42c190cb5caf8f3e217748e49183a951491b similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-commit-a6ff42c190cb5caf8f3e217748e49183a951491b rename to spec/fixtures/release-notes/cache/electron-electron-commit-a6ff42c190cb5caf8f3e217748e49183a951491b diff --git a/spec/fixtures/release-notes/cache/electron-electron-commit-d6c8ff2e7050f30dffd784915bcbd2a9f993cdb2 b/spec/fixtures/release-notes/cache/electron-electron-commit-d6c8ff2e7050f30dffd784915bcbd2a9f993cdb2 new file mode 100644 index 0000000000000..a8852cb648f68 --- /dev/null +++ b/spec/fixtures/release-notes/cache/electron-electron-commit-d6c8ff2e7050f30dffd784915bcbd2a9f993cdb2 @@ -0,0 +1 @@ +{"status":200,"url":"https://api.github.com/repos/electron/electron/commits/d6c8ff2e7050f30dffd784915bcbd2a9f993cdb2/pulls","headers":{"accept-ranges":"bytes","access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","cache-control":"public, max-age=60, s-maxage=60","content-encoding":"gzip","content-length":"2656","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Fri, 20 Sep 2024 04:00:37 GMT","etag":"W/\"b1a96400c9529932fb835905524621cae9010fe39a87e5b4720587f8f5f1bf99\"","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept,Accept-Encoding, Accept, X-Requested-With","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"C623:36E55D:247B56F:4558C56:66ECF365","x-ratelimit-limit":"60","x-ratelimit-remaining":"47","x-ratelimit-reset":"1726805543","x-ratelimit-resource":"core","x-ratelimit-used":"13","x-xss-protection":"0"},"data":[{"url":"https://api.github.com/repos/electron/electron/pulls/39944","id":1524826900,"node_id":"PR_kwDOAI8xS85a4wMU","html_url":"https://github.com/electron/electron/pull/39944","diff_url":"https://github.com/electron/electron/pull/39944.diff","patch_url":"https://github.com/electron/electron/pull/39944.patch","issue_url":"https://api.github.com/repos/electron/electron/issues/39944","number":39944,"state":"closed","locked":false,"title":"chore: bump chromium to 119.0.6029.0 (main)","user":{"login":"electron-roller[bot]","id":84116207,"node_id":"MDM6Qm90ODQxMTYyMDc=","avatar_url":"https://avatars.githubusercontent.com/in/115177?v=4","gravatar_id":"","url":"https://api.github.com/users/electron-roller%5Bbot%5D","html_url":"https://github.com/apps/electron-roller","followers_url":"https://api.github.com/users/electron-roller%5Bbot%5D/followers","following_url":"https://api.github.com/users/electron-roller%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/electron-roller%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/electron-roller%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron-roller%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/electron-roller%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/electron-roller%5Bbot%5D/repos","events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/received_events","type":"Bot","site_admin":false},"body":"Updating Chromium to 119.0.6029.0.\n\nSee [all changes in 119.0.6019.2..119.0.6029.0](https://chromium.googlesource.com/chromium/src/+log/119.0.6019.2..119.0.6029.0?n=10000&pretty=fuller)\n\n\n\nNotes: Updated Chromium to 119.0.6029.0.","created_at":"2023-09-21T13:00:39Z","updated_at":"2023-09-29T05:26:44Z","closed_at":"2023-09-29T05:26:41Z","merged_at":"2023-09-29T05:26:41Z","merge_commit_sha":"d6c8ff2e7050f30dffd784915bcbd2a9f993cdb2","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":1034512799,"node_id":"MDU6TGFiZWwxMDM0NTEyNzk5","url":"https://api.github.com/repos/electron/electron/labels/semver/patch","name":"semver/patch","color":"6ac2dd","default":false,"description":"backwards-compatible bug fixes"},{"id":1648234711,"node_id":"MDU6TGFiZWwxNjQ4MjM0NzEx","url":"https://api.github.com/repos/electron/electron/labels/roller/pause","name":"roller/pause","color":"fbca04","default":false,"description":""},{"id":2968604945,"node_id":"MDU6TGFiZWwyOTY4NjA0OTQ1","url":"https://api.github.com/repos/electron/electron/labels/no-backport","name":"no-backport","color":"CB07C4","default":false,"description":""}],"milestone":null,"draft":false,"commits_url":"https://api.github.com/repos/electron/electron/pulls/39944/commits","review_comments_url":"https://api.github.com/repos/electron/electron/pulls/39944/comments","review_comment_url":"https://api.github.com/repos/electron/electron/pulls/comments{/number}","comments_url":"https://api.github.com/repos/electron/electron/issues/39944/comments","statuses_url":"https://api.github.com/repos/electron/electron/statuses/bcb310340b17faa47fa68eae5db91d908995ffe0","head":{"label":"electron:roller/chromium/main","ref":"roller/chromium/main","sha":"bcb310340b17faa47fa68eae5db91d908995ffe0","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"base":{"label":"electron:main","ref":"main","sha":"dd7395ebedf0cfef3129697f9585035a4ddbde63","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"_links":{"self":{"href":"https://api.github.com/repos/electron/electron/pulls/39944"},"html":{"href":"https://github.com/electron/electron/pull/39944"},"issue":{"href":"https://api.github.com/repos/electron/electron/issues/39944"},"comments":{"href":"https://api.github.com/repos/electron/electron/issues/39944/comments"},"review_comments":{"href":"https://api.github.com/repos/electron/electron/pulls/39944/comments"},"review_comment":{"href":"https://api.github.com/repos/electron/electron/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/electron/electron/pulls/39944/commits"},"statuses":{"href":"https://api.github.com/repos/electron/electron/statuses/bcb310340b17faa47fa68eae5db91d908995ffe0"}},"author_association":"CONTRIBUTOR","auto_merge":null,"active_lock_reason":null}]} \ No newline at end of file diff --git a/spec/fixtures/release-notes/cache/electron-electron-commit-d9ba26273ad3e7a34c905eccbd5dabda4eb7b402 b/spec/fixtures/release-notes/cache/electron-electron-commit-d9ba26273ad3e7a34c905eccbd5dabda4eb7b402 new file mode 100644 index 0000000000000..d85f99aa2322e --- /dev/null +++ b/spec/fixtures/release-notes/cache/electron-electron-commit-d9ba26273ad3e7a34c905eccbd5dabda4eb7b402 @@ -0,0 +1 @@ +{"status":200,"url":"https://api.github.com/repos/electron/electron/commits/d9ba26273ad3e7a34c905eccbd5dabda4eb7b402/pulls","headers":{"accept-ranges":"bytes","access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","cache-control":"public, max-age=60, s-maxage=60","content-encoding":"gzip","content-length":"2671","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Fri, 20 Sep 2024 04:00:37 GMT","etag":"W/\"43d13a3642303cd5f8d90df11c58df1d9952cb3c42dacdfb39e02e1d60d2d54f\"","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept,Accept-Encoding, Accept, X-Requested-With","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"C623:36E55D:247B3BD:4558915:66ECF365","x-ratelimit-limit":"60","x-ratelimit-remaining":"49","x-ratelimit-reset":"1726805543","x-ratelimit-resource":"core","x-ratelimit-used":"11","x-xss-protection":"0"},"data":[{"url":"https://api.github.com/repos/electron/electron/pulls/39714","id":1498359807,"node_id":"PR_kwDOAI8xS85ZTyf_","html_url":"https://github.com/electron/electron/pull/39714","diff_url":"https://github.com/electron/electron/pull/39714.diff","patch_url":"https://github.com/electron/electron/pull/39714.patch","issue_url":"https://api.github.com/repos/electron/electron/issues/39714","number":39714,"state":"closed","locked":false,"title":"chore: bump chromium to 118.0.5991.0 (main)","user":{"login":"electron-roller[bot]","id":84116207,"node_id":"MDM6Qm90ODQxMTYyMDc=","avatar_url":"https://avatars.githubusercontent.com/in/115177?v=4","gravatar_id":"","url":"https://api.github.com/users/electron-roller%5Bbot%5D","html_url":"https://github.com/apps/electron-roller","followers_url":"https://api.github.com/users/electron-roller%5Bbot%5D/followers","following_url":"https://api.github.com/users/electron-roller%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/electron-roller%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/electron-roller%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron-roller%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/electron-roller%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/electron-roller%5Bbot%5D/repos","events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/received_events","type":"Bot","site_admin":false},"body":"Updating Chromium to 118.0.5991.0.\n\nSee [all changes in 118.0.5975.0..118.0.5991.0](https://chromium.googlesource.com/chromium/src/+log/118.0.5975.0..118.0.5991.0?n=10000&pretty=fuller)\n\n\n\nNotes: Updated Chromium to 118.0.5991.0.","created_at":"2023-09-01T06:55:20Z","updated_at":"2023-09-06T01:18:00Z","closed_at":"2023-09-06T01:17:57Z","merged_at":"2023-09-06T01:17:57Z","merge_commit_sha":"d9ba26273ad3e7a34c905eccbd5dabda4eb7b402","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":1034512799,"node_id":"MDU6TGFiZWwxMDM0NTEyNzk5","url":"https://api.github.com/repos/electron/electron/labels/semver/patch","name":"semver/patch","color":"6ac2dd","default":false,"description":"backwards-compatible bug fixes"},{"id":1648234711,"node_id":"MDU6TGFiZWwxNjQ4MjM0NzEx","url":"https://api.github.com/repos/electron/electron/labels/roller/pause","name":"roller/pause","color":"fbca04","default":false,"description":""},{"id":2968604945,"node_id":"MDU6TGFiZWwyOTY4NjA0OTQ1","url":"https://api.github.com/repos/electron/electron/labels/no-backport","name":"no-backport","color":"CB07C4","default":false,"description":""}],"milestone":null,"draft":false,"commits_url":"https://api.github.com/repos/electron/electron/pulls/39714/commits","review_comments_url":"https://api.github.com/repos/electron/electron/pulls/39714/comments","review_comment_url":"https://api.github.com/repos/electron/electron/pulls/comments{/number}","comments_url":"https://api.github.com/repos/electron/electron/issues/39714/comments","statuses_url":"https://api.github.com/repos/electron/electron/statuses/6bf3066e43060001074a8a38168024531dbceec3","head":{"label":"electron:roller/chromium/main","ref":"roller/chromium/main","sha":"6bf3066e43060001074a8a38168024531dbceec3","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"base":{"label":"electron:main","ref":"main","sha":"54d8402a6ca8a357d7695c1c6d01d5040e42926a","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"_links":{"self":{"href":"https://api.github.com/repos/electron/electron/pulls/39714"},"html":{"href":"https://github.com/electron/electron/pull/39714"},"issue":{"href":"https://api.github.com/repos/electron/electron/issues/39714"},"comments":{"href":"https://api.github.com/repos/electron/electron/issues/39714/comments"},"review_comments":{"href":"https://api.github.com/repos/electron/electron/pulls/39714/comments"},"review_comment":{"href":"https://api.github.com/repos/electron/electron/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/electron/electron/pulls/39714/commits"},"statuses":{"href":"https://api.github.com/repos/electron/electron/statuses/6bf3066e43060001074a8a38168024531dbceec3"}},"author_association":"CONTRIBUTOR","auto_merge":null,"active_lock_reason":null}]} \ No newline at end of file diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-issue-20214-comments b/spec/fixtures/release-notes/cache/electron-electron-issue-20214-comments similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-issue-20214-comments rename to spec/fixtures/release-notes/cache/electron-electron-issue-20214-comments diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-issue-21497-comments b/spec/fixtures/release-notes/cache/electron-electron-issue-21497-comments similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-issue-21497-comments rename to spec/fixtures/release-notes/cache/electron-electron-issue-21497-comments diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-issue-21891-comments b/spec/fixtures/release-notes/cache/electron-electron-issue-21891-comments similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-issue-21891-comments rename to spec/fixtures/release-notes/cache/electron-electron-issue-21891-comments diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-issue-21946-comments b/spec/fixtures/release-notes/cache/electron-electron-issue-21946-comments similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-issue-21946-comments rename to spec/fixtures/release-notes/cache/electron-electron-issue-21946-comments diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-issue-22750-comments b/spec/fixtures/release-notes/cache/electron-electron-issue-22750-comments similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-issue-22750-comments rename to spec/fixtures/release-notes/cache/electron-electron-issue-22750-comments diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-issue-22770-comments b/spec/fixtures/release-notes/cache/electron-electron-issue-22770-comments similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-issue-22770-comments rename to spec/fixtures/release-notes/cache/electron-electron-issue-22770-comments diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-issue-22828-comments b/spec/fixtures/release-notes/cache/electron-electron-issue-22828-comments similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-issue-22828-comments rename to spec/fixtures/release-notes/cache/electron-electron-issue-22828-comments diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-issue-25052-comments b/spec/fixtures/release-notes/cache/electron-electron-issue-25052-comments similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-issue-25052-comments rename to spec/fixtures/release-notes/cache/electron-electron-issue-25052-comments diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-issue-25216-comments b/spec/fixtures/release-notes/cache/electron-electron-issue-25216-comments similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-issue-25216-comments rename to spec/fixtures/release-notes/cache/electron-electron-issue-25216-comments diff --git a/spec/fixtures/release-notes/cache/electron-electron-issue-39714-comments b/spec/fixtures/release-notes/cache/electron-electron-issue-39714-comments new file mode 100644 index 0000000000000..5770c77857155 --- /dev/null +++ b/spec/fixtures/release-notes/cache/electron-electron-issue-39714-comments @@ -0,0 +1 @@ +{"status":200,"url":"https://api.github.com/repos/electron/electron/issues/39714/comments?per_page=100","headers":{"accept-ranges":"bytes","access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","cache-control":"public, max-age=60, s-maxage=60","content-encoding":"gzip","content-length":"645","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Fri, 20 Sep 2024 04:00:38 GMT","etag":"W/\"6fcb725196d33f08ba1ccba10f866b6bc0a51030d157259b2cce6d2758910e24\"","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept,Accept-Encoding, Accept, X-Requested-With","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"C623:36E55D:247B64D:4558DD8:66ECF365","x-ratelimit-limit":"60","x-ratelimit-remaining":"46","x-ratelimit-reset":"1726805543","x-ratelimit-resource":"core","x-ratelimit-used":"14","x-xss-protection":"0"},"data":[{"url":"https://api.github.com/repos/electron/electron/issues/comments/1707509099","html_url":"https://github.com/electron/electron/pull/39714#issuecomment-1707509099","issue_url":"https://api.github.com/repos/electron/electron/issues/39714","id":1707509099,"node_id":"IC_kwDOAI8xS85lxoVr","user":{"login":"release-clerk[bot]","id":42386326,"node_id":"MDM6Qm90NDIzODYzMjY=","avatar_url":"https://avatars.githubusercontent.com/in/16104?v=4","gravatar_id":"","url":"https://api.github.com/users/release-clerk%5Bbot%5D","html_url":"https://github.com/apps/release-clerk","followers_url":"https://api.github.com/users/release-clerk%5Bbot%5D/followers","following_url":"https://api.github.com/users/release-clerk%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/release-clerk%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/release-clerk%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/release-clerk%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/release-clerk%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/release-clerk%5Bbot%5D/repos","events_url":"https://api.github.com/users/release-clerk%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/release-clerk%5Bbot%5D/received_events","type":"Bot","site_admin":false},"created_at":"2023-09-06T01:18:00Z","updated_at":"2023-09-06T01:18:00Z","author_association":"NONE","body":"**Release Notes Persisted**\n\n> Updated Chromium to 118.0.5991.0.","reactions":{"url":"https://api.github.com/repos/electron/electron/issues/comments/1707509099/reactions","total_count":0,"+1":0,"-1":0,"laugh":0,"hooray":0,"confused":0,"heart":0,"rocket":0,"eyes":0},"performed_via_github_app":null}]} \ No newline at end of file diff --git a/spec/fixtures/release-notes/cache/electron-electron-issue-39944-comments b/spec/fixtures/release-notes/cache/electron-electron-issue-39944-comments new file mode 100644 index 0000000000000..288d1b4afef5e --- /dev/null +++ b/spec/fixtures/release-notes/cache/electron-electron-issue-39944-comments @@ -0,0 +1 @@ +{"status":200,"url":"https://api.github.com/repos/electron/electron/issues/39944/comments?per_page=100","headers":{"accept-ranges":"bytes","access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","cache-control":"public, max-age=60, s-maxage=60","content-encoding":"gzip","content-length":"869","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Fri, 20 Sep 2024 04:00:38 GMT","etag":"W/\"b34114fbdb2350380ab4adac1c9c48568bebf0e5c0a427ecaa40402f7166456c\"","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept,Accept-Encoding, Accept, X-Requested-With","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"C623:36E55D:247B74B:4558FC8:66ECF366","x-ratelimit-limit":"60","x-ratelimit-remaining":"44","x-ratelimit-reset":"1726805543","x-ratelimit-resource":"core","x-ratelimit-used":"16","x-xss-protection":"0"},"data":[{"url":"https://api.github.com/repos/electron/electron/issues/comments/1732251450","html_url":"https://github.com/electron/electron/pull/39944#issuecomment-1732251450","issue_url":"https://api.github.com/repos/electron/electron/issues/39944","id":1732251450,"node_id":"IC_kwDOAI8xS85nQA86","user":{"login":"codebytere","id":2036040,"node_id":"MDQ6VXNlcjIwMzYwNDA=","avatar_url":"https://avatars.githubusercontent.com/u/2036040?v=4","gravatar_id":"","url":"https://api.github.com/users/codebytere","html_url":"https://github.com/codebytere","followers_url":"https://api.github.com/users/codebytere/followers","following_url":"https://api.github.com/users/codebytere/following{/other_user}","gists_url":"https://api.github.com/users/codebytere/gists{/gist_id}","starred_url":"https://api.github.com/users/codebytere/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/codebytere/subscriptions","organizations_url":"https://api.github.com/users/codebytere/orgs","repos_url":"https://api.github.com/users/codebytere/repos","events_url":"https://api.github.com/users/codebytere/events{/privacy}","received_events_url":"https://api.github.com/users/codebytere/received_events","type":"User","site_admin":false},"created_at":"2023-09-23T08:19:47Z","updated_at":"2023-09-23T08:19:47Z","author_association":"MEMBER","body":"Needs https://github.com/electron/build-tools/pull/516","reactions":{"url":"https://api.github.com/repos/electron/electron/issues/comments/1732251450/reactions","total_count":0,"+1":0,"-1":0,"laugh":0,"hooray":0,"confused":0,"heart":0,"rocket":0,"eyes":0},"performed_via_github_app":null},{"url":"https://api.github.com/repos/electron/electron/issues/comments/1740333567","html_url":"https://github.com/electron/electron/pull/39944#issuecomment-1740333567","issue_url":"https://api.github.com/repos/electron/electron/issues/39944","id":1740333567,"node_id":"IC_kwDOAI8xS85nu2H_","user":{"login":"release-clerk[bot]","id":42386326,"node_id":"MDM6Qm90NDIzODYzMjY=","avatar_url":"https://avatars.githubusercontent.com/in/16104?v=4","gravatar_id":"","url":"https://api.github.com/users/release-clerk%5Bbot%5D","html_url":"https://github.com/apps/release-clerk","followers_url":"https://api.github.com/users/release-clerk%5Bbot%5D/followers","following_url":"https://api.github.com/users/release-clerk%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/release-clerk%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/release-clerk%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/release-clerk%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/release-clerk%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/release-clerk%5Bbot%5D/repos","events_url":"https://api.github.com/users/release-clerk%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/release-clerk%5Bbot%5D/received_events","type":"Bot","site_admin":false},"created_at":"2023-09-29T05:26:44Z","updated_at":"2023-09-29T05:26:44Z","author_association":"NONE","body":"**Release Notes Persisted**\n\n> Updated Chromium to 119.0.6029.0.","reactions":{"url":"https://api.github.com/repos/electron/electron/issues/comments/1740333567/reactions","total_count":2,"+1":1,"-1":0,"laugh":0,"hooray":0,"confused":0,"heart":0,"rocket":1,"eyes":0},"performed_via_github_app":null}]} \ No newline at end of file diff --git a/spec/fixtures/release-notes/cache/electron-electron-issue-40045-comments b/spec/fixtures/release-notes/cache/electron-electron-issue-40045-comments new file mode 100644 index 0000000000000..f7ecc0e3c731b --- /dev/null +++ b/spec/fixtures/release-notes/cache/electron-electron-issue-40045-comments @@ -0,0 +1 @@ +{"status":200,"url":"https://api.github.com/repos/electron/electron/issues/40045/comments?per_page=100","headers":{"accept-ranges":"bytes","access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","cache-control":"public, max-age=60, s-maxage=60","content-encoding":"gzip","content-length":"645","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Fri, 20 Sep 2024 04:00:38 GMT","etag":"W/\"597a0b18dff7544d3742956759f06c9233095b92fdc8e3a1ac78afaf61a42b5c\"","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept,Accept-Encoding, Accept, X-Requested-With","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"C623:36E55D:247B6D4:4558ED3:66ECF366","x-ratelimit-limit":"60","x-ratelimit-remaining":"45","x-ratelimit-reset":"1726805543","x-ratelimit-resource":"core","x-ratelimit-used":"15","x-xss-protection":"0"},"data":[{"url":"https://api.github.com/repos/electron/electron/issues/comments/1743831479","html_url":"https://github.com/electron/electron/pull/40045#issuecomment-1743831479","issue_url":"https://api.github.com/repos/electron/electron/issues/40045","id":1743831479,"node_id":"IC_kwDOAI8xS85n8MG3","user":{"login":"release-clerk[bot]","id":42386326,"node_id":"MDM6Qm90NDIzODYzMjY=","avatar_url":"https://avatars.githubusercontent.com/in/16104?v=4","gravatar_id":"","url":"https://api.github.com/users/release-clerk%5Bbot%5D","html_url":"https://github.com/apps/release-clerk","followers_url":"https://api.github.com/users/release-clerk%5Bbot%5D/followers","following_url":"https://api.github.com/users/release-clerk%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/release-clerk%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/release-clerk%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/release-clerk%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/release-clerk%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/release-clerk%5Bbot%5D/repos","events_url":"https://api.github.com/users/release-clerk%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/release-clerk%5Bbot%5D/received_events","type":"Bot","site_admin":false},"created_at":"2023-10-02T22:01:11Z","updated_at":"2023-10-02T22:01:11Z","author_association":"NONE","body":"**Release Notes Persisted**\n\n> Updated Chromium to 119.0.6043.0.","reactions":{"url":"https://api.github.com/repos/electron/electron/issues/comments/1743831479/reactions","total_count":0,"+1":0,"-1":0,"laugh":0,"hooray":0,"confused":0,"heart":0,"rocket":0,"eyes":0},"performed_via_github_app":null}]} \ No newline at end of file diff --git a/spec/fixtures/release-notes/cache/electron-electron-issue-40076-comments b/spec/fixtures/release-notes/cache/electron-electron-issue-40076-comments new file mode 100644 index 0000000000000..411ab60c17767 --- /dev/null +++ b/spec/fixtures/release-notes/cache/electron-electron-issue-40076-comments @@ -0,0 +1 @@ +{"status":200,"url":"https://api.github.com/repos/electron/electron/issues/40076/comments?per_page=100","headers":{"accept-ranges":"bytes","access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","cache-control":"public, max-age=60, s-maxage=60","content-encoding":"gzip","content-length":"894","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Fri, 20 Sep 2024 04:00:38 GMT","etag":"W/\"b11c58261437bdbb984540cd6090cfe239f8f4b5b7af801f6f711e7f0bbe5915\"","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept,Accept-Encoding, Accept, X-Requested-With","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"C623:36E55D:247B8AF:4559259:66ECF366","x-ratelimit-limit":"60","x-ratelimit-remaining":"42","x-ratelimit-reset":"1726805543","x-ratelimit-resource":"core","x-ratelimit-used":"18","x-xss-protection":"0"},"data":[{"url":"https://api.github.com/repos/electron/electron/issues/comments/1749810095","html_url":"https://github.com/electron/electron/pull/40076#issuecomment-1749810095","issue_url":"https://api.github.com/repos/electron/electron/issues/40076","id":1749810095,"node_id":"IC_kwDOAI8xS85oS_uv","user":{"login":"release-clerk[bot]","id":42386326,"node_id":"MDM6Qm90NDIzODYzMjY=","avatar_url":"https://avatars.githubusercontent.com/in/16104?v=4","gravatar_id":"","url":"https://api.github.com/users/release-clerk%5Bbot%5D","html_url":"https://github.com/apps/release-clerk","followers_url":"https://api.github.com/users/release-clerk%5Bbot%5D/followers","following_url":"https://api.github.com/users/release-clerk%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/release-clerk%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/release-clerk%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/release-clerk%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/release-clerk%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/release-clerk%5Bbot%5D/repos","events_url":"https://api.github.com/users/release-clerk%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/release-clerk%5Bbot%5D/received_events","type":"Bot","site_admin":false},"created_at":"2023-10-05T23:59:43Z","updated_at":"2023-10-05T23:59:43Z","author_association":"NONE","body":"**Release Notes Persisted**\n\n> Updated Chromium to 119.0.6045.0.","reactions":{"url":"https://api.github.com/repos/electron/electron/issues/comments/1749810095/reactions","total_count":0,"+1":0,"-1":0,"laugh":0,"hooray":0,"confused":0,"heart":0,"rocket":0,"eyes":0},"performed_via_github_app":null},{"url":"https://api.github.com/repos/electron/electron/issues/comments/1749846515","html_url":"https://github.com/electron/electron/pull/40076#issuecomment-1749846515","issue_url":"https://api.github.com/repos/electron/electron/issues/40076","id":1749846515,"node_id":"IC_kwDOAI8xS85oTInz","user":{"login":"ckerr","id":70381,"node_id":"MDQ6VXNlcjcwMzgx","avatar_url":"https://avatars.githubusercontent.com/u/70381?v=4","gravatar_id":"","url":"https://api.github.com/users/ckerr","html_url":"https://github.com/ckerr","followers_url":"https://api.github.com/users/ckerr/followers","following_url":"https://api.github.com/users/ckerr/following{/other_user}","gists_url":"https://api.github.com/users/ckerr/gists{/gist_id}","starred_url":"https://api.github.com/users/ckerr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ckerr/subscriptions","organizations_url":"https://api.github.com/users/ckerr/orgs","repos_url":"https://api.github.com/users/ckerr/repos","events_url":"https://api.github.com/users/ckerr/events{/privacy}","received_events_url":"https://api.github.com/users/ckerr/received_events","type":"User","site_admin":false},"created_at":"2023-10-06T00:56:09Z","updated_at":"2023-10-06T00:56:09Z","author_association":"MEMBER","body":"Ah, merged while I was reading. :sweat_smile: FWIW @jkleinsc here's a tardy :+1: on the glib/gio changes","reactions":{"url":"https://api.github.com/repos/electron/electron/issues/comments/1749846515/reactions","total_count":0,"+1":0,"-1":0,"laugh":0,"hooray":0,"confused":0,"heart":0,"rocket":0,"eyes":0},"performed_via_github_app":null}]} \ No newline at end of file diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-pull-20214 b/spec/fixtures/release-notes/cache/electron-electron-pull-20214 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-pull-20214 rename to spec/fixtures/release-notes/cache/electron-electron-pull-20214 diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-pull-20620 b/spec/fixtures/release-notes/cache/electron-electron-pull-20620 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-pull-20620 rename to spec/fixtures/release-notes/cache/electron-electron-pull-20620 diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-pull-21497 b/spec/fixtures/release-notes/cache/electron-electron-pull-21497 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-pull-21497 rename to spec/fixtures/release-notes/cache/electron-electron-pull-21497 diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-pull-21591 b/spec/fixtures/release-notes/cache/electron-electron-pull-21591 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-pull-21591 rename to spec/fixtures/release-notes/cache/electron-electron-pull-21591 diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-pull-21891 b/spec/fixtures/release-notes/cache/electron-electron-pull-21891 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-pull-21891 rename to spec/fixtures/release-notes/cache/electron-electron-pull-21891 diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-pull-21946 b/spec/fixtures/release-notes/cache/electron-electron-pull-21946 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-pull-21946 rename to spec/fixtures/release-notes/cache/electron-electron-pull-21946 diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-pull-22750 b/spec/fixtures/release-notes/cache/electron-electron-pull-22750 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-pull-22750 rename to spec/fixtures/release-notes/cache/electron-electron-pull-22750 diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-pull-22770 b/spec/fixtures/release-notes/cache/electron-electron-pull-22770 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-pull-22770 rename to spec/fixtures/release-notes/cache/electron-electron-pull-22770 diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-pull-22828 b/spec/fixtures/release-notes/cache/electron-electron-pull-22828 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-pull-22828 rename to spec/fixtures/release-notes/cache/electron-electron-pull-22828 diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-pull-25052 b/spec/fixtures/release-notes/cache/electron-electron-pull-25052 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-pull-25052 rename to spec/fixtures/release-notes/cache/electron-electron-pull-25052 diff --git a/spec-main/fixtures/release-notes/cache/electron-electron-pull-25216 b/spec/fixtures/release-notes/cache/electron-electron-pull-25216 similarity index 100% rename from spec-main/fixtures/release-notes/cache/electron-electron-pull-25216 rename to spec/fixtures/release-notes/cache/electron-electron-pull-25216 diff --git a/spec/fixtures/release-notes/cache/electron-electron-pull-39714 b/spec/fixtures/release-notes/cache/electron-electron-pull-39714 new file mode 100644 index 0000000000000..e1166b21a3e03 --- /dev/null +++ b/spec/fixtures/release-notes/cache/electron-electron-pull-39714 @@ -0,0 +1 @@ +{"status":200,"url":"https://api.github.com/repos/electron/electron/commits/d9ba26273ad3e7a34c905eccbd5dabda4eb7b402/pulls","headers":{"accept-ranges":"bytes","access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","cache-control":"public, max-age=60, s-maxage=60","content-encoding":"gzip","content-length":"2671","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Fri, 20 Sep 2024 04:00:37 GMT","etag":"W/\"43d13a3642303cd5f8d90df11c58df1d9952cb3c42dacdfb39e02e1d60d2d54f\"","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept,Accept-Encoding, Accept, X-Requested-With","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"C623:36E55D:247B3BD:4558915:66ECF365","x-ratelimit-limit":"60","x-ratelimit-remaining":"49","x-ratelimit-reset":"1726805543","x-ratelimit-resource":"core","x-ratelimit-used":"11","x-xss-protection":"0"},"data":{"url":"https://api.github.com/repos/electron/electron/pulls/39714","id":1498359807,"node_id":"PR_kwDOAI8xS85ZTyf_","html_url":"https://github.com/electron/electron/pull/39714","diff_url":"https://github.com/electron/electron/pull/39714.diff","patch_url":"https://github.com/electron/electron/pull/39714.patch","issue_url":"https://api.github.com/repos/electron/electron/issues/39714","number":39714,"state":"closed","locked":false,"title":"chore: bump chromium to 118.0.5991.0 (main)","user":{"login":"electron-roller[bot]","id":84116207,"node_id":"MDM6Qm90ODQxMTYyMDc=","avatar_url":"https://avatars.githubusercontent.com/in/115177?v=4","gravatar_id":"","url":"https://api.github.com/users/electron-roller%5Bbot%5D","html_url":"https://github.com/apps/electron-roller","followers_url":"https://api.github.com/users/electron-roller%5Bbot%5D/followers","following_url":"https://api.github.com/users/electron-roller%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/electron-roller%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/electron-roller%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron-roller%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/electron-roller%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/electron-roller%5Bbot%5D/repos","events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/received_events","type":"Bot","site_admin":false},"body":"Updating Chromium to 118.0.5991.0.\n\nSee [all changes in 118.0.5975.0..118.0.5991.0](https://chromium.googlesource.com/chromium/src/+log/118.0.5975.0..118.0.5991.0?n=10000&pretty=fuller)\n\n\n\nNotes: Updated Chromium to 118.0.5991.0.","created_at":"2023-09-01T06:55:20Z","updated_at":"2023-09-06T01:18:00Z","closed_at":"2023-09-06T01:17:57Z","merged_at":"2023-09-06T01:17:57Z","merge_commit_sha":"d9ba26273ad3e7a34c905eccbd5dabda4eb7b402","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":1034512799,"node_id":"MDU6TGFiZWwxMDM0NTEyNzk5","url":"https://api.github.com/repos/electron/electron/labels/semver/patch","name":"semver/patch","color":"6ac2dd","default":false,"description":"backwards-compatible bug fixes"},{"id":1648234711,"node_id":"MDU6TGFiZWwxNjQ4MjM0NzEx","url":"https://api.github.com/repos/electron/electron/labels/roller/pause","name":"roller/pause","color":"fbca04","default":false,"description":""},{"id":2968604945,"node_id":"MDU6TGFiZWwyOTY4NjA0OTQ1","url":"https://api.github.com/repos/electron/electron/labels/no-backport","name":"no-backport","color":"CB07C4","default":false,"description":""}],"milestone":null,"draft":false,"commits_url":"https://api.github.com/repos/electron/electron/pulls/39714/commits","review_comments_url":"https://api.github.com/repos/electron/electron/pulls/39714/comments","review_comment_url":"https://api.github.com/repos/electron/electron/pulls/comments{/number}","comments_url":"https://api.github.com/repos/electron/electron/issues/39714/comments","statuses_url":"https://api.github.com/repos/electron/electron/statuses/6bf3066e43060001074a8a38168024531dbceec3","head":{"label":"electron:roller/chromium/main","ref":"roller/chromium/main","sha":"6bf3066e43060001074a8a38168024531dbceec3","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"base":{"label":"electron:main","ref":"main","sha":"54d8402a6ca8a357d7695c1c6d01d5040e42926a","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"_links":{"self":{"href":"https://api.github.com/repos/electron/electron/pulls/39714"},"html":{"href":"https://github.com/electron/electron/pull/39714"},"issue":{"href":"https://api.github.com/repos/electron/electron/issues/39714"},"comments":{"href":"https://api.github.com/repos/electron/electron/issues/39714/comments"},"review_comments":{"href":"https://api.github.com/repos/electron/electron/pulls/39714/comments"},"review_comment":{"href":"https://api.github.com/repos/electron/electron/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/electron/electron/pulls/39714/commits"},"statuses":{"href":"https://api.github.com/repos/electron/electron/statuses/6bf3066e43060001074a8a38168024531dbceec3"}},"author_association":"CONTRIBUTOR","auto_merge":null,"active_lock_reason":null}} \ No newline at end of file diff --git a/spec/fixtures/release-notes/cache/electron-electron-pull-39745 b/spec/fixtures/release-notes/cache/electron-electron-pull-39745 new file mode 100644 index 0000000000000..9bde239b59580 --- /dev/null +++ b/spec/fixtures/release-notes/cache/electron-electron-pull-39745 @@ -0,0 +1 @@ +{"status":200,"url":"https://api.github.com/repos/electron/electron/commits/029127a8b6f7c511fca4612748ad5b50e43aadaa/pulls","headers":{"accept-ranges":"bytes","access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","cache-control":"public, max-age=60, s-maxage=60","content-encoding":"gzip","content-length":"2717","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Fri, 20 Sep 2024 04:00:37 GMT","etag":"W/\"80e2d0edebd07c0cf53916bf23fee37544d3eb301e1a65595fff37115a465eae\"","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept,Accept-Encoding, Accept, X-Requested-With","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"C623:36E55D:247B2AD:4558739:66ECF364","x-ratelimit-limit":"60","x-ratelimit-remaining":"50","x-ratelimit-reset":"1726805543","x-ratelimit-resource":"core","x-ratelimit-used":"10","x-xss-protection":"0"},"data":{"url":"https://api.github.com/repos/electron/electron/pulls/39745","id":1504592750,"node_id":"PR_kwDOAI8xS85ZrkNu","html_url":"https://github.com/electron/electron/pull/39745","diff_url":"https://github.com/electron/electron/pull/39745.diff","patch_url":"https://github.com/electron/electron/pull/39745.patch","issue_url":"https://api.github.com/repos/electron/electron/issues/39745","number":39745,"state":"closed","locked":false,"title":"chore: bump chromium to 118.0.5993.0 (main)","user":{"login":"electron-roller[bot]","id":84116207,"node_id":"MDM6Qm90ODQxMTYyMDc=","avatar_url":"https://avatars.githubusercontent.com/in/115177?v=4","gravatar_id":"","url":"https://api.github.com/users/electron-roller%5Bbot%5D","html_url":"https://github.com/apps/electron-roller","followers_url":"https://api.github.com/users/electron-roller%5Bbot%5D/followers","following_url":"https://api.github.com/users/electron-roller%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/electron-roller%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/electron-roller%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron-roller%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/electron-roller%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/electron-roller%5Bbot%5D/repos","events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/received_events","type":"Bot","site_admin":false},"body":"Updating Chromium to 118.0.5993.0.\n\nSee [all changes in 118.0.5991.0..118.0.5993.0](https://chromium.googlesource.com/chromium/src/+log/118.0.5991.0..118.0.5993.0?n=10000&pretty=fuller)\n\n\n\nNotes: Updated Chromium to 118.0.5993.0.","created_at":"2023-09-06T13:00:33Z","updated_at":"2023-09-06T23:28:42Z","closed_at":"2023-09-06T23:27:26Z","merged_at":"2023-09-06T23:27:26Z","merge_commit_sha":"029127a8b6f7c511fca4612748ad5b50e43aadaa","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":1034512799,"node_id":"MDU6TGFiZWwxMDM0NTEyNzk5","url":"https://api.github.com/repos/electron/electron/labels/semver/patch","name":"semver/patch","color":"6ac2dd","default":false,"description":"backwards-compatible bug fixes"},{"id":1243058793,"node_id":"MDU6TGFiZWwxMjQzMDU4Nzkz","url":"https://api.github.com/repos/electron/electron/labels/new-pr%20%F0%9F%8C%B1","name":"new-pr 🌱","color":"8af297","default":false,"description":"PR opened in the last 24 hours"},{"id":2968604945,"node_id":"MDU6TGFiZWwyOTY4NjA0OTQ1","url":"https://api.github.com/repos/electron/electron/labels/no-backport","name":"no-backport","color":"CB07C4","default":false,"description":""}],"milestone":null,"draft":false,"commits_url":"https://api.github.com/repos/electron/electron/pulls/39745/commits","review_comments_url":"https://api.github.com/repos/electron/electron/pulls/39745/comments","review_comment_url":"https://api.github.com/repos/electron/electron/pulls/comments{/number}","comments_url":"https://api.github.com/repos/electron/electron/issues/39745/comments","statuses_url":"https://api.github.com/repos/electron/electron/statuses/7ba0be830a247d916c05d2471c5ce214d2598476","head":{"label":"electron:roller/chromium/main","ref":"roller/chromium/main","sha":"7ba0be830a247d916c05d2471c5ce214d2598476","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"base":{"label":"electron:main","ref":"main","sha":"34b79c15c2f2de2fa514538b7ccb4b3c473808ae","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"_links":{"self":{"href":"https://api.github.com/repos/electron/electron/pulls/39745"},"html":{"href":"https://github.com/electron/electron/pull/39745"},"issue":{"href":"https://api.github.com/repos/electron/electron/issues/39745"},"comments":{"href":"https://api.github.com/repos/electron/electron/issues/39745/comments"},"review_comments":{"href":"https://api.github.com/repos/electron/electron/pulls/39745/comments"},"review_comment":{"href":"https://api.github.com/repos/electron/electron/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/electron/electron/pulls/39745/commits"},"statuses":{"href":"https://api.github.com/repos/electron/electron/statuses/7ba0be830a247d916c05d2471c5ce214d2598476"}},"author_association":"CONTRIBUTOR","auto_merge":null,"active_lock_reason":null}} \ No newline at end of file diff --git a/spec/fixtures/release-notes/cache/electron-electron-pull-39944 b/spec/fixtures/release-notes/cache/electron-electron-pull-39944 new file mode 100644 index 0000000000000..374b574670616 --- /dev/null +++ b/spec/fixtures/release-notes/cache/electron-electron-pull-39944 @@ -0,0 +1 @@ +{"status":200,"url":"https://api.github.com/repos/electron/electron/commits/d6c8ff2e7050f30dffd784915bcbd2a9f993cdb2/pulls","headers":{"accept-ranges":"bytes","access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","cache-control":"public, max-age=60, s-maxage=60","content-encoding":"gzip","content-length":"2656","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Fri, 20 Sep 2024 04:00:37 GMT","etag":"W/\"b1a96400c9529932fb835905524621cae9010fe39a87e5b4720587f8f5f1bf99\"","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept,Accept-Encoding, Accept, X-Requested-With","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"C623:36E55D:247B56F:4558C56:66ECF365","x-ratelimit-limit":"60","x-ratelimit-remaining":"47","x-ratelimit-reset":"1726805543","x-ratelimit-resource":"core","x-ratelimit-used":"13","x-xss-protection":"0"},"data":{"url":"https://api.github.com/repos/electron/electron/pulls/39944","id":1524826900,"node_id":"PR_kwDOAI8xS85a4wMU","html_url":"https://github.com/electron/electron/pull/39944","diff_url":"https://github.com/electron/electron/pull/39944.diff","patch_url":"https://github.com/electron/electron/pull/39944.patch","issue_url":"https://api.github.com/repos/electron/electron/issues/39944","number":39944,"state":"closed","locked":false,"title":"chore: bump chromium to 119.0.6029.0 (main)","user":{"login":"electron-roller[bot]","id":84116207,"node_id":"MDM6Qm90ODQxMTYyMDc=","avatar_url":"https://avatars.githubusercontent.com/in/115177?v=4","gravatar_id":"","url":"https://api.github.com/users/electron-roller%5Bbot%5D","html_url":"https://github.com/apps/electron-roller","followers_url":"https://api.github.com/users/electron-roller%5Bbot%5D/followers","following_url":"https://api.github.com/users/electron-roller%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/electron-roller%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/electron-roller%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron-roller%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/electron-roller%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/electron-roller%5Bbot%5D/repos","events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/received_events","type":"Bot","site_admin":false},"body":"Updating Chromium to 119.0.6029.0.\n\nSee [all changes in 119.0.6019.2..119.0.6029.0](https://chromium.googlesource.com/chromium/src/+log/119.0.6019.2..119.0.6029.0?n=10000&pretty=fuller)\n\n\n\nNotes: Updated Chromium to 119.0.6029.0.","created_at":"2023-09-21T13:00:39Z","updated_at":"2023-09-29T05:26:44Z","closed_at":"2023-09-29T05:26:41Z","merged_at":"2023-09-29T05:26:41Z","merge_commit_sha":"d6c8ff2e7050f30dffd784915bcbd2a9f993cdb2","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":1034512799,"node_id":"MDU6TGFiZWwxMDM0NTEyNzk5","url":"https://api.github.com/repos/electron/electron/labels/semver/patch","name":"semver/patch","color":"6ac2dd","default":false,"description":"backwards-compatible bug fixes"},{"id":1648234711,"node_id":"MDU6TGFiZWwxNjQ4MjM0NzEx","url":"https://api.github.com/repos/electron/electron/labels/roller/pause","name":"roller/pause","color":"fbca04","default":false,"description":""},{"id":2968604945,"node_id":"MDU6TGFiZWwyOTY4NjA0OTQ1","url":"https://api.github.com/repos/electron/electron/labels/no-backport","name":"no-backport","color":"CB07C4","default":false,"description":""}],"milestone":null,"draft":false,"commits_url":"https://api.github.com/repos/electron/electron/pulls/39944/commits","review_comments_url":"https://api.github.com/repos/electron/electron/pulls/39944/comments","review_comment_url":"https://api.github.com/repos/electron/electron/pulls/comments{/number}","comments_url":"https://api.github.com/repos/electron/electron/issues/39944/comments","statuses_url":"https://api.github.com/repos/electron/electron/statuses/bcb310340b17faa47fa68eae5db91d908995ffe0","head":{"label":"electron:roller/chromium/main","ref":"roller/chromium/main","sha":"bcb310340b17faa47fa68eae5db91d908995ffe0","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"base":{"label":"electron:main","ref":"main","sha":"dd7395ebedf0cfef3129697f9585035a4ddbde63","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"_links":{"self":{"href":"https://api.github.com/repos/electron/electron/pulls/39944"},"html":{"href":"https://github.com/electron/electron/pull/39944"},"issue":{"href":"https://api.github.com/repos/electron/electron/issues/39944"},"comments":{"href":"https://api.github.com/repos/electron/electron/issues/39944/comments"},"review_comments":{"href":"https://api.github.com/repos/electron/electron/pulls/39944/comments"},"review_comment":{"href":"https://api.github.com/repos/electron/electron/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/electron/electron/pulls/39944/commits"},"statuses":{"href":"https://api.github.com/repos/electron/electron/statuses/bcb310340b17faa47fa68eae5db91d908995ffe0"}},"author_association":"CONTRIBUTOR","auto_merge":null,"active_lock_reason":null}} \ No newline at end of file diff --git a/spec/fixtures/release-notes/cache/electron-electron-pull-40045 b/spec/fixtures/release-notes/cache/electron-electron-pull-40045 new file mode 100644 index 0000000000000..996570b00e337 --- /dev/null +++ b/spec/fixtures/release-notes/cache/electron-electron-pull-40045 @@ -0,0 +1 @@ +{"status":200,"url":"https://api.github.com/repos/electron/electron/commits/9d0e6d09f0be0abbeae46dd3d66afd96d2daacaa/pulls","headers":{"accept-ranges":"bytes","access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","cache-control":"public, max-age=60, s-maxage=60","content-encoding":"gzip","content-length":"2667","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Fri, 20 Sep 2024 04:00:37 GMT","etag":"W/\"1467bf4bc68e3bbb5c598d01f59d72ae71f38c1e45f7a20c7397ada84fbbb80c\"","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept,Accept-Encoding, Accept, X-Requested-With","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"C623:36E55D:247B4A7:4558AB7:66ECF365","x-ratelimit-limit":"60","x-ratelimit-remaining":"48","x-ratelimit-reset":"1726805543","x-ratelimit-resource":"core","x-ratelimit-used":"12","x-xss-protection":"0"},"data":{"url":"https://api.github.com/repos/electron/electron/pulls/40045","id":1535161486,"node_id":"PR_kwDOAI8xS85bgLSO","html_url":"https://github.com/electron/electron/pull/40045","diff_url":"https://github.com/electron/electron/pull/40045.diff","patch_url":"https://github.com/electron/electron/pull/40045.patch","issue_url":"https://api.github.com/repos/electron/electron/issues/40045","number":40045,"state":"closed","locked":false,"title":"chore: bump chromium to 119.0.6043.0 (main)","user":{"login":"electron-roller[bot]","id":84116207,"node_id":"MDM6Qm90ODQxMTYyMDc=","avatar_url":"https://avatars.githubusercontent.com/in/115177?v=4","gravatar_id":"","url":"https://api.github.com/users/electron-roller%5Bbot%5D","html_url":"https://github.com/apps/electron-roller","followers_url":"https://api.github.com/users/electron-roller%5Bbot%5D/followers","following_url":"https://api.github.com/users/electron-roller%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/electron-roller%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/electron-roller%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron-roller%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/electron-roller%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/electron-roller%5Bbot%5D/repos","events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/received_events","type":"Bot","site_admin":false},"body":"Updating Chromium to 119.0.6043.0.\n\nSee [all changes in 119.0.6029.0..119.0.6043.0](https://chromium.googlesource.com/chromium/src/+log/119.0.6029.0..119.0.6043.0?n=10000&pretty=fuller)\n\n\n\nNotes: Updated Chromium to 119.0.6043.0.","created_at":"2023-09-29T05:27:06Z","updated_at":"2023-10-02T22:01:11Z","closed_at":"2023-10-02T22:01:07Z","merged_at":"2023-10-02T22:01:07Z","merge_commit_sha":"9d0e6d09f0be0abbeae46dd3d66afd96d2daacaa","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":1034512799,"node_id":"MDU6TGFiZWwxMDM0NTEyNzk5","url":"https://api.github.com/repos/electron/electron/labels/semver/patch","name":"semver/patch","color":"6ac2dd","default":false,"description":"backwards-compatible bug fixes"},{"id":1648234711,"node_id":"MDU6TGFiZWwxNjQ4MjM0NzEx","url":"https://api.github.com/repos/electron/electron/labels/roller/pause","name":"roller/pause","color":"fbca04","default":false,"description":""},{"id":2968604945,"node_id":"MDU6TGFiZWwyOTY4NjA0OTQ1","url":"https://api.github.com/repos/electron/electron/labels/no-backport","name":"no-backport","color":"CB07C4","default":false,"description":""}],"milestone":null,"draft":false,"commits_url":"https://api.github.com/repos/electron/electron/pulls/40045/commits","review_comments_url":"https://api.github.com/repos/electron/electron/pulls/40045/comments","review_comment_url":"https://api.github.com/repos/electron/electron/pulls/comments{/number}","comments_url":"https://api.github.com/repos/electron/electron/issues/40045/comments","statuses_url":"https://api.github.com/repos/electron/electron/statuses/6fcb6a8d7ffc0b57f8d161bbdd9ff87a3dd5e934","head":{"label":"electron:roller/chromium/main","ref":"roller/chromium/main","sha":"6fcb6a8d7ffc0b57f8d161bbdd9ff87a3dd5e934","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"base":{"label":"electron:main","ref":"main","sha":"503ae86ab216406485bf437969da8c56266c3346","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"_links":{"self":{"href":"https://api.github.com/repos/electron/electron/pulls/40045"},"html":{"href":"https://github.com/electron/electron/pull/40045"},"issue":{"href":"https://api.github.com/repos/electron/electron/issues/40045"},"comments":{"href":"https://api.github.com/repos/electron/electron/issues/40045/comments"},"review_comments":{"href":"https://api.github.com/repos/electron/electron/pulls/40045/comments"},"review_comment":{"href":"https://api.github.com/repos/electron/electron/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/electron/electron/pulls/40045/commits"},"statuses":{"href":"https://api.github.com/repos/electron/electron/statuses/6fcb6a8d7ffc0b57f8d161bbdd9ff87a3dd5e934"}},"author_association":"CONTRIBUTOR","auto_merge":null,"active_lock_reason":null}} \ No newline at end of file diff --git a/spec/fixtures/release-notes/cache/electron-electron-pull-40076 b/spec/fixtures/release-notes/cache/electron-electron-pull-40076 new file mode 100644 index 0000000000000..84bd9002d89ff --- /dev/null +++ b/spec/fixtures/release-notes/cache/electron-electron-pull-40076 @@ -0,0 +1 @@ +{"status":200,"url":"https://api.github.com/repos/electron/electron/commits/8f7a48879ef8633a76279803637cdee7f7c6cd4f/pulls","headers":{"accept-ranges":"bytes","access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","cache-control":"public, max-age=60, s-maxage=60","content-encoding":"gzip","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Fri, 20 Sep 2024 04:00:38 GMT","etag":"W/\"fc25a1c4edee51c7c227cdb578189b0196dfeea4976c22509630ee1fc0b75919\"","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","transfer-encoding":"chunked","vary":"Accept,Accept-Encoding, Accept, X-Requested-With","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"C623:36E55D:247B7DF:45590F1:66ECF366","x-ratelimit-limit":"60","x-ratelimit-remaining":"43","x-ratelimit-reset":"1726805543","x-ratelimit-resource":"core","x-ratelimit-used":"17","x-xss-protection":"0"},"data":{"url":"https://api.github.com/repos/electron/electron/pulls/40076","id":1539965204,"node_id":"PR_kwDOAI8xS85bygEU","html_url":"https://github.com/electron/electron/pull/40076","diff_url":"https://github.com/electron/electron/pull/40076.diff","patch_url":"https://github.com/electron/electron/pull/40076.patch","issue_url":"https://api.github.com/repos/electron/electron/issues/40076","number":40076,"state":"closed","locked":false,"title":"chore: bump chromium to 119.0.6045.0 (main)","user":{"login":"electron-roller[bot]","id":84116207,"node_id":"MDM6Qm90ODQxMTYyMDc=","avatar_url":"https://avatars.githubusercontent.com/in/115177?v=4","gravatar_id":"","url":"https://api.github.com/users/electron-roller%5Bbot%5D","html_url":"https://github.com/apps/electron-roller","followers_url":"https://api.github.com/users/electron-roller%5Bbot%5D/followers","following_url":"https://api.github.com/users/electron-roller%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/electron-roller%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/electron-roller%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron-roller%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/electron-roller%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/electron-roller%5Bbot%5D/repos","events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/electron-roller%5Bbot%5D/received_events","type":"Bot","site_admin":false},"body":"Updating Chromium to 119.0.6045.0.\r\n\r\nSee [all changes in 119.0.6043.0..119.0.6045.0](https://chromium.googlesource.com/chromium/src/+log/119.0.6043.0..119.0.6045.0?n=10000&pretty=fuller)\r\n\r\n\r\n\r\nNotes: Updated Chromium to 119.0.6045.0.","created_at":"2023-10-03T13:00:35Z","updated_at":"2023-10-06T00:56:09Z","closed_at":"2023-10-05T23:59:40Z","merged_at":"2023-10-05T23:59:40Z","merge_commit_sha":"8f7a48879ef8633a76279803637cdee7f7c6cd4f","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":1034512799,"node_id":"MDU6TGFiZWwxMDM0NTEyNzk5","url":"https://api.github.com/repos/electron/electron/labels/semver/patch","name":"semver/patch","color":"6ac2dd","default":false,"description":"backwards-compatible bug fixes"},{"id":1648234711,"node_id":"MDU6TGFiZWwxNjQ4MjM0NzEx","url":"https://api.github.com/repos/electron/electron/labels/roller/pause","name":"roller/pause","color":"fbca04","default":false,"description":""},{"id":2968604945,"node_id":"MDU6TGFiZWwyOTY4NjA0OTQ1","url":"https://api.github.com/repos/electron/electron/labels/no-backport","name":"no-backport","color":"CB07C4","default":false,"description":""}],"milestone":null,"draft":false,"commits_url":"https://api.github.com/repos/electron/electron/pulls/40076/commits","review_comments_url":"https://api.github.com/repos/electron/electron/pulls/40076/comments","review_comment_url":"https://api.github.com/repos/electron/electron/pulls/comments{/number}","comments_url":"https://api.github.com/repos/electron/electron/issues/40076/comments","statuses_url":"https://api.github.com/repos/electron/electron/statuses/6a695f015bac8388dc450b46f548288bff58a433","head":{"label":"electron:roller/chromium/main","ref":"roller/chromium/main","sha":"6a695f015bac8388dc450b46f548288bff58a433","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"base":{"label":"electron:main","ref":"main","sha":"3392d9a2e74973960ca516adc1c1684e03f78414","user":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"node_id":"MDEwOlJlcG9zaXRvcnk5Mzg0MjY3","name":"electron","full_name":"electron/electron","private":false,"owner":{"login":"electron","id":13409222,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy","avatar_url":"https://avatars.githubusercontent.com/u/13409222?v=4","gravatar_id":"","url":"https://api.github.com/users/electron","html_url":"https://github.com/electron","followers_url":"https://api.github.com/users/electron/followers","following_url":"https://api.github.com/users/electron/following{/other_user}","gists_url":"https://api.github.com/users/electron/gists{/gist_id}","starred_url":"https://api.github.com/users/electron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electron/subscriptions","organizations_url":"https://api.github.com/users/electron/orgs","repos_url":"https://api.github.com/users/electron/repos","events_url":"https://api.github.com/users/electron/events{/privacy}","received_events_url":"https://api.github.com/users/electron/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/electron/electron","description":":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS","fork":false,"url":"https://api.github.com/repos/electron/electron","forks_url":"https://api.github.com/repos/electron/electron/forks","keys_url":"https://api.github.com/repos/electron/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/electron/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/electron/electron/teams","hooks_url":"https://api.github.com/repos/electron/electron/hooks","issue_events_url":"https://api.github.com/repos/electron/electron/issues/events{/number}","events_url":"https://api.github.com/repos/electron/electron/events","assignees_url":"https://api.github.com/repos/electron/electron/assignees{/user}","branches_url":"https://api.github.com/repos/electron/electron/branches{/branch}","tags_url":"https://api.github.com/repos/electron/electron/tags","blobs_url":"https://api.github.com/repos/electron/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/electron/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/electron/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/electron/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/electron/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/electron/electron/languages","stargazers_url":"https://api.github.com/repos/electron/electron/stargazers","contributors_url":"https://api.github.com/repos/electron/electron/contributors","subscribers_url":"https://api.github.com/repos/electron/electron/subscribers","subscription_url":"https://api.github.com/repos/electron/electron/subscription","commits_url":"https://api.github.com/repos/electron/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/electron/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/electron/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/electron/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/electron/electron/contents/{+path}","compare_url":"https://api.github.com/repos/electron/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/electron/electron/merges","archive_url":"https://api.github.com/repos/electron/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/electron/electron/downloads","issues_url":"https://api.github.com/repos/electron/electron/issues{/number}","pulls_url":"https://api.github.com/repos/electron/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/electron/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/electron/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/electron/electron/labels{/name}","releases_url":"https://api.github.com/repos/electron/electron/releases{/id}","deployments_url":"https://api.github.com/repos/electron/electron/deployments","created_at":"2013-04-12T01:47:36Z","updated_at":"2024-09-20T03:36:40Z","pushed_at":"2024-09-20T03:35:04Z","git_url":"git://github.com/electron/electron.git","ssh_url":"git@github.com:electron/electron.git","clone_url":"https://github.com/electron/electron.git","svn_url":"https://github.com/electron/electron","homepage":"https://electronjs.org","size":156304,"stargazers_count":113719,"watchers_count":113719,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"has_discussions":false,"forks_count":15312,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":946,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":["c-plus-plus","chrome","css","electron","html","javascript","nodejs","v8","works-with-codespaces"],"visibility":"public","forks":15312,"open_issues":946,"watchers":113719,"default_branch":"main"}},"_links":{"self":{"href":"https://api.github.com/repos/electron/electron/pulls/40076"},"html":{"href":"https://github.com/electron/electron/pull/40076"},"issue":{"href":"https://api.github.com/repos/electron/electron/issues/40076"},"comments":{"href":"https://api.github.com/repos/electron/electron/issues/40076/comments"},"review_comments":{"href":"https://api.github.com/repos/electron/electron/pulls/40076/comments"},"review_comment":{"href":"https://api.github.com/repos/electron/electron/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/electron/electron/pulls/40076/commits"},"statuses":{"href":"https://api.github.com/repos/electron/electron/statuses/6a695f015bac8388dc450b46f548288bff58a433"}},"author_association":"CONTRIBUTOR","auto_merge":null,"active_lock_reason":null}} \ No newline at end of file diff --git a/spec-main/fixtures/sub-frames/debug-frames.html b/spec/fixtures/sub-frames/debug-frames.html similarity index 100% rename from spec-main/fixtures/sub-frames/debug-frames.html rename to spec/fixtures/sub-frames/debug-frames.html diff --git a/spec-main/fixtures/sub-frames/frame-container-webview.html b/spec/fixtures/sub-frames/frame-container-webview.html similarity index 81% rename from spec-main/fixtures/sub-frames/frame-container-webview.html rename to spec/fixtures/sub-frames/frame-container-webview.html index aabc9e87e1a19..98c30790890b3 100644 --- a/spec-main/fixtures/sub-frames/frame-container-webview.html +++ b/spec/fixtures/sub-frames/frame-container-webview.html @@ -8,6 +8,6 @@ This is the root page with a webview - + diff --git a/spec-main/fixtures/sub-frames/frame-container.html b/spec/fixtures/sub-frames/frame-container.html similarity index 83% rename from spec-main/fixtures/sub-frames/frame-container.html rename to spec/fixtures/sub-frames/frame-container.html index f731555a5ddaf..48e1e12150be4 100644 --- a/spec-main/fixtures/sub-frames/frame-container.html +++ b/spec/fixtures/sub-frames/frame-container.html @@ -8,6 +8,6 @@ This is the root page - + \ No newline at end of file diff --git a/spec-main/fixtures/sub-frames/frame-with-frame-container-webview.html b/spec/fixtures/sub-frames/frame-with-frame-container-webview.html similarity index 100% rename from spec-main/fixtures/sub-frames/frame-with-frame-container-webview.html rename to spec/fixtures/sub-frames/frame-with-frame-container-webview.html diff --git a/spec-main/fixtures/sub-frames/frame-with-frame-container.html b/spec/fixtures/sub-frames/frame-with-frame-container.html similarity index 100% rename from spec-main/fixtures/sub-frames/frame-with-frame-container.html rename to spec/fixtures/sub-frames/frame-with-frame-container.html diff --git a/spec-main/fixtures/sub-frames/frame-with-frame.html b/spec/fixtures/sub-frames/frame-with-frame.html similarity index 84% rename from spec-main/fixtures/sub-frames/frame-with-frame.html rename to spec/fixtures/sub-frames/frame-with-frame.html index 9d99fef71b332..3f46a8adab9d3 100644 --- a/spec-main/fixtures/sub-frames/frame-with-frame.html +++ b/spec/fixtures/sub-frames/frame-with-frame.html @@ -8,6 +8,6 @@ This is a frame, is has one child - + \ No newline at end of file diff --git a/spec-main/fixtures/sub-frames/frame.html b/spec/fixtures/sub-frames/frame.html similarity index 100% rename from spec-main/fixtures/sub-frames/frame.html rename to spec/fixtures/sub-frames/frame.html diff --git a/spec/fixtures/sub-frames/preload.js b/spec/fixtures/sub-frames/preload.js new file mode 100644 index 0000000000000..a1f7ca4be4754 --- /dev/null +++ b/spec/fixtures/sub-frames/preload.js @@ -0,0 +1,13 @@ +const { ipcRenderer, webFrame } = require('electron'); + +window.isolatedGlobal = true; + +ipcRenderer.send('preload-ran', window.location.href, webFrame.frameToken); + +ipcRenderer.on('preload-ping', () => { + ipcRenderer.send('preload-pong', webFrame.frameToken); +}); + +window.addEventListener('unload', () => { + ipcRenderer.send('preload-unload', window.location.href); +}); diff --git a/spec-main/fixtures/sub-frames/test.js b/spec/fixtures/sub-frames/test.js similarity index 100% rename from spec-main/fixtures/sub-frames/test.js rename to spec/fixtures/sub-frames/test.js diff --git a/spec/fixtures/sub-frames/webview-iframe-preload.js b/spec/fixtures/sub-frames/webview-iframe-preload.js new file mode 100644 index 0000000000000..1fb3e6d2c22c9 --- /dev/null +++ b/spec/fixtures/sub-frames/webview-iframe-preload.js @@ -0,0 +1,19 @@ +const { ipcRenderer } = require('electron'); + +if (process.isMainFrame) { + window.addEventListener('DOMContentLoaded', () => { + const webview = document.createElement('webview'); + webview.src = 'about:blank'; + webview.setAttribute('webpreferences', 'contextIsolation=no'); + webview.addEventListener( + 'did-finish-load', + () => { + ipcRenderer.send('webview-loaded'); + }, + { once: true } + ); + document.body.appendChild(webview); + }); +} else { + ipcRenderer.send('preload-in-frame'); +} diff --git a/spec/fixtures/test.asar/a.asar b/spec/fixtures/test.asar/a.asar index 0b74f5639cd8a..852f460b6d548 100644 Binary files a/spec/fixtures/test.asar/a.asar and b/spec/fixtures/test.asar/a.asar differ diff --git a/spec/fixtures/test.asar/echo.asar b/spec/fixtures/test.asar/echo.asar index 4d72f7a92a7bb..b7caacca17950 100644 Binary files a/spec/fixtures/test.asar/echo.asar and b/spec/fixtures/test.asar/echo.asar differ diff --git a/spec/fixtures/test.asar/empty.asar b/spec/fixtures/test.asar/empty.asar index 10cddfb67654e..2c4be954d306e 100644 Binary files a/spec/fixtures/test.asar/empty.asar and b/spec/fixtures/test.asar/empty.asar differ diff --git a/spec/fixtures/test.asar/logo.asar b/spec/fixtures/test.asar/logo.asar index fe21fd9ab7b3c..4c2c9f6020b64 100644 Binary files a/spec/fixtures/test.asar/logo.asar and b/spec/fixtures/test.asar/logo.asar differ diff --git a/spec/fixtures/test.asar/repack.js b/spec/fixtures/test.asar/repack.js new file mode 100644 index 0000000000000..d85dc01e750c0 --- /dev/null +++ b/spec/fixtures/test.asar/repack.js @@ -0,0 +1,23 @@ +// Use this script to regenerate these fixture files +// using a new version of the asar package + +const asar = require('@electron/asar'); + +const fs = require('node:fs'); +const os = require('node:os'); +const path = require('node:path'); + +const archives = []; +for (const child of fs.readdirSync(__dirname)) { + if (child.endsWith('.asar')) { + archives.push(path.resolve(__dirname, child)); + } +} + +for (const archive of archives) { + const tmp = fs.mkdtempSync(path.resolve(os.tmpdir(), 'asar-spec-')); + asar.extractAll(archive, tmp); + asar.createPackageWithOptions(tmp, archive, { + unpack: fs.existsSync(archive + '.unpacked') ? '*' : undefined + }); +} diff --git a/spec/fixtures/test.asar/script.asar b/spec/fixtures/test.asar/script.asar index 7239786ec90ea..1b7f3e23fb72e 100755 Binary files a/spec/fixtures/test.asar/script.asar and b/spec/fixtures/test.asar/script.asar differ diff --git a/spec/fixtures/test.asar/unpack.asar b/spec/fixtures/test.asar/unpack.asar index 8c1231c1b230a..de64d63853a5e 100644 Binary files a/spec/fixtures/test.asar/unpack.asar and b/spec/fixtures/test.asar/unpack.asar differ diff --git a/spec/fixtures/test.asar/video.asar b/spec/fixtures/test.asar/video.asar index 3d31a6e589568..d73dee7b84fbb 100644 Binary files a/spec/fixtures/test.asar/video.asar and b/spec/fixtures/test.asar/video.asar differ diff --git a/spec/fixtures/test.asar/web.asar b/spec/fixtures/test.asar/web.asar index 1e9db65b8128e..3057de38030b6 100644 Binary files a/spec/fixtures/test.asar/web.asar and b/spec/fixtures/test.asar/web.asar differ diff --git a/spec/fixtures/test.asar/worker_threads.asar b/spec/fixtures/test.asar/worker_threads.asar new file mode 100644 index 0000000000000..5c7db28525895 Binary files /dev/null and b/spec/fixtures/test.asar/worker_threads.asar differ diff --git a/spec/fixtures/testsnap.js b/spec/fixtures/testsnap.js index 3ac89c522a8bb..2859f8ecfa3de 100644 --- a/spec/fixtures/testsnap.js +++ b/spec/fixtures/testsnap.js @@ -1,3 +1,8 @@ -// taken from https://chromium.googlesource.com/v8/v8.git/+/HEAD/test/cctest/test-serialize.cc#1127 -function f () { return g() * 2; } // eslint-disable-line no-unused-vars -function g () { return 43; } +// taken from https://chromium.googlesource.com/v8/v8.git/+/HEAD/test/cctest/test-serialize.cc +// eslint-disable-next-line @typescript-eslint/no-unused-vars +function f() { + return g() * 2; +} +function g() { + return 43; +} diff --git a/spec/fixtures/type-stripping/basic.ts b/spec/fixtures/type-stripping/basic.ts new file mode 100644 index 0000000000000..fda0232351fc4 --- /dev/null +++ b/spec/fixtures/type-stripping/basic.ts @@ -0,0 +1,7 @@ +import { app } from 'electron/main'; + +const logMessage = (message: string): void => console.log(message); + +logMessage('running'); + +app.exit(0); diff --git a/spec/fixtures/type-stripping/transform-types-node.ts b/spec/fixtures/type-stripping/transform-types-node.ts new file mode 100644 index 0000000000000..c8614e285bf31 --- /dev/null +++ b/spec/fixtures/type-stripping/transform-types-node.ts @@ -0,0 +1,9 @@ +enum Test { + A, + B, + C +} + +console.log(Test.A); + +process.exit(0); diff --git a/spec/fixtures/type-stripping/transform-types.ts b/spec/fixtures/type-stripping/transform-types.ts new file mode 100644 index 0000000000000..0959ffde7c7c9 --- /dev/null +++ b/spec/fixtures/type-stripping/transform-types.ts @@ -0,0 +1,11 @@ +import { app } from 'electron/main'; + +enum Test { + A, + B, + C +} + +console.log(Test.A); + +app.exit(0); diff --git a/spec/fixtures/webview/fullscreen/frame.html b/spec/fixtures/webview/fullscreen/frame.html new file mode 100644 index 0000000000000..d7307f0b83bc4 --- /dev/null +++ b/spec/fixtures/webview/fullscreen/frame.html @@ -0,0 +1,13 @@ + +
+ WebView +
+ + + diff --git a/spec/fixtures/webview/fullscreen/main.html b/spec/fixtures/webview/fullscreen/main.html new file mode 100644 index 0000000000000..aeb460578f97d --- /dev/null +++ b/spec/fixtures/webview/fullscreen/main.html @@ -0,0 +1,12 @@ + + + + diff --git a/spec/fixtures/workers/audio_worklet_node.js b/spec/fixtures/workers/audio_worklet_node.js new file mode 100644 index 0000000000000..ee07cc714d4bf --- /dev/null +++ b/spec/fixtures/workers/audio_worklet_node.js @@ -0,0 +1,29 @@ +// Reports whether the Node.js environment is wired up inside this +// AudioWorklet's global scope. Used by spec/fixtures/pages/audio-worklet.html +// to verify that nodeIntegrationInWorker keeps working when Blink reuses a +// pooled worker thread for multiple AudioWorklet contexts. +class NodeIntegrationProbeProcessor extends AudioWorkletProcessor { + constructor() { + super(); + this.port.onmessage = () => { + let info; + try { + // require should be a function and `node:timers` should resolve. + const ok = + typeof require === 'function' && + typeof require('node:timers').setImmediate === 'function' && + typeof process === 'object'; + info = ok ? 'ok' : 'missing'; + } catch (err) { + info = `throw: ${err && err.message ? err.message : err}`; + } + this.port.postMessage(info); + }; + } + + process() { + return true; + } +} + +registerProcessor('node-integration-probe', NodeIntegrationProbeProcessor); diff --git a/spec/fixtures/workers/load_shared_worker.html b/spec/fixtures/workers/load_shared_worker.html new file mode 100644 index 0000000000000..acee01f439d94 --- /dev/null +++ b/spec/fixtures/workers/load_shared_worker.html @@ -0,0 +1,15 @@ + + diff --git a/spec/fixtures/workers/load_worker.html b/spec/fixtures/workers/load_worker.html new file mode 100644 index 0000000000000..267b465939c2c --- /dev/null +++ b/spec/fixtures/workers/load_worker.html @@ -0,0 +1,14 @@ + diff --git a/spec/fixtures/workers/worker_node_fetch.js b/spec/fixtures/workers/worker_node_fetch.js new file mode 100644 index 0000000000000..abbf00126c0e5 --- /dev/null +++ b/spec/fixtures/workers/worker_node_fetch.js @@ -0,0 +1 @@ +self.postMessage([typeof fetch, typeof Response, typeof Request, typeof Headers, typeof FormData].join(' ')); diff --git a/spec/fixtures/workers/workers.asar b/spec/fixtures/workers/workers.asar new file mode 100644 index 0000000000000..599c694bb746e Binary files /dev/null and b/spec/fixtures/workers/workers.asar differ diff --git a/spec/fixtures/zip/a.zip b/spec/fixtures/zip/a.zip deleted file mode 100644 index 7b3a13209f551..0000000000000 Binary files a/spec/fixtures/zip/a.zip and /dev/null differ diff --git a/spec/fuses-spec.ts b/spec/fuses-spec.ts new file mode 100644 index 0000000000000..bd8f4de1efc9f --- /dev/null +++ b/spec/fuses-spec.ts @@ -0,0 +1,121 @@ +import { BrowserWindow } from 'electron'; + +import { expect } from 'chai'; + +import { spawn, spawnSync } from 'node:child_process'; +import { once } from 'node:events'; +import path = require('node:path'); + +import { startRemoteControlApp } from './lib/spec-helpers'; + +describe('fuses', () => { + it('can be enabled by command-line argument during testing', async () => { + const child0 = spawn(process.execPath, ['-v'], { env: { NODE_OPTIONS: '-e 0' } }); + const [code0] = await once(child0, 'exit'); + // Should exit with 9 because -e is not allowed in NODE_OPTIONS + expect(code0).to.equal(9); + const child1 = spawn(process.execPath, ['--set-fuse-node_options=0', '-v'], { env: { NODE_OPTIONS: '-e 0' } }); + const [code1] = await once(child1, 'exit'); + // Should print the version and exit with 0 + expect(code1).to.equal(0); + }); + + it('disables --inspect flag when node_cli_inspect is 0', () => { + const { status, stderr } = spawnSync(process.execPath, ['--set-fuse-node_cli_inspect=0', '--inspect', '-v'], { + encoding: 'utf-8' + }); + expect(stderr).to.not.include('Debugger listening on ws://'); + // Should print the version and exit with 0 + expect(status).to.equal(0); + }); + + it('disables fetching file:// URLs when grant_file_protocol_extra_privileges is 0', async () => { + const rc = await startRemoteControlApp(['--set-fuse-grant_file_protocol_extra_privileges=0']); + await expect( + rc.remotely( + async (fixture: string) => { + const bw = new BrowserWindow({ show: false }); + await bw.loadFile(fixture); + return await bw.webContents.executeJavaScript("ajax('file:///etc/passwd')"); + }, + path.join(__dirname, 'fixtures', 'pages', 'fetch.html') + ) + ).to.eventually.be.rejectedWith('Failed to fetch'); + }); + + describe('cookie_encryption', () => { + it('allows setting and retrieving cookies when enabled', async () => { + const rc = await startRemoteControlApp(['--set-fuse-cookie_encryption=1']); + const result = await rc.remotely(async () => { + const { session } = require('electron'); + const ses = session.defaultSession; + const testUrl = 'https://example.com'; + + await ses.clearStorageData({ storages: ['cookies'] }); + + await ses.cookies.set({ + url: testUrl, + name: 'test_cookie', + value: 'encrypted_value_12345', + expirationDate: Math.floor(Date.now() / 1000) + 3600 + }); + + await ses.cookies.set({ + url: testUrl, + name: 'secure_cookie', + value: 'secret_data_67890', + secure: true, + httpOnly: true, + expirationDate: Math.floor(Date.now() / 1000) + 7200 + }); + + const cookies = await ses.cookies.get({ url: testUrl }); + const testCookie = cookies.find((c: Electron.Cookie) => c.name === 'test_cookie'); + const secureCookie = cookies.find((c: Electron.Cookie) => c.name === 'secure_cookie'); + + return { + cookieCount: cookies.length, + testCookieValue: testCookie?.value, + secureCookieValue: secureCookie?.value, + secureCookieIsSecure: secureCookie?.secure, + secureCookieIsHttpOnly: secureCookie?.httpOnly + }; + }); + + expect(result.cookieCount).to.equal(2); + expect(result.testCookieValue).to.equal('encrypted_value_12345'); + expect(result.secureCookieValue).to.equal('secret_data_67890'); + expect(result.secureCookieIsSecure).to.be.true(); + expect(result.secureCookieIsHttpOnly).to.be.true(); + }); + + it('persists cookies across sessions when enabled', async () => { + const rc = await startRemoteControlApp(['--set-fuse-cookie_encryption=1']); + + await rc.remotely(async () => { + const { session } = require('electron'); + await session.defaultSession.clearStorageData({ storages: ['cookies'] }); + await session.defaultSession.cookies.set({ + url: 'https://example.com', + name: 'persistent_cookie', + value: 'persist_me', + expirationDate: Math.floor(Date.now() / 1000) + 86400 + }); + }); + + await rc.remotely(async () => { + const { session } = require('electron'); + await session.defaultSession.cookies.flushStore(); + }); + + const result = await rc.remotely(async () => { + const { session } = require('electron'); + const cookies = await session.defaultSession.cookies.get({ url: 'https://example.com' }); + const cookie = cookies.find((c: Electron.Cookie) => c.name === 'persistent_cookie'); + return cookie?.value; + }); + + expect(result).to.equal('persist_me'); + }); + }); +}); diff --git a/spec/get-files.ts b/spec/get-files.ts new file mode 100644 index 0000000000000..09985ce00e98b --- /dev/null +++ b/spec/get-files.ts @@ -0,0 +1,12 @@ +import * as fs from 'node:fs'; +import * as path from 'node:path'; + +export async function getFiles( + dir: string, + test: (file: string) => boolean = (_: string) => true // eslint-disable-line @typescript-eslint/no-unused-vars +): Promise { + return fs.promises + .readdir(dir) + .then((files) => files.map((file) => path.join(dir, file))) + .then((files) => files.filter((file) => test(file))); +} diff --git a/spec/guest-window-manager-spec.ts b/spec/guest-window-manager-spec.ts new file mode 100644 index 0000000000000..9021cc939c6fd --- /dev/null +++ b/spec/guest-window-manager-spec.ts @@ -0,0 +1,578 @@ +import { BrowserWindow, screen } from 'electron'; + +import { expect, assert } from 'chai'; + +import { once } from 'node:events'; +import * as http from 'node:http'; +import * as nodePath from 'node:path'; + +import { HexColors, ScreenCapture, hasCapturableScreen } from './lib/screen-helpers'; +import { ifit, listen } from './lib/spec-helpers'; +import { closeAllWindows } from './lib/window-helpers'; + +describe('webContents.setWindowOpenHandler', () => { + describe('native window', () => { + let browserWindow: BrowserWindow; + beforeEach(async () => { + browserWindow = new BrowserWindow({ show: false }); + await browserWindow.loadURL('about:blank'); + }); + + afterEach(closeAllWindows); + + it('does not fire window creation events if the handler callback throws an error', (done) => { + const error = new Error('oh no'); + const listeners = process.listeners('uncaughtException'); + process.removeAllListeners('uncaughtException'); + process.on('uncaughtException', (thrown) => { + try { + expect(thrown).to.equal(error); + done(); + } catch (e) { + done(e); + } finally { + process.removeAllListeners('uncaughtException'); + for (const listener of listeners) { + process.on('uncaughtException', listener); + } + } + }); + + browserWindow.webContents.on('did-create-window', () => { + assert.fail('did-create-window should not be called with an overridden window.open'); + }); + + browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true"); + + browserWindow.webContents.setWindowOpenHandler(() => { + throw error; + }); + }); + + it('does not fire window creation events if the handler callback returns a bad result', async () => { + const bad = new Promise((resolve) => { + browserWindow.webContents.setWindowOpenHandler(() => { + setTimeout(resolve); + return [1, 2, 3] as any; + }); + }); + + browserWindow.webContents.on('did-create-window', () => { + assert.fail('did-create-window should not be called with an overridden window.open'); + }); + + browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true"); + + await bad; + }); + + it('does not fire window creation events if an override returns action: deny', async () => { + const denied = new Promise((resolve) => { + browserWindow.webContents.setWindowOpenHandler(() => { + setTimeout(resolve); + return { action: 'deny' }; + }); + }); + + browserWindow.webContents.on('did-create-window', () => { + assert.fail('did-create-window should not be called with an overridden window.open'); + }); + + browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true"); + + await denied; + }); + + it('is called when clicking on a target=_blank link', async () => { + const denied = new Promise((resolve) => { + browserWindow.webContents.setWindowOpenHandler(() => { + setTimeout(resolve); + return { action: 'deny' }; + }); + }); + + browserWindow.webContents.on('did-create-window', () => { + assert.fail('did-create-window should not be called with an overridden window.open'); + }); + + await browserWindow.webContents.loadURL( + 'data:text/html,link' + ); + browserWindow.webContents.sendInputEvent({ type: 'mouseDown', x: 10, y: 10, button: 'left', clickCount: 1 }); + browserWindow.webContents.sendInputEvent({ type: 'mouseUp', x: 10, y: 10, button: 'left', clickCount: 1 }); + + await denied; + }); + + it('is called when shift-clicking on a link', async () => { + const denied = new Promise((resolve) => { + browserWindow.webContents.setWindowOpenHandler(() => { + setTimeout(resolve); + return { action: 'deny' }; + }); + }); + + browserWindow.webContents.on('did-create-window', () => { + assert.fail('did-create-window should not be called with an overridden window.open'); + }); + + await browserWindow.webContents.loadURL( + 'data:text/html,link' + ); + browserWindow.webContents.sendInputEvent({ + type: 'mouseDown', + x: 10, + y: 10, + button: 'left', + clickCount: 1, + modifiers: ['shift'] + }); + browserWindow.webContents.sendInputEvent({ + type: 'mouseUp', + x: 10, + y: 10, + button: 'left', + clickCount: 1, + modifiers: ['shift'] + }); + + await denied; + }); + + it('fires handler with correct params', async () => { + const testFrameName = 'test-frame-name'; + const testFeatures = 'top=10&left=10&something-unknown&show=no'; + const testUrl = 'app://does-not-exist/'; + const details = await new Promise((resolve) => { + browserWindow.webContents.setWindowOpenHandler((details) => { + setTimeout(() => resolve(details)); + return { action: 'deny' }; + }); + + browserWindow.webContents.executeJavaScript( + `window.open('${testUrl}', '${testFrameName}', '${testFeatures}') && true` + ); + }); + const { url, frameName, features, disposition, referrer } = details; + expect(url).to.equal(testUrl); + expect(frameName).to.equal(testFrameName); + expect(features).to.equal(testFeatures); + expect(disposition).to.equal('new-window'); + expect(referrer).to.deep.equal({ + policy: 'strict-origin-when-cross-origin', + url: '' + }); + }); + + it('includes post body', async () => { + const details = await new Promise((resolve) => { + browserWindow.webContents.setWindowOpenHandler((details) => { + setTimeout(() => resolve(details)); + return { action: 'deny' }; + }); + + browserWindow.webContents.loadURL( + `data:text/html,${encodeURIComponent(` +
+ +
+ + `)}` + ); + }); + const { url, frameName, features, disposition, referrer, postBody } = details; + expect(url).to.equal('http://example.com/'); + expect(frameName).to.equal(''); + expect(features).to.deep.equal(''); + expect(disposition).to.equal('foreground-tab'); + expect(referrer).to.deep.equal({ + policy: 'strict-origin-when-cross-origin', + url: '' + }); + expect(postBody).to.deep.equal({ + contentType: 'application/x-www-form-urlencoded', + data: [ + { + type: 'rawData', + bytes: Buffer.from('key=value') + } + ] + }); + }); + + it('does fire window creation events if an override returns action: allow', async () => { + browserWindow.webContents.setWindowOpenHandler(() => ({ action: 'allow' })); + + setImmediate(() => { + browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true"); + }); + + await once(browserWindow.webContents, 'did-create-window'); + }); + + it('reuses an existing window when window.open is called with the same frame name', async () => { + let handlerCallCount = 0; + browserWindow.webContents.setWindowOpenHandler(() => { + handlerCallCount++; + return { action: 'allow' }; + }); + + const didCreateWindow = once(browserWindow.webContents, 'did-create-window') as Promise< + [BrowserWindow, Electron.DidCreateWindowDetails] + >; + await browserWindow.webContents.executeJavaScript( + "window.open('about:blank?one', 'named-target', 'show=no') && true" + ); + const [childWindow] = await didCreateWindow; + expect(handlerCallCount).to.equal(1); + expect(childWindow.webContents.getURL()).to.equal('about:blank?one'); + + browserWindow.webContents.on('did-create-window', () => { + assert.fail('did-create-window should not fire when reusing a named window'); + }); + + const didNavigate = once(childWindow.webContents, 'did-navigate'); + const sameWindow = await browserWindow.webContents.executeJavaScript(` + (() => { + const first = window.open('about:blank?one', 'named-target', 'show=no'); + const second = window.open('about:blank?two', 'named-target', 'show=no'); + return first === second; + })() + `); + await didNavigate; + + expect(sameWindow).to.be.true('window.open with matching frame name should return the same window proxy'); + expect(handlerCallCount).to.equal( + 1, + 'setWindowOpenHandler should not be called when Blink resolves the named target' + ); + expect(childWindow.webContents.getURL()).to.equal('about:blank?two'); + expect(BrowserWindow.getAllWindows()).to.have.lengthOf(2); + }); + + it('can change webPreferences of child windows', async () => { + browserWindow.webContents.setWindowOpenHandler(() => ({ + action: 'allow', + overrideBrowserWindowOptions: { webPreferences: { defaultFontSize: 30 } } + })); + + const didCreateWindow = once(browserWindow.webContents, 'did-create-window') as Promise< + [BrowserWindow, Electron.DidCreateWindowDetails] + >; + browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true"); + const [childWindow] = await didCreateWindow; + + await childWindow.webContents.executeJavaScript("document.write('hello')"); + const size = await childWindow.webContents.executeJavaScript( + "getComputedStyle(document.querySelector('body')).fontSize" + ); + expect(size).to.equal('30px'); + }); + + it('does not hang parent window when denying window.open', async () => { + browserWindow.webContents.setWindowOpenHandler(() => ({ action: 'deny' })); + browserWindow.webContents.executeJavaScript("window.open('https://127.0.0.1')"); + expect(await browserWindow.webContents.executeJavaScript('42')).to.equal(42); + }); + + it('does not propagate non-allowlisted features-string options like icon to the BrowserWindow', async () => { + browserWindow.webContents.setWindowOpenHandler(() => ({ action: 'allow' })); + + const didCreateWindow = once(browserWindow.webContents, 'did-create-window') as Promise< + [BrowserWindow, Electron.DidCreateWindowDetails] + >; + browserWindow.webContents.executeJavaScript( + "window.open('about:blank', '', 'show=no,width=400,icon=/tmp/does-not-exist.png') && true" + ); + const [, details] = await didCreateWindow; + + expect(details.options).to.not.have.property('icon'); + expect(details.options.width).to.equal(400); + expect(details.options.show).to.equal(false); + }); + + it('still allows the main process to set icon via overrideBrowserWindowOptions', async () => { + const iconPath = nodePath.join(__dirname, 'fixtures', 'assets', 'icon.ico'); + browserWindow.webContents.setWindowOpenHandler(() => ({ + action: 'allow', + overrideBrowserWindowOptions: { icon: iconPath } + })); + + const didCreateWindow = once(browserWindow.webContents, 'did-create-window') as Promise< + [BrowserWindow, Electron.DidCreateWindowDetails] + >; + browserWindow.webContents.executeJavaScript( + "window.open('about:blank', '', 'show=no,icon=/tmp/attacker.png') && true" + ); + const [, details] = await didCreateWindow; + + expect((details.options as any).icon).to.equal(iconPath); + }); + + it('can open an offscreen child window from an onscreen parent', async () => { + browserWindow.webContents.setWindowOpenHandler(() => ({ + action: 'allow', + overrideBrowserWindowOptions: { + webPreferences: { + offscreen: true + } + } + })); + + const didCreateWindow = once(browserWindow.webContents, 'did-create-window'); + const url = `file://${nodePath.join('fixtures', 'pages', 'content.html')}`; + browserWindow.webContents.executeJavaScript(`window.open('${JSON.stringify(url)}') && true`); + const [childWindow] = await didCreateWindow; + expect(childWindow.webContents.isOffscreen()).to.be.true('Child window should be offscreen'); + }); + + it('can open an onscreen child window from an offscreen parent', async () => { + const obw = new BrowserWindow({ + show: false, + webPreferences: { + offscreen: true + } + }); + + await obw.loadURL('about:blank'); + obw.webContents.setWindowOpenHandler(() => ({ action: 'allow' })); + + const didCreateWindow = once(obw.webContents, 'did-create-window'); + const url = `file://${nodePath.join('fixtures', 'pages', 'content.html')}`; + obw.webContents.executeJavaScript(`window.open('${JSON.stringify(url)}') && true`); + const [childWindow] = await didCreateWindow; + expect(childWindow.webContents.isOffscreen()).to.be.false('Child window should not be offscreen'); + }); + + it('can open an offscreen child window from an offscreen parent', async () => { + const obw = new BrowserWindow({ + show: false, + webPreferences: { + offscreen: true + } + }); + + await obw.loadURL('about:blank'); + obw.webContents.setWindowOpenHandler(() => ({ + action: 'allow', + overrideBrowserWindowOptions: { + webPreferences: { + offscreen: true + } + } + })); + + const didCreateWindow = once(obw.webContents, 'did-create-window'); + const url = `file://${nodePath.join('fixtures', 'pages', 'content.html')}`; + obw.webContents.executeJavaScript(`window.open('${JSON.stringify(url)}') && true`); + const [childWindow] = await didCreateWindow; + expect(childWindow.webContents.isOffscreen()).to.be.true('Child window should be offscreen'); + }); + + ifit(hasCapturableScreen())('should not make child window background transparent', async () => { + browserWindow.webContents.setWindowOpenHandler(() => ({ action: 'allow' })); + const didCreateWindow = once(browserWindow.webContents, 'did-create-window'); + browserWindow.webContents.executeJavaScript("window.open('about:blank') && true"); + const [childWindow] = await didCreateWindow; + const display = screen.getPrimaryDisplay(); + childWindow.setBounds(display.bounds); + await childWindow.webContents.executeJavaScript( + "const meta = document.createElement('meta'); meta.name = 'color-scheme'; meta.content = 'dark'; document.head.appendChild(meta); true;" + ); + const screenCapture = new ScreenCapture(display); + // color-scheme is set to dark so background should not be white + await screenCapture.expectColorAtCenterDoesNotMatch(HexColors.WHITE); + }); + }); + + describe('custom window', () => { + let browserWindow: BrowserWindow; + + let server: http.Server; + let url: string; + + before(async () => { + server = http.createServer((request, response) => { + switch (request.url) { + case '/index': + response.statusCode = 200; + response.end('Index page'); + break; + case '/child': + response.statusCode = 200; + response.end('Child page'); + break; + case '/test': + response.statusCode = 200; + response.end('Test page'); + break; + default: + throw new Error(`Unsupported endpoint: ${request.url}`); + } + }); + + url = (await listen(server)).url; + }); + + after(() => { + server.close(); + }); + + beforeEach(async () => { + browserWindow = new BrowserWindow({ show: false }); + await browserWindow.loadURL(`${url}/index`); + }); + + afterEach(closeAllWindows); + + it('throws error when created window uses invalid webcontents', async () => { + const listeners = process.listeners('uncaughtException'); + process.removeAllListeners('uncaughtException'); + const uncaughtExceptionEmitted = new Promise((resolve, reject) => { + process.on('uncaughtException', (thrown) => { + try { + expect(thrown.message).to.equal( + 'Invalid webContents. Created window should be connected to webContents passed with options object.' + ); + resolve(); + } catch (e) { + reject(e); + } finally { + process.removeAllListeners('uncaughtException'); + listeners.forEach((listener) => process.on('uncaughtException', listener)); + } + }); + }); + + browserWindow.webContents.setWindowOpenHandler(() => { + return { + action: 'allow', + createWindow: () => { + const childWindow = new BrowserWindow({ title: 'New window' }); + return childWindow.webContents; + } + }; + }); + + browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true"); + + await uncaughtExceptionEmitted; + }); + + it('spawns browser window when createWindow is provided', async () => { + const browserWindowTitle = 'Child browser window'; + + const childWindow = await new Promise((resolve) => { + browserWindow.webContents.setWindowOpenHandler(() => { + return { + action: 'allow', + createWindow: (options) => { + const childWindow = new BrowserWindow({ ...options, title: browserWindowTitle }); + resolve(childWindow); + return childWindow.webContents; + } + }; + }); + + browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true"); + }); + + expect(childWindow.title).to.equal(browserWindowTitle); + }); + + it('should be able to access the child window document when createWindow is provided', async () => { + browserWindow.webContents.setWindowOpenHandler(() => { + return { + action: 'allow', + createWindow: (options) => { + const child = new BrowserWindow(options); + return child.webContents; + } + }; + }); + + const aboutBlankTitle = await browserWindow.webContents.executeJavaScript(` + const win1 = window.open('about:blank', '', 'show=no'); + win1.document.title = 'about-blank-title'; + win1.document.title; + `); + expect(aboutBlankTitle).to.equal('about-blank-title'); + + const serverPageTitle = await browserWindow.webContents.executeJavaScript(` + const win2 = window.open('${url}/child', '', 'show=no'); + win2.document.title = 'server-page-title'; + win2.document.title; + `); + expect(serverPageTitle).to.equal('server-page-title'); + }); + + it('spawns browser window with overridden options', async () => { + const childWindow = await new Promise((resolve) => { + browserWindow.webContents.setWindowOpenHandler(() => { + return { + action: 'allow', + overrideBrowserWindowOptions: { + width: 640, + height: 480 + }, + createWindow: (options) => { + expect(options.width).to.equal(640); + expect(options.height).to.equal(480); + const childWindow = new BrowserWindow(options); + resolve(childWindow); + return childWindow.webContents; + } + }; + }); + + browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true"); + }); + + const size = childWindow.getSize(); + expect(size[0]).to.equal(640); + expect(size[1]).to.equal(480); + }); + + it('spawns browser window with access to opener property', async () => { + const childWindow = await new Promise((resolve) => { + browserWindow.webContents.setWindowOpenHandler(() => { + return { + action: 'allow', + createWindow: (options) => { + const childWindow = new BrowserWindow(options); + resolve(childWindow); + return childWindow.webContents; + } + }; + }); + + browserWindow.webContents.executeJavaScript(`window.open('${url}/child', '', 'show=no') && true`); + }); + + await once(childWindow.webContents, 'ready-to-show'); + const childWindowOpenerTitle = await childWindow.webContents.executeJavaScript('window.opener.document.title'); + expect(childWindowOpenerTitle).to.equal(browserWindow.title); + }); + + it('spawns browser window without access to opener property because of noopener attribute ', async () => { + const childWindow = await new Promise((resolve) => { + browserWindow.webContents.setWindowOpenHandler(() => { + return { + action: 'allow', + createWindow: (options) => { + const childWindow = new BrowserWindow(options); + resolve(childWindow); + return childWindow.webContents; + } + }; + }); + browserWindow.webContents.executeJavaScript(`window.open('${url}/child', '', 'noopener,show=no') && true`); + }); + + await once(childWindow.webContents, 'ready-to-show'); + await expect(childWindow.webContents.executeJavaScript('window.opener.document.title')).to.be.rejectedWith( + 'Script failed to execute, this normally means an error was thrown. Check the renderer console for the error.' + ); + }); + }); +}); diff --git a/spec/index.js b/spec/index.js new file mode 100644 index 0000000000000..3dd3bf027e1b8 --- /dev/null +++ b/spec/index.js @@ -0,0 +1,211 @@ +const { app, protocol } = require('electron'); + +const fs = require('node:fs'); +const path = require('node:path'); +const v8 = require('node:v8'); + +const FAILURE_STATUS_KEY = 'Electron_Spec_Runner_Failures'; + +// We want to terminate on errors, not throw up a dialog +process.on('uncaughtException', (err) => { + console.error('Unhandled exception in main spec runner:', err); + process.exit(1); +}); + +// Tell ts-node which tsconfig to use +process.env.TS_NODE_PROJECT = path.resolve(__dirname, '../tsconfig.spec.json'); +process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = 'true'; + +// Some Linux machines have broken hardware acceleration support. +if (process.env.ELECTRON_TEST_DISABLE_HARDWARE_ACCELERATION) { + app.disableHardwareAcceleration(); +} + +v8.setFlagsFromString('--expose_gc'); +app.commandLine.appendSwitch('js-flags', '--expose_gc'); +// Prevent the spec runner quitting when the first window closes +app.on('window-all-closed', () => null); + +// Use fake device for Media Stream to replace actual camera and microphone. +app.commandLine.appendSwitch('use-fake-device-for-media-stream'); +app.commandLine.appendSwitch( + 'host-resolver-rules', + [ + 'MAP localhost2 127.0.0.1', + 'MAP ipv4.localhost2 10.0.0.1', + 'MAP ipv6.localhost2 [::1]', + 'MAP notfound.localhost2 ~NOTFOUND' + ].join(', ') +); + +// Enable features required by tests. +app.commandLine.appendSwitch( + 'enable-features', + [ + // spec/api-web-frame-main-spec.ts + 'DocumentPolicyIncludeJSCallStacksInCrashReports', + // spec/spellchecker-spec.ts - allows spellcheck without user gesture + // https://chromium-review.googlesource.com/c/chromium/src/+/7452579 + 'UnrestrictSpellingAndGrammarForTesting' + ].join(',') +); + +global.standardScheme = 'app'; +global.zoomScheme = 'zoom'; +global.serviceWorkerScheme = 'sw'; +protocol.registerSchemesAsPrivileged([ + { scheme: global.standardScheme, privileges: { standard: true, secure: true, stream: false } }, + { scheme: global.zoomScheme, privileges: { standard: true, secure: true } }, + { scheme: global.serviceWorkerScheme, privileges: { allowServiceWorkers: true, standard: true, secure: true } }, + { scheme: 'http-like', privileges: { standard: true, secure: true, corsEnabled: true, supportFetchAPI: true } }, + { scheme: 'cors-blob', privileges: { corsEnabled: true, supportFetchAPI: true } }, + { scheme: 'cors', privileges: { corsEnabled: true, supportFetchAPI: true } }, + { scheme: 'no-cors', privileges: { supportFetchAPI: true } }, + { scheme: 'no-cors-standard', privileges: { standard: true, supportFetchAPI: true } }, + { scheme: 'no-fetch', privileges: { corsEnabled: true } }, + { scheme: 'stream', privileges: { standard: true, stream: true } }, + { scheme: 'foo', privileges: { standard: true } }, + { scheme: 'bar', privileges: { standard: true } } +]); + +app + .whenReady() + .then(async () => { + require('ts-node/register'); + + const argv = require('yargs') + .boolean('ci') + .array('files') + .string('g') + .alias('g', 'grep') + .boolean('i') + .alias('i', 'invert').argv; + + const Mocha = require('mocha'); + const mochaOptions = { + forbidOnly: process.env.CI + }; + if (process.env.CI) { + mochaOptions.retries = 3; + } + if (process.env.MOCHA_REPORTER) { + mochaOptions.reporter = process.env.MOCHA_REPORTER; + } + if (process.env.MOCHA_MULTI_REPORTERS) { + mochaOptions.reporterOptions = { + reporterEnabled: process.env.MOCHA_MULTI_REPORTERS + }; + } + // The MOCHA_GREP and MOCHA_INVERT are used in some vendor builds for sharding + // tests. + if (process.env.MOCHA_GREP) { + mochaOptions.grep = process.env.MOCHA_GREP; + } + if (process.env.MOCHA_INVERT) { + mochaOptions.invert = process.env.MOCHA_INVERT === 'true'; + } + const mocha = new Mocha(mochaOptions); + + // Add a root hook on mocha to skip any tests that are disabled + const disabledTests = new Set(JSON.parse(fs.readFileSync(path.join(__dirname, 'disabled-tests.json'), 'utf8'))); + mocha.suite.beforeEach(function () { + // TODO(clavin): add support for disabling *suites* by title, not just tests + if (disabledTests.has(this.currentTest?.fullTitle())) { + this.skip(); + } + }); + + // The cleanup method is registered this way rather than through an + // `afterEach` at the top level so that it can run before other `afterEach` + // methods. + // + // The order of events is: + // 1. test completes, + // 2. `defer()`-ed methods run, in reverse order, + // 3. regular `afterEach` hooks run. + const { runCleanupFunctions } = require('./lib/spec-helpers'); + mocha.suite.on('suite', function attach(suite) { + suite.afterEach('cleanup', runCleanupFunctions); + suite.on('suite', attach); + }); + + if (!process.env.MOCHA_REPORTER) { + mocha.ui('bdd').reporter('tap'); + } + const mochaTimeout = process.env.MOCHA_TIMEOUT || 30000; + mocha.timeout(mochaTimeout); + + if (argv.grep) mocha.grep(argv.grep); + if (argv.invert) mocha.invert(); + + const baseElectronDir = path.resolve(__dirname, '..'); + const validTestPaths = + argv.files && + argv.files.map((file) => (path.isAbsolute(file) ? path.relative(baseElectronDir, file) : path.normalize(file))); + const filter = (file) => { + if (!/-spec\.[tj]s$/.test(file)) { + return false; + } + + // This allows you to run specific modules only: + // npm run test -match=menu + const moduleMatch = process.env.npm_config_match ? new RegExp(process.env.npm_config_match, 'g') : null; + if (moduleMatch && !moduleMatch.test(file)) { + return false; + } + + if (validTestPaths && !validTestPaths.includes(path.relative(baseElectronDir, file))) { + return false; + } + + return true; + }; + + const { getFiles } = require('./get-files'); + const testFiles = await getFiles(__dirname, filter); + for (const file of testFiles.sort()) { + mocha.addFile(file); + } + + if (validTestPaths && validTestPaths.length > 0 && testFiles.length === 0) { + console.error('Test files were provided, but they did not match any searched files'); + console.error('provided file paths (relative to electron/):', validTestPaths); + process.exit(1); + } + + const cb = () => { + // Ensure the callback is called after runner is defined + process.nextTick(() => { + if (process.env.ELECTRON_FORCE_TEST_SUITE_EXIT === 'true') { + console.log(`${FAILURE_STATUS_KEY}: ${runner.failures}`); + process.kill(process.pid); + } else { + process.exit(runner.failures); + } + }); + }; + + // Set up chai in the correct order + const chai = require('chai'); + chai.use(require('chai-as-promised')); + chai.use(require('dirty-chai')); + + // Show full object diff + // https://github.com/chaijs/chai/issues/469 + chai.config.truncateThreshold = 0; + + const runner = mocha.run(cb); + + const RETRY_EVENT = Mocha?.Runner?.constants?.EVENT_TEST_RETRY || 'retry'; + + runner.on(RETRY_EVENT, (test, err) => { + console.log(`Failure in test: "${test.fullTitle()}"`); + if (err?.stack) console.log(err.stack.split('\n').slice(0, 3).join('\n')); + console.log(`Retrying test (${test.currentRetry() + 1}/${test.retries()})...`); + }); + }) + .catch((err) => { + console.error('An error occurred while running the spec runner'); + console.error(err); + process.exit(1); + }); diff --git a/spec/lib/accelerator-helpers.ts b/spec/lib/accelerator-helpers.ts new file mode 100644 index 0000000000000..c3461f8102fe0 --- /dev/null +++ b/spec/lib/accelerator-helpers.ts @@ -0,0 +1,103 @@ +/** + * @fileoverview A set of helper functions to make it easier to work + * with accelerators across tests. + */ + +const modifiers = [ + 'CmdOrCtrl', + 'Alt', + process.platform === 'darwin' ? 'Option' : null, + 'AltGr', + 'Shift', + 'Super', + 'Meta' +].filter(Boolean); + +const keyCodes = [ + ...Array.from({ length: 10 }, (_, i) => `${i}`), // 0 to 9 + ...Array.from({ length: 26 }, (_, i) => String.fromCharCode(65 + i)), // A to Z + ...Array.from({ length: 24 }, (_, i) => `F${i + 1}`), // F1 to F24 + ')', + '!', + '@', + '#', + '$', + '%', + '^', + '&', + '*', + '(', + ':', + ';', + ':', + '+', + '=', + '<', + ',', + '_', + '-', + '>', + '.', + '?', + '/', + '~', + '`', + '{', + ']', + '[', + '|', + '\\', + '}', + '"', + 'Plus', + 'Space', + 'Tab', + 'Capslock', + 'Numlock', + 'Scrolllock', + 'Backspace', + 'Delete', + 'Insert', + 'Return', + 'Enter', + 'Up', + 'Down', + 'Left', + 'Right', + 'Home', + 'End', + 'PageUp', + 'PageDown', + 'Escape', + 'Esc', + 'PrintScreen', + 'num0', + 'num1', + 'num2', + 'num3', + 'num4', + 'num5', + 'num6', + 'num7', + 'num8', + 'num9', + 'numdec', + 'numadd', + 'numsub', + 'nummult', + 'numdiv' +]; + +export const singleModifierCombinations = modifiers.flatMap((mod) => + keyCodes.map((key) => { + return key === '+' ? `${mod}+Plus` : `${mod}+${key}`; + }) +); + +export const doubleModifierCombinations = modifiers.flatMap((mod1, i) => + modifiers.slice(i + 1).flatMap((mod2) => + keyCodes.map((key) => { + return key === '+' ? `${mod1}+${mod2}+Plus` : `${mod1}+${mod2}+${key}`; + }) + ) +); diff --git a/spec/lib/artifacts.ts b/spec/lib/artifacts.ts new file mode 100644 index 0000000000000..1bd73e0bea399 --- /dev/null +++ b/spec/lib/artifacts.ts @@ -0,0 +1,30 @@ +import { randomBytes } from 'node:crypto'; +import fs = require('node:fs/promises'); +import path = require('node:path'); + +const IS_CI = !!process.env.CI; +const ARTIFACT_DIR = path.join(__dirname, '..', 'artifacts'); + +async function ensureArtifactDir(): Promise { + if (!IS_CI) { + return; + } + + await fs.mkdir(ARTIFACT_DIR, { recursive: true }); +} + +export async function createArtifact(fileName: string, data: Buffer): Promise { + if (!IS_CI) { + return; + } + + await ensureArtifactDir(); + await fs.writeFile(path.join(ARTIFACT_DIR, fileName), data); +} + +export async function createArtifactWithRandomId(makeFileName: (id: string) => string, data: Buffer): Promise { + const randomId = randomBytes(12).toString('hex'); + const fileName = makeFileName(randomId); + await createArtifact(fileName, data); + return fileName; +} diff --git a/spec/lib/codesign-helpers.ts b/spec/lib/codesign-helpers.ts new file mode 100644 index 0000000000000..5c0b294ae66e6 --- /dev/null +++ b/spec/lib/codesign-helpers.ts @@ -0,0 +1,86 @@ +import { expect } from 'chai'; + +import * as cp from 'node:child_process'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; + +const features = process._linkedBinding('electron_common_features'); +const fixturesPath = path.resolve(__dirname, '..', 'fixtures'); + +export const shouldRunCodesignTests = process.platform === 'darwin' && !process.mas && !features.isComponentBuild(); + +let identity: string | null; + +export function getCodesignIdentity() { + if (identity === undefined) { + const result = cp.spawnSync(path.resolve(__dirname, '../../script/codesign/get-trusted-identity.sh')); + if (result.status !== 0 || result.stdout.toString().trim().length === 0) { + identity = null; + } else { + identity = result.stdout.toString().trim(); + } + } + return identity; +} + +export async function copyMacOSFixtureApp(newDir: string, fixture: string | null = 'initial') { + const appBundlePath = path.resolve(process.execPath, '../../..'); + const newPath = path.resolve(newDir, 'Electron.app'); + cp.spawnSync('cp', ['-R', appBundlePath, path.dirname(newPath)]); + if (fixture) { + const appDir = path.resolve(newPath, 'Contents/Resources/app'); + await fs.promises.mkdir(appDir, { recursive: true }); + await fs.promises.cp(path.resolve(fixturesPath, 'auto-update', fixture), appDir, { recursive: true }); + } + const plistPath = path.resolve(newPath, 'Contents', 'Info.plist'); + await fs.promises.writeFile( + plistPath, + (await fs.promises.readFile(plistPath, 'utf8')).replace( + 'BuildMachineOSBuild', + `NSAppTransportSecurity + + NSAllowsArbitraryLoads + + NSExceptionDomains + + localhost + + NSExceptionAllowsInsecureHTTPLoads + + NSIncludesSubdomains + + + + BuildMachineOSBuild` + ) + ); + return newPath; +} + +export function spawn(cmd: string, args: string[], opts: any = {}) { + let out = ''; + const child = cp.spawn(cmd, args, opts); + child.stdout.on('data', (chunk: Buffer) => { + out += chunk.toString(); + }); + child.stderr.on('data', (chunk: Buffer) => { + out += chunk.toString(); + }); + return new Promise<{ code: number; out: string }>((resolve) => { + child.on('exit', (code, signal) => { + expect(signal).to.equal(null); + resolve({ + code: code!, + out + }); + }); + }); +} + +export function signApp(appPath: string, identity: string) { + return spawn('codesign', ['-s', identity, '--deep', '--force', appPath]); +} + +export function unsignApp(appPath: string) { + return spawn('codesign', ['--remove-signature', '--deep', appPath]); +} diff --git a/spec/lib/events-helpers.ts b/spec/lib/events-helpers.ts new file mode 100644 index 0000000000000..2bb9fa59b181f --- /dev/null +++ b/spec/lib/events-helpers.ts @@ -0,0 +1,33 @@ +/** + * @fileoverview A set of helper functions to make it easier to work + * with events in async/await manner. + */ + +import { on } from 'node:events'; + +export const emittedNTimes = async ( + emitter: NodeJS.EventEmitter, + eventName: string, + times: number, + trigger?: () => void +) => { + const events: any[][] = []; + const iter = on(emitter, eventName); + if (trigger) await Promise.resolve(trigger()); + for await (const args of iter) { + events.push(args); + if (events.length === times) { + break; + } + } + return events; +}; + +export const emittedUntil = async (emitter: NodeJS.EventEmitter, eventName: string, untilFn: Function) => { + for await (const args of on(emitter, eventName)) { + if (untilFn(...args)) { + return args; + } + } + return []; +}; diff --git a/spec/lib/fs-helpers.ts b/spec/lib/fs-helpers.ts new file mode 100644 index 0000000000000..4a39a346db921 --- /dev/null +++ b/spec/lib/fs-helpers.ts @@ -0,0 +1,50 @@ +import * as fs from 'original-fs'; + +import * as cp from 'node:child_process'; +import * as os from 'node:os'; +import * as path from 'node:path'; + +export async function copyApp(targetDir: string): Promise { + // On macOS we can just copy the app bundle, easier too because of symlinks + if (process.platform === 'darwin') { + const appBundlePath = path.resolve(process.execPath, '../../..'); + const newPath = path.resolve(targetDir, 'Electron.app'); + cp.spawnSync('cp', ['-R', appBundlePath, path.dirname(newPath)]); + return newPath; + } + + // On windows and linux we should read the zip manifest files and then copy each of those files + // one by one + const baseDir = path.dirname(process.execPath); + const zipManifestPath = path.resolve( + __dirname, + '..', + '..', + 'script', + 'zip_manifests', + `dist_zip.${process.platform === 'win32' ? 'win' : 'linux'}.${process.arch === 'ia32' ? 'x86' : process.arch}.manifest` + ); + const filesToCopy = fs + .readFileSync(zipManifestPath, 'utf-8') + .split('\n') + .filter((f) => f !== 'LICENSE' && f !== 'LICENSES.chromium.html' && f !== 'version' && f.trim()); + await Promise.all( + filesToCopy.map(async (rel) => { + await fs.promises.mkdir(path.dirname(path.resolve(targetDir, rel)), { recursive: true }); + fs.copyFileSync(path.resolve(baseDir, rel), path.resolve(targetDir, rel)); + }) + ); + + return path.resolve(targetDir, path.basename(process.execPath)); +} + +export async function withTempDirectory(fn: (dir: string) => Promise, autoCleanUp = true) { + const dir = await fs.promises.mkdtemp(path.resolve(os.tmpdir(), 'electron-update-spec-')); + try { + await fn(dir); + } finally { + if (autoCleanUp) { + cp.spawnSync('rm', ['-r', dir]); + } + } +} diff --git a/spec/lib/heapsnapshot-helpers.js b/spec/lib/heapsnapshot-helpers.js new file mode 100644 index 0000000000000..398082656e64c --- /dev/null +++ b/spec/lib/heapsnapshot-helpers.js @@ -0,0 +1,22 @@ +export function containsRetainingPath(snapshot, retainingPath, options) { + let root = snapshot.filter((node) => node.name === retainingPath[0] && node.type !== 'string'); + for (let i = 1; i < retainingPath.length; i++) { + const needle = retainingPath[i]; + const newRoot = []; + for (const node of root) { + for (let j = 0; j < node.outgoingEdges.length; j++) { + const child = node.outgoingEdges[j].to; + if (child.type === 'string') continue; + if (child.name === needle) { + newRoot.push(child); + } + } + } + if (!newRoot.length) { + console.log(`No retaining path found for ${needle}`); + return false; + } + root = newRoot; + } + return options?.occurrances ? root.length === options.occurrances : true; +} diff --git a/spec/lib/media-helpers.ts b/spec/lib/media-helpers.ts new file mode 100644 index 0000000000000..6020817dac57e --- /dev/null +++ b/spec/lib/media-helpers.ts @@ -0,0 +1,39 @@ +import { BrowserWindow } from 'electron/main'; + +export interface TabSourceCaptureResult { + ok: boolean; + href: string; + message?: string; + origin: string; + videoTrackCount?: number; +} + +export const captureWithTabSourceId = async ( + requestingWindow: BrowserWindow, + streamId: string +): Promise => { + return requestingWindow.webContents.executeJavaScript(` + navigator.mediaDevices.getUserMedia({ + video: { + mandatory: { + chromeMediaSource: 'tab', + chromeMediaSourceId: ${JSON.stringify(streamId)}, + }, + }, + }).then((stream) => { + const result = { + ok: stream instanceof MediaStream, + href: location.href, + origin: location.origin, + videoTrackCount: stream.getVideoTracks().length, + }; + stream.getTracks().forEach((track) => track.stop()); + return result; + }, (error) => ({ + ok: false, + href: location.href, + message: error.message, + origin: location.origin, + })); + `); +}; diff --git a/spec/lib/msix-helpers.ts b/spec/lib/msix-helpers.ts new file mode 100644 index 0000000000000..ae78995e2bbdf --- /dev/null +++ b/spec/lib/msix-helpers.ts @@ -0,0 +1,156 @@ +import { expect } from 'chai'; + +import * as cp from 'node:child_process'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; + +const fixturesPath = path.resolve(__dirname, '..', 'fixtures', 'api', 'autoupdater', 'msix'); +const manifestFixturePath = path.resolve(fixturesPath, 'ElectronDevAppxManifest.xml'); +const installCertScriptPath = path.resolve(fixturesPath, 'install_test_cert.ps1'); + +// Install the signing certificate for MSIX test packages to the Trusted People store +// This is required to install self-signed MSIX packages +export async function installMsixCertificate(): Promise { + const result = cp.spawnSync('powershell', [ + '-NoProfile', + '-ExecutionPolicy', + 'Bypass', + '-File', + installCertScriptPath + ]); + + if (result.status !== 0) { + throw new Error(`Failed to install MSIX certificate: ${result.stderr.toString() || result.stdout.toString()}`); + } +} + +// Check if we should run MSIX tests +export const shouldRunMsixTests = process.platform === 'win32'; + +// Get the Electron executable path +export function getElectronExecutable(): string { + return process.execPath; +} + +// Get path to main.js fixture +export function getMainJsFixturePath(): string { + return path.resolve(fixturesPath, 'main.js'); +} + +// Register executable with identity +export async function registerExecutableWithIdentity(executablePath: string): Promise { + if (!fs.existsSync(manifestFixturePath)) { + throw new Error(`Manifest fixture not found: ${manifestFixturePath}`); + } + + const executableDir = path.dirname(executablePath); + const manifestPath = path.join(executableDir, 'AppxManifest.xml'); + const escapedManifestPath = manifestPath.replace(/'/g, "''").replace(/\\/g, '\\\\'); + const psCommand = ` + $ErrorActionPreference = 'Stop'; + try { + Add-AppxPackage -Register '${escapedManifestPath}' -ForceUpdateFromAnyVersion + } catch { + Write-Error $_.Exception.Message + exit 1 + } + `; + + fs.copyFileSync(manifestFixturePath, manifestPath); + + const result = cp.spawnSync('powershell', ['-NoProfile', '-Command', psCommand]); + if (result.status !== 0) { + const errorMsg = result.stderr.toString() || result.stdout.toString(); + try { + fs.unlinkSync(manifestPath); + } catch { + // Ignore cleanup errors + } + throw new Error(`Failed to register executable with identity: ${errorMsg}`); + } +} + +// Unregister the Electron Dev MSIX package +// This removes the sparse package registration created by registerExecutableWithIdentity +export async function unregisterExecutableWithIdentity(): Promise { + const result = cp.spawnSync('powershell', [ + '-NoProfile', + '-Command', + ' Get-AppxPackage Electron.Dev.MSIX | Remove-AppxPackage' + ]); + // Don't throw if package doesn't exist + if (result.status !== 0) { + throw new Error( + `Failed to unregister executable with identity: ${result.stderr.toString() || result.stdout.toString()}` + ); + } + + const electronExec = getElectronExecutable(); + const executableDir = path.dirname(electronExec); + const manifestPath = path.join(executableDir, 'AppxManifest.xml'); + try { + if (fs.existsSync(manifestPath)) { + fs.unlinkSync(manifestPath); + } + } catch { + // Ignore cleanup errors + } +} + +// Get path to MSIX fixture package +export function getMsixFixturePath(version: 'v1' | 'v2'): string { + const filename = `HelloMSIX_${version}.msix`; + return path.resolve(fixturesPath, filename); +} + +// Install MSIX package +export async function installMsixPackage(msixPath: string): Promise { + // Use Add-AppxPackage PowerShell cmdlet + const result = cp.spawnSync('powershell', [ + '-Command', + `Add-AppxPackage -Path "${msixPath}" -ForceApplicationShutdown` + ]); + if (result.status !== 0) { + throw new Error(`Failed to install MSIX package: ${result.stderr.toString()}`); + } +} + +// Uninstall MSIX package by name +export async function uninstallMsixPackage(name: string): Promise { + const result = cp.spawnSync('powershell', ['-NoProfile', '-Command', `Get-AppxPackage ${name} | Remove-AppxPackage`]); + // Don't throw if package doesn't exist + if (result.status !== 0) { + throw new Error(`Failed to uninstall MSIX package: ${result.stderr.toString() || result.stdout.toString()}`); + } +} + +// Get version of installed MSIX package by name +export async function getMsixPackageVersion(name: string): Promise { + const psCommand = `(Get-AppxPackage -Name '${name}').Version`; + const result = cp.spawnSync('powershell', ['-NoProfile', '-Command', psCommand]); + if (result.status !== 0) { + return null; + } + const version = result.stdout.toString().trim(); + return version || null; +} + +export function spawn(cmd: string, args: string[], opts: any = {}): Promise<{ code: number; out: string }> { + let out = ''; + const child = cp.spawn(cmd, args, opts); + child.stdout.on('data', (chunk: Buffer) => { + out += chunk.toString(); + }); + child.stderr.on('data', (chunk: Buffer) => { + out += chunk.toString(); + }); + return new Promise<{ code: number; out: string }>((resolve) => { + child.on('exit', (code, signal) => { + expect(signal).to.equal(null); + resolve({ + code: code!, + out + }); + }); + }); +} diff --git a/spec/lib/net-helpers.ts b/spec/lib/net-helpers.ts new file mode 100644 index 0000000000000..9877b5e0f7754 --- /dev/null +++ b/spec/lib/net-helpers.ts @@ -0,0 +1,110 @@ +import { expect } from 'chai'; + +import * as dns from 'node:dns'; +import * as http from 'node:http'; +import { Socket } from 'node:net'; + +import { defer, listen } from './spec-helpers'; + +// See https://github.com/nodejs/node/issues/40702. +dns.setDefaultResultOrder('ipv4first'); + +export const kOneKiloByte = 1024; +export const kOneMegaByte = kOneKiloByte * kOneKiloByte; + +export function randomBuffer(size: number, start: number = 0, end: number = 255) { + const range = 1 + end - start; + const buffer = Buffer.allocUnsafe(size); + for (let i = 0; i < size; ++i) { + buffer[i] = start + Math.floor(Math.random() * range); + } + return buffer; +} + +export function randomString(length: number) { + const buffer = randomBuffer(length, '0'.charCodeAt(0), 'z'.charCodeAt(0)); + return buffer.toString(); +} + +export async function getResponse(urlRequest: Electron.ClientRequest) { + return new Promise((resolve, reject) => { + urlRequest.on('error', reject); + urlRequest.on('abort', reject); + urlRequest.on('response', (response) => resolve(response)); + urlRequest.end(); + }); +} + +export async function collectStreamBody(response: Electron.IncomingMessage | http.IncomingMessage) { + return (await collectStreamBodyBuffer(response)).toString(); +} + +export function collectStreamBodyBuffer(response: Electron.IncomingMessage | http.IncomingMessage) { + return new Promise((resolve, reject) => { + response.on('error', reject); + (response as NodeJS.EventEmitter).on('aborted', reject); + const data: Buffer[] = []; + response.on('data', (chunk) => data.push(chunk)); + response.on('end', (chunk?: Buffer) => { + if (chunk) data.push(chunk); + resolve(Buffer.concat(data)); + }); + }); +} + +export async function respondNTimes(fn: http.RequestListener, n: number): Promise { + const server = http.createServer((request, response) => { + fn(request, response); + // don't close if a redirect was returned + if ((response.statusCode < 300 || response.statusCode >= 399) && n <= 0) { + n--; + server.close(); + } + }); + const sockets: Socket[] = []; + server.on('connection', (s) => sockets.push(s)); + defer(() => { + server.close(); + for (const socket of sockets) { + socket.destroy(); + } + }); + return (await listen(server)).url; +} + +export function respondOnce(fn: http.RequestListener) { + return respondNTimes(fn, 1); +} + +respondNTimes.routeFailure = false; + +respondNTimes.toRoutes = (routes: Record, n: number) => { + return respondNTimes((request, response) => { + if (Object.hasOwn(routes, request.url || '')) { + (async () => { + await Promise.resolve(routes[request.url || ''](request, response)); + })().catch((err) => { + respondNTimes.routeFailure = true; + console.error('Route handler failed, this is probably why your test failed', err); + response.statusCode = 500; + response.end(); + }); + } else { + response.statusCode = 500; + response.end(); + expect.fail(`Unexpected URL: ${request.url}`); + } + }, n); +}; +respondOnce.toRoutes = (routes: Record) => respondNTimes.toRoutes(routes, 1); + +respondNTimes.toURL = (url: string, fn: http.RequestListener, n: number) => { + return respondNTimes.toRoutes({ [url]: fn }, n); +}; +respondOnce.toURL = (url: string, fn: http.RequestListener) => respondNTimes.toURL(url, fn, 1); + +respondNTimes.toSingleURL = (fn: http.RequestListener, n: number) => { + const requestUrl = '/requestUrl'; + return respondNTimes.toURL(requestUrl, fn, n).then((url) => `${url}${requestUrl}`); +}; +respondOnce.toSingleURL = (fn: http.RequestListener) => respondNTimes.toSingleURL(fn, 1); diff --git a/spec/lib/screen-helpers.ts b/spec/lib/screen-helpers.ts new file mode 100644 index 0000000000000..9aa89c33fb089 --- /dev/null +++ b/spec/lib/screen-helpers.ts @@ -0,0 +1,191 @@ +import { screen, desktopCapturer, NativeImage } from 'electron'; + +import { AssertionError } from 'chai'; + +import { createArtifactWithRandomId } from './artifacts'; + +export enum HexColors { + GREEN = '#00b140', + PURPLE = '#6a0dad', + RED = '#ff0000', + BLUE = '#0000ff', + WHITE = '#ffffff' +} + +function hexToRgba(hexColor: string): [number, number, number, number] | undefined { + const match = hexColor.match(/^#([0-9a-fA-F]{6,8})$/); + if (!match) return; + + const colorStr = match[1]; + return [ + parseInt(colorStr.substring(0, 2), 16), + parseInt(colorStr.substring(2, 4), 16), + parseInt(colorStr.substring(4, 6), 16), + parseInt(colorStr.substring(6, 8), 16) || 0xff + ]; +} + +function formatHexByte(val: number): string { + const str = val.toString(16); + return str.length === 2 ? str : `0${str}`; +} + +/** + * Get the hex color at the given pixel coordinate in an image. + */ +function getPixelColor(image: Electron.NativeImage, point: Electron.Point): string { + // image.crop crashes if point is fractional, so round to prevent that crash + const pixel = image.crop({ + x: Math.round(point.x), + y: Math.round(point.y), + width: 1, + height: 1 + }); + // TODO(samuelmaddock): NativeImage.toBitmap() should return the raw pixel + // color, but it sometimes differs. Why is that? + const [b, g, r] = pixel.toBitmap(); + return `#${formatHexByte(r)}${formatHexByte(g)}${formatHexByte(b)}`; +} + +/** Calculate euclidean distance between colors. */ +function colorDistance(hexColorA: string, hexColorB: string): number { + const colorA = hexToRgba(hexColorA); + const colorB = hexToRgba(hexColorB); + if (!colorA || !colorB) return -1; + return Math.sqrt( + Math.pow(colorB[0] - colorA[0], 2) + Math.pow(colorB[1] - colorA[1], 2) + Math.pow(colorB[2] - colorA[2], 2) + ); +} + +/** + * Determine if colors are similar based on distance. This can be useful when + * comparing colors which may differ based on lossy compression. + */ +function areColorsSimilar(hexColorA: string, hexColorB: string, distanceThreshold = 90): boolean { + const distance = colorDistance(hexColorA, hexColorB); + return distance <= distanceThreshold; +} + +function displayCenter(display: Electron.Display): Electron.Point { + return { + x: display.size.width / 2, + y: display.size.height / 2 + }; +} + +/** Resolve when approx. one frame has passed (30FPS) */ +export async function nextFrameTime(): Promise { + return await new Promise((resolve) => { + setTimeout(resolve, 1000 / 30); + }); +} + +/** + * Utilities for creating and inspecting a screen capture. + * + * Set `PAUSE_CAPTURE_TESTS` env var to briefly pause during screen + * capture for easier inspection. + * + * NOTE: Not yet supported on Linux in CI due to empty sources list. + */ +export class ScreenCapture { + /** Timeout to wait for expected color to match. */ + static TIMEOUT = 3000; + + constructor(display?: Electron.Display) { + this.display = display || screen.getPrimaryDisplay(); + } + + public async expectColorAtCenterMatches(hexColor: string) { + return this._expectImpl(displayCenter(this.display), hexColor, true); + } + + public async expectColorAtCenterDoesNotMatch(hexColor: string) { + return this._expectImpl(displayCenter(this.display), hexColor, false); + } + + public async expectColorAtPointOnDisplayMatches( + hexColor: string, + findPoint: (displaySize: Electron.Size) => Electron.Point + ) { + return this._expectImpl(findPoint(this.display.size), hexColor, true); + } + + public async takeScreenshot(filePrefix: string) { + const frame = await this.captureFrame(); + return await createArtifactWithRandomId((id) => `${filePrefix}-${id}.png`, frame.toPNG()); + } + + private async captureFrame(): Promise { + const sources = await desktopCapturer.getSources({ + types: ['screen'], + thumbnailSize: this.display.size + }); + + const captureSource = sources.find((source) => source.display_id === this.display.id.toString()); + if (captureSource === undefined) { + const displayIds = sources.map((source) => source.display_id).join(', '); + throw new Error( + `Unable to find screen capture for display '${this.display.id}'\n\tAvailable displays: ${displayIds}` + ); + } + + if (process.env.PAUSE_CAPTURE_TESTS) { + await new Promise((resolve) => setTimeout(resolve, 1e3)); + } + + return captureSource.thumbnail; + } + + private async _expectImpl(point: Electron.Point, expectedColor: string, matchIsExpected: boolean) { + let frame: Electron.NativeImage; + let actualColor: string; + let gotExpectedResult: boolean = false; + const expiration = Date.now() + ScreenCapture.TIMEOUT; + + // Continuously capture frames until we either see the expected result or + // reach a timeout. This helps avoid flaky tests in which a short waiting + // period is required for the expected result. + do { + frame = await this.captureFrame(); + actualColor = getPixelColor(frame, point); + const colorsMatch = areColorsSimilar(expectedColor, actualColor); + gotExpectedResult = matchIsExpected ? colorsMatch : !colorsMatch; + if (gotExpectedResult) break; + + await nextFrameTime(); // limit framerate + } while (Date.now() < expiration); + + if (!gotExpectedResult) { + // Limit image to 720p to save on storage space + if (process.env.CI) { + const width = Math.floor(Math.min(frame.getSize().width, 720)); + frame = frame.resize({ width }); + } + + // Save the image as an artifact for better debugging + const artifactName = await createArtifactWithRandomId((id) => `color-mismatch-${id}.png`, frame.toPNG()); + + throw new AssertionError( + `Expected color at (${point.x}, ${point.y}) to ${ + matchIsExpected ? 'match' : '*not* match' + } '${expectedColor}', but got '${actualColor}'. See the artifact '${artifactName}' for more information.` + ); + } + } + + private display: Electron.Display; +} + +/** + * Whether the current VM has a valid screen which can be used to capture. + * + * This is specific to Electron's CI test runners. + * - Linux: virtual screen display is 0x0 + * - Win32 arm64 (WOA): virtual screen display is 0x0 + * - Win32 ia32: skipped + * - Win32 x64: virtual screen display is 0x0 + */ +export const hasCapturableScreen = () => { + return process.env.CI ? process.platform === 'darwin' : true; +}; diff --git a/spec/lib/spec-helpers.ts b/spec/lib/spec-helpers.ts new file mode 100644 index 0000000000000..21d98aa94084e --- /dev/null +++ b/spec/lib/spec-helpers.ts @@ -0,0 +1,261 @@ +import { BrowserWindow } from 'electron/main'; + +import { AssertionError } from 'chai'; +import { SuiteFunction, TestFunction } from 'mocha'; + +import * as childProcess from 'node:child_process'; +import * as http from 'node:http'; +import * as http2 from 'node:http2'; +import * as https from 'node:https'; +import * as net from 'node:net'; +import * as path from 'node:path'; +import { setTimeout } from 'node:timers/promises'; +import * as url from 'node:url'; +import * as v8 from 'node:v8'; + +const addOnly = (fn: Function): T => { + const wrapped = (...args: any[]) => { + return fn(...args); + }; + (wrapped as any).only = wrapped; + (wrapped as any).skip = wrapped; + return wrapped as any; +}; + +export const ifit = (condition: boolean) => (condition ? it : addOnly(it.skip)); +export const ifdescribe = (condition: boolean) => (condition ? describe : addOnly(describe.skip)); + +export const isWayland = + process.platform === 'linux' && + (process.env.XDG_SESSION_TYPE === 'wayland' || + !!process.env.WAYLAND_DISPLAY || + process.argv.includes('--ozone-platform=wayland')); + +type CleanupFunction = (() => void) | (() => Promise); +const cleanupFunctions: CleanupFunction[] = []; +export async function runCleanupFunctions() { + for (const cleanup of cleanupFunctions) { + const r = cleanup(); + if (r instanceof Promise) { + await r; + } + } + cleanupFunctions.length = 0; +} + +export function defer(f: CleanupFunction) { + cleanupFunctions.unshift(f); +} + +class RemoteControlApp { + process: childProcess.ChildProcess; + port: number; + + constructor(proc: childProcess.ChildProcess, port: number) { + this.process = proc; + this.port = port; + } + + remoteEval = (js: string): Promise => { + return new Promise((resolve, reject) => { + const req = http.request( + { + host: '127.0.0.1', + port: this.port, + method: 'POST' + }, + (res) => { + const chunks = [] as Buffer[]; + res.on('data', (chunk) => { + chunks.push(chunk); + }); + res.on('end', () => { + const ret = v8.deserialize(Buffer.concat(chunks)); + if (Object.hasOwn(ret, 'error')) { + reject(new Error(`remote error: ${ret.error}\n\nTriggered at:`)); + } else { + resolve(ret.result); + } + }); + } + ); + req.write(js); + req.end(); + }); + }; + + remotely = (script: Function, ...args: any[]): Promise => { + return this.remoteEval(`(${script})(...${JSON.stringify(args)})`); + }; +} + +export async function startRemoteControlApp(extraArgs: string[] = [], options?: childProcess.SpawnOptionsWithoutStdio) { + const appPath = path.join(__dirname, '..', 'fixtures', 'apps', 'remote-control'); + const appProcess = childProcess.spawn(process.execPath, [appPath, ...extraArgs], options); + appProcess.stderr.on('data', (d) => { + process.stderr.write(d); + }); + const port = await new Promise((resolve) => { + appProcess.stdout.on('data', (d) => { + const m = /Listening: (\d+)/.exec(d.toString()); + if (m && m[1] != null) { + resolve(Number(m[1])); + } + }); + }); + defer(() => { + appProcess.kill('SIGINT'); + }); + return new RemoteControlApp(appProcess, port); +} + +export function waitUntil(callback: () => boolean | Promise, opts: { rate?: number; timeout?: number } = {}) { + const { rate = 10, timeout = 10000 } = opts; + return (async () => { + const ac = new AbortController(); + const signal = ac.signal; + let checkCompleted = false; + let timedOut = false; + + const check = async () => { + let result; + + try { + result = await callback(); + } catch (e) { + ac.abort(); + throw e; + } + + return result; + }; + + setTimeout(timeout, { signal }).then(() => { + timedOut = true; + checkCompleted = true; + }); + + while (checkCompleted === false) { + const checkSatisfied = await check(); + if (checkSatisfied === true) { + ac.abort(); + checkCompleted = true; + return; + } else { + await setTimeout(rate); + } + } + + if (timedOut) { + throw new Error(`waitUntil timed out after ${timeout}ms`); + } + })(); +} + +export async function repeatedly(fn: () => Promise, opts?: { until?: (x: T) => boolean; timeLimit?: number }) { + const { until = (x: T) => !!x, timeLimit = 10000 } = opts ?? {}; + const begin = Date.now(); + while (true) { + const ret = await fn(); + if (until(ret)) { + return ret; + } + if (Date.now() - begin > timeLimit) { + throw new Error(`repeatedly timed out (limit=${timeLimit})`); + } + } +} + +async function makeRemoteContext(opts?: any) { + const { webPreferences, setup, url = 'about:blank', ...rest } = opts ?? {}; + const w = new BrowserWindow({ + show: false, + webPreferences: { nodeIntegration: true, contextIsolation: false, ...webPreferences }, + ...rest + }); + await w.loadURL(url.toString()); + if (setup) await w.webContents.executeJavaScript(setup); + return w; +} + +const remoteContext: BrowserWindow[] = []; +export async function getRemoteContext() { + if (remoteContext.length) { + return remoteContext[0]; + } + const w = await makeRemoteContext(); + defer(() => w.close()); + return w; +} + +export function useRemoteContext(opts?: any) { + before(async () => { + remoteContext.unshift(await makeRemoteContext(opts)); + }); + after(() => { + const w = remoteContext.shift(); + w!.close(); + }); +} + +async function runRemote(type: 'skip' | 'none' | 'only', name: string, fn: Function, args?: any[]) { + const wrapped = async () => { + const w = await getRemoteContext(); + const { ok, message } = await w.webContents.executeJavaScript(`(async () => { + try { + const chai_1 = require('chai') + const promises_1 = require('node:timers/promises') + chai_1.use(require('chai-as-promised')) + chai_1.use(require('dirty-chai')) + await (${fn})(...${JSON.stringify(args ?? [])}) + return {ok: true}; + } catch (e) { + return {ok: false, message: e.message} + } + })()`); + if (!ok) { + throw new AssertionError(message); + } + }; + + let runFn: any = it; + if (type === 'only') { + // eslint-disable-next-line no-only-tests/no-only-tests + runFn = it.only; + } else if (type === 'skip') { + runFn = it.skip; + } + + runFn(name, wrapped); +} + +export const itremote = Object.assign( + (name: string, fn: Function, args?: any[]) => { + runRemote('none', name, fn, args); + }, + { + only: (name: string, fn: Function, args?: any[]) => { + runRemote('only', name, fn, args); + }, + skip: (name: string, fn: Function, args?: any[]) => { + runRemote('skip', name, fn, args); + } + } +); + +export async function listen(server: http.Server | https.Server | http2.Http2SecureServer) { + const hostname = '127.0.0.1'; + await new Promise((resolve) => server.listen(0, hostname, () => resolve())); + const { port } = server.address() as net.AddressInfo; + const protocol = server instanceof http.Server ? 'http' : 'https'; + return { port, hostname, url: url.format({ protocol, hostname, port }) }; +} + +export function isTestingBindingAvailable() { + try { + process._linkedBinding('electron_common_testing'); + return true; + } catch { + return false; + } +} diff --git a/spec-main/video-helpers.js b/spec/lib/video-helpers.js similarity index 77% rename from spec-main/video-helpers.js rename to spec/lib/video-helpers.js index d5538c8eab15a..5fa204b060945 100644 --- a/spec-main/video-helpers.js +++ b/spec/lib/video-helpers.js @@ -23,14 +23,14 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -function atob (str) { +function atob(str) { return Buffer.from(str, 'base64').toString('binary'); } // in this case, frames has a very specific meaning, which will be // detailed once i finish writing the code -function ToWebM (frames) { +function ToWebM(frames) { const info = checkFrames(frames); // max duration by cluster in milliseconds @@ -206,22 +206,24 @@ function ToWebM (frames) { data: Math.round(clusterTimecode), id: 0xe7 // Timecode } - ].concat(clusterFrames.map(function (webp) { - const block = makeSimpleBlock({ - discardable: 0, - frame: webp.data.slice(4), - invisible: 0, - keyframe: 1, - lacing: 0, - trackNum: 1, - timecode: Math.round(clusterCounter) - }); - clusterCounter += webp.duration; - return { - data: block, - id: 0xa3 - }; - })) + ].concat( + clusterFrames.map(function (webp) { + const block = makeSimpleBlock({ + discardable: 0, + frame: webp.data.slice(4), + invisible: 0, + keyframe: 1, + lacing: 0, + trackNum: 1, + timecode: Math.round(clusterCounter) + }); + clusterCounter += webp.duration; + return { + data: block, + id: 0xa3 + }; + }) + ) }; // Add cluster to segment @@ -237,7 +239,8 @@ function ToWebM (frames) { } const data = generateEBML([segment.data[i]]); position += data.size || data.byteLength || data.length; - if (i !== 2) { // not cues + if (i !== 2) { + // not cues // Save results to avoid having to encode everything twice segment.data[i] = data; } @@ -248,24 +251,26 @@ function ToWebM (frames) { // sums the lengths of all the frames and gets the duration, woo -function checkFrames (frames) { +function checkFrames(frames) { const width = frames[0].width; const height = frames[0].height; let duration = frames[0].duration; for (let i = 1; i < frames.length; i++) { if (frames[i].width !== width) throw new Error('Frame ' + (i + 1) + ' has a different width'); if (frames[i].height !== height) throw new Error('Frame ' + (i + 1) + ' has a different height'); - if (frames[i].duration < 0 || frames[i].duration > 0x7fff) throw new Error('Frame ' + (i + 1) + ' has a weird duration (must be between 0 and 32767)'); + if (frames[i].duration < 0 || frames[i].duration > 0x7fff) { + throw new Error('Frame ' + (i + 1) + ' has a weird duration (must be between 0 and 32767)'); + } duration += frames[i].duration; } return { - duration: duration, - width: width, - height: height + duration, + width, + height }; } -function numToBuffer (num) { +function numToBuffer(num) { const parts = []; while (num > 0) { parts.push(num & 0xff); @@ -274,7 +279,7 @@ function numToBuffer (num) { return new Uint8Array(parts.reverse()); } -function numToFixedBuffer (num, size) { +function numToFixedBuffer(num, size) { const parts = new Uint8Array(size); for (let i = size - 1; i >= 0; i--) { parts[i] = num & 0xff; @@ -283,7 +288,7 @@ function numToFixedBuffer (num, size) { return parts; } -function strToBuffer (str) { +function strToBuffer(str) { // return new Blob([str]); const arr = new Uint8Array(str.length); @@ -301,9 +306,9 @@ function strToBuffer (str) { // at all really, but the reason is that there's some code below that i dont really // feel like understanding, and this is easier than using my brain. -function bitsToBuffer (bits) { +function bitsToBuffer(bits) { const data = []; - const pad = (bits.length % 8) ? (new Array(1 + 8 - (bits.length % 8))).join('0') : ''; + const pad = bits.length % 8 ? new Array(1 + 8 - (bits.length % 8)).join('0') : ''; bits = pad + bits; for (let i = 0; i < bits.length; i += 8) { data.push(parseInt(bits.substr(i, 8), 2)); @@ -311,31 +316,33 @@ function bitsToBuffer (bits) { return new Uint8Array(data); } -function generateEBML (json) { +function generateEBML(json) { const ebml = []; - for (let i = 0; i < json.length; i++) { - if (!('id' in json[i])) { + for (const item of json) { + if (!('id' in item)) { // already encoded blob or byteArray - ebml.push(json[i]); + ebml.push(item); continue; } - let data = json[i].data; + let data = item.data; if (typeof data === 'object') data = generateEBML(data); - if (typeof data === 'number') data = ('size' in json[i]) ? numToFixedBuffer(data, json[i].size) : bitsToBuffer(data.toString(2)); + if (typeof data === 'number') { + data = 'size' in item ? numToFixedBuffer(data, item.size) : bitsToBuffer(data.toString(2)); + } if (typeof data === 'string') data = strToBuffer(data); const len = data.size || data.byteLength || data.length; const zeroes = Math.ceil(Math.ceil(Math.log(len) / Math.log(2)) / 8); const sizeStr = len.toString(2); - const padded = (new Array((zeroes * 7 + 7 + 1) - sizeStr.length)).join('0') + sizeStr; - const size = (new Array(zeroes)).join('0') + '1' + padded; + const padded = new Array(zeroes * 7 + 7 + 1 - sizeStr.length).join('0') + sizeStr; + const size = new Array(zeroes).join('0') + '1' + padded; // i actually dont quite understand what went on up there, so I'm not really // going to fix this, i'm probably just going to write some hacky thing which // converts that string into a buffer-esque thing - ebml.push(numToBuffer(json[i].id)); + ebml.push(numToBuffer(item.id)); ebml.push(bitsToBuffer(size)); ebml.push(data); } @@ -345,41 +352,44 @@ function generateEBML (json) { return new Uint8Array(buffer); } -function toFlatArray (arr, outBuffer) { +function toFlatArray(arr, outBuffer) { if (outBuffer == null) { outBuffer = []; } - for (let i = 0; i < arr.length; i++) { - if (typeof arr[i] === 'object') { + for (const item of arr) { + if (typeof item === 'object') { // an array - toFlatArray(arr[i], outBuffer); + toFlatArray(item, outBuffer); } else { // a simple element - outBuffer.push(arr[i]); + outBuffer.push(item); } } return outBuffer; } -function makeSimpleBlock (data) { +function makeSimpleBlock(data) { let flags = 0; if (data.keyframe) flags |= 128; if (data.invisible) flags |= 8; - if (data.lacing) flags |= (data.lacing << 1); + if (data.lacing) flags |= data.lacing << 1; if (data.discardable) flags |= 1; if (data.trackNum > 127) { throw new Error('TrackNumber > 127 not supported'); } - const out = [data.trackNum | 0x80, data.timecode >> 8, data.timecode & 0xff, flags].map(function (e) { - return String.fromCharCode(e); - }).join('') + data.frame; + const out = + [data.trackNum | 0x80, data.timecode >> 8, data.timecode & 0xff, flags] + .map(function (e) { + return String.fromCharCode(e); + }) + .join('') + data.frame; return out; } // here's something else taken verbatim from weppy, awesome rite? -function parseWebP (riff) { +function parseWebP(riff) { const VP8 = riff.RIFF[0].WEBP[0]; const frameStart = VP8.indexOf('\x9d\x01\x2a'); // A VP8 keyframe starts with the 0x9d012a header @@ -388,16 +398,18 @@ function parseWebP (riff) { // the code below is literally copied verbatim from the bitstream spec let tmp = (c[1] << 8) | c[0]; - const width = tmp & 0x3FFF; + const width = tmp & 0x3fff; const horizontalScale = tmp >> 14; tmp = (c[3] << 8) | c[2]; - const height = tmp & 0x3FFF; + const height = tmp & 0x3fff; const verticalScale = tmp >> 14; return { - width: width, - height: height, + width, + height, + horizontalScale, + verticalScale, data: VP8, - riff: riff + riff }; } @@ -408,7 +420,7 @@ function parseWebP (riff) { // break which makes me make up puns. well, enough riff-raff (aha a // rescue of sorts), this function was ripped wholesale from weppy -function parseRIFF (string) { +function parseRIFF(string) { let offset = 0; const chunks = {}; @@ -416,10 +428,17 @@ function parseRIFF (string) { const id = string.substr(offset, 4); chunks[id] = chunks[id] || []; if (id === 'RIFF' || id === 'LIST') { - const len = parseInt(string.substr(offset + 4, 4).split('').map(function (i) { - const unpadded = i.charCodeAt(0).toString(2); - return (new Array(8 - unpadded.length + 1)).join('0') + unpadded; - }).join(''), 2); + const len = parseInt( + string + .substr(offset + 4, 4) + .split('') + .map(function (i) { + const unpadded = i.charCodeAt(0).toString(2); + return new Array(8 - unpadded.length + 1).join('0') + unpadded; + }) + .join(''), + 2 + ); const data = string.substr(offset + 4 + 4, len); offset += 4 + 4 + len; chunks[id].push(parseRIFF(data)); @@ -439,21 +458,24 @@ function parseRIFF (string) { // here's a little utility function that acts as a utility for other functions // basically, the only purpose is for encoding "Duration", which is encoded as // a double (considerably more difficult to encode than an integer) -function doubleToString (num) { - return [].slice.call( - new Uint8Array( - ( - new Float64Array([num]) // create a float64 array - ).buffer) // extract the array buffer - , 0) // convert the Uint8Array into a regular array - .map(function (e) { // since it's a regular array, we can now use map +function doubleToString(num) { + return Array.prototype.slice + .call( + new Uint8Array( + new Float64Array([num]).buffer // create a float64 array + ), // extract the array buffer + 0 + ) // convert the Uint8Array into a regular array + .map(function (e) { + // since it's a regular array, we can now use map return String.fromCharCode(e); // encode all the bytes individually }) .reverse() // correct the byte endianness (assume it's little endian for now) .join(''); // join the bytes in holy matrimony as a string } -function WhammyVideo (speed, quality = 0.8) { // a more abstract-ish API +function WhammyVideo(speed, quality = 0.8) { + // a more abstract-ish API this.frames = []; this.duration = 1000 / speed; this.quality = quality; @@ -466,8 +488,11 @@ function WhammyVideo (speed, quality = 0.8) { // a more abstract-ish API */ WhammyVideo.prototype.add = function (frame, duration) { if (typeof duration !== 'undefined' && this.duration) throw new Error("you can't pass a duration if the fps is set"); - if (typeof duration === 'undefined' && !this.duration) throw new Error("if you don't have the fps set, you need to have durations here."); - if (frame.canvas) { // CanvasRenderingContext2D + if (typeof duration === 'undefined' && !this.duration) { + throw new Error("if you don't have the fps set, you need to have durations here."); + } + if (frame.canvas) { + // CanvasRenderingContext2D frame = frame.canvas; } if (frame.toDataURL) { @@ -475,9 +500,11 @@ WhammyVideo.prototype.add = function (frame, duration) { // quickly store image data so we don't block cpu. encode in compile method. frame = frame.getContext('2d').getImageData(0, 0, frame.width, frame.height); } else if (typeof frame !== 'string') { - throw new Error('frame must be a a HTMLCanvasElement, a CanvasRenderingContext2D or a DataURI formatted string'); + throw new TypeError( + 'frame must be a a HTMLCanvasElement, a CanvasRenderingContext2D or a DataURI formatted string' + ); } - if (typeof frame === 'string' && !(/^data:image\/webp;base64,/ig).test(frame)) { + if (typeof frame === 'string' && !/^data:image\/webp;base64,/gi.test(frame)) { throw new Error('Input must be formatted properly as a base64 encoded DataURI of type image/webp'); } this.frames.push({ @@ -487,11 +514,13 @@ WhammyVideo.prototype.add = function (frame, duration) { }; WhammyVideo.prototype.compile = function (callback) { - const webm = new ToWebM(this.frames.map(function (frame) { - const webp = parseWebP(parseRIFF(atob(frame.image.slice(23)))); - webp.duration = frame.duration; - return webp; - })); + const webm = new ToWebM( + this.frames.map(function (frame) { + const webp = parseWebP(parseRIFF(atob(frame.image.slice(23)))); + webp.duration = frame.duration; + return webp; + }) + ); callback(webm); }; diff --git a/spec/lib/warning-helpers.ts b/spec/lib/warning-helpers.ts new file mode 100644 index 0000000000000..9c6a02bf07f69 --- /dev/null +++ b/spec/lib/warning-helpers.ts @@ -0,0 +1,59 @@ +import { expect } from 'chai'; + +type ExpectedWarningMessage = RegExp | string; + +async function expectWarnings(func: () => any, expected: { name: string; message: ExpectedWarningMessage }[]) { + const messages: { name: string; message: string }[] = []; + + const originalWarn = console.warn; + console.warn = (message) => { + messages.push({ name: 'Warning', message }); + }; + + const warningListener = (error: Error) => { + messages.push({ name: error.name, message: error.message }); + }; + + process.on('warning', warningListener); + + try { + return await func(); + } finally { + // process.emitWarning seems to need us to wait a tick + await new Promise(process.nextTick); + console.warn = originalWarn; + process.off('warning' as any, warningListener); + expect(messages).to.have.lengthOf(expected.length); + for (const [idx, { name, message }] of messages.entries()) { + expect(name).to.equal(expected[idx].name); + if (expected[idx].message instanceof RegExp) { + expect(message).to.match(expected[idx].message); + } else { + expect(message).to.equal(expected[idx].message); + } + } + } +} + +export async function expectWarningMessages( + func: () => any, + ...expected: ({ name: string; message: ExpectedWarningMessage } | ExpectedWarningMessage)[] +) { + return expectWarnings( + func, + expected.map((message) => { + if (typeof message === 'string' || message instanceof RegExp) { + return { name: 'Warning', message }; + } else { + return message; + } + }) + ); +} + +export async function expectDeprecationMessages(func: () => any, ...expected: ExpectedWarningMessage[]) { + return expectWarnings( + func, + expected.map((message) => ({ name: 'DeprecationWarning', message })) + ); +} diff --git a/spec/lib/window-helpers.ts b/spec/lib/window-helpers.ts new file mode 100644 index 0000000000000..e70de77f8db51 --- /dev/null +++ b/spec/lib/window-helpers.ts @@ -0,0 +1,70 @@ +import { BaseWindow, BrowserWindow, webContents } from 'electron/main'; + +import { expect } from 'chai'; + +import { once } from 'node:events'; + +async function ensureWindowIsClosed(window: BaseWindow | null) { + if (window && !window.isDestroyed()) { + if (window instanceof BrowserWindow && window.webContents && !window.webContents.isDestroyed()) { + // If a window isn't destroyed already, and it has non-destroyed WebContents, + // then calling destroy() won't immediately destroy it, as it may have + // children which need to be destroyed first. In that case, we + // await the 'closed' event which signals the complete shutdown of the + // window. + const isClosed = once(window, 'closed'); + window.destroy(); + await isClosed; + } else { + // If there's no WebContents or if the WebContents is already destroyed, + // then the 'closed' event has already been emitted so there's nothing to + // wait for. + window.destroy(); + } + } +} + +export const closeWindow = async ( + window: BaseWindow | null = null, + { assertNotWindows } = { assertNotWindows: true } +) => { + await ensureWindowIsClosed(window); + + if (assertNotWindows) { + let windows = BaseWindow.getAllWindows(); + if (windows.length > 0) { + setTimeout(async () => { + // Wait until next tick to assert that all windows have been closed. + windows = BaseWindow.getAllWindows(); + try { + expect(windows).to.have.lengthOf(0); + } finally { + for (const win of windows) { + await ensureWindowIsClosed(win); + } + } + }); + } + } +}; + +export async function closeAllWindows(assertNotWindows = false) { + let windowsClosed = 0; + for (const w of BaseWindow.getAllWindows()) { + await closeWindow(w, { assertNotWindows }); + windowsClosed++; + } + return windowsClosed; +} + +export async function cleanupWebContents() { + let webContentsDestroyed = 0; + const existingWCS = webContents.getAllWebContents(); + for (const contents of existingWCS) { + const isDestroyed = once(contents, 'destroyed'); + contents.destroy(); + await isDestroyed; + webContentsDestroyed++; + } + return webContentsDestroyed; +} diff --git a/spec/logging-spec.ts b/spec/logging-spec.ts new file mode 100644 index 0000000000000..878de230d3b72 --- /dev/null +++ b/spec/logging-spec.ts @@ -0,0 +1,257 @@ +import { app } from 'electron'; + +import { expect } from 'chai'; +import * as uuid from 'uuid'; + +import { once } from 'node:events'; +import * as fs from 'node:fs/promises'; +import * as path from 'node:path'; + +import { startRemoteControlApp, ifdescribe, ifit, isTestingBindingAvailable } from './lib/spec-helpers'; + +// This test depends on functions that are only available when DCHECK_IS_ON. +ifdescribe(isTestingBindingAvailable())('logging', () => { + it('does not log by default', async () => { + // ELECTRON_ENABLE_LOGGING might be set in the environment, so remove it + const { ELECTRON_ENABLE_LOGGING: _, ...envWithoutEnableLogging } = process.env; + const rc = await startRemoteControlApp([], { env: envWithoutEnableLogging }); + const stderrComplete = new Promise((resolve) => { + let stderr = ''; + rc.process.stderr!.on('data', function listener(chunk) { + stderr += chunk.toString('utf8'); + }); + rc.process.on('close', () => { + resolve(stderr); + }); + }); + const [hasLoggingSwitch, hasLoggingVar] = await rc.remotely(() => { + // Make sure we're actually capturing stderr by logging a known value to + // stderr. + console.error('SENTINEL'); + process._linkedBinding('electron_common_testing').log(0, 'TEST_LOG'); + setTimeout(() => { + process.exit(0); + }); + return [require('electron').app.commandLine.hasSwitch('enable-logging'), !!process.env.ELECTRON_ENABLE_LOGGING]; + }); + expect(hasLoggingSwitch).to.be.false(); + expect(hasLoggingVar).to.be.false(); + const stderr = await stderrComplete; + // stderr should include the sentinel but not the LOG() message. + expect(stderr).to.match(/SENTINEL/); + expect(stderr).not.to.match(/TEST_LOG/); + }); + + it('logs to stderr when --enable-logging is passed', async () => { + const rc = await startRemoteControlApp(['--enable-logging']); + const stderrComplete = new Promise((resolve) => { + let stderr = ''; + rc.process.stderr!.on('data', function listener(chunk) { + stderr += chunk.toString('utf8'); + }); + rc.process.on('close', () => { + resolve(stderr); + }); + }); + rc.remotely(() => { + process._linkedBinding('electron_common_testing').log(0, 'TEST_LOG'); + setTimeout(() => { + require('electron').app.quit(); + }); + }); + const stderr = await stderrComplete; + expect(stderr).to.match(/TEST_LOG/); + }); + + it('logs to stderr when ELECTRON_ENABLE_LOGGING is set', async () => { + const rc = await startRemoteControlApp([], { env: { ...process.env, ELECTRON_ENABLE_LOGGING: '1' } }); + const stderrComplete = new Promise((resolve) => { + let stderr = ''; + rc.process.stderr!.on('data', function listener(chunk) { + stderr += chunk.toString('utf8'); + }); + rc.process.on('close', () => { + resolve(stderr); + }); + }); + rc.remotely(() => { + process._linkedBinding('electron_common_testing').log(0, 'TEST_LOG'); + setTimeout(() => { + require('electron').app.quit(); + }); + }); + const stderr = await stderrComplete; + expect(stderr).to.match(/TEST_LOG/); + }); + + it('logs to a file in the user data dir when --enable-logging=file is passed', async () => { + const rc = await startRemoteControlApp(['--enable-logging=file']); + const userDataDir = await rc.remotely(() => { + const { app } = require('electron'); + process._linkedBinding('electron_common_testing').log(0, 'TEST_LOG'); + setTimeout(() => { + app.quit(); + }); + return app.getPath('userData'); + }); + await once(rc.process, 'exit'); + const logFilePath = path.join(userDataDir, 'electron_debug.log'); + const stat = await fs.stat(logFilePath); + expect(stat.isFile()).to.be.true(); + const contents = await fs.readFile(logFilePath, 'utf8'); + expect(contents).to.match(/TEST_LOG/); + }); + + it('logs to a file in the user data dir when ELECTRON_ENABLE_LOGGING=file is set', async () => { + const rc = await startRemoteControlApp([], { env: { ...process.env, ELECTRON_ENABLE_LOGGING: 'file' } }); + const userDataDir = await rc.remotely(() => { + const { app } = require('electron'); + process._linkedBinding('electron_common_testing').log(0, 'TEST_LOG'); + setTimeout(() => { + app.quit(); + }); + return app.getPath('userData'); + }); + await once(rc.process, 'exit'); + const logFilePath = path.join(userDataDir, 'electron_debug.log'); + const stat = await fs.stat(logFilePath); + expect(stat.isFile()).to.be.true(); + const contents = await fs.readFile(logFilePath, 'utf8'); + expect(contents).to.match(/TEST_LOG/); + }); + + it('logs to the given file when --log-file is passed', async () => { + const logFilePath = path.join(app.getPath('temp'), 'test-log-file-' + uuid.v4()); + const rc = await startRemoteControlApp(['--enable-logging', '--log-file=' + logFilePath]); + rc.remotely(() => { + process._linkedBinding('electron_common_testing').log(0, 'TEST_LOG'); + setTimeout(() => { + require('electron').app.quit(); + }); + }); + await once(rc.process, 'exit'); + const stat = await fs.stat(logFilePath); + expect(stat.isFile()).to.be.true(); + const contents = await fs.readFile(logFilePath, 'utf8'); + expect(contents).to.match(/TEST_LOG/); + }); + + ifit(process.platform === 'win32')('child process logs to the given file when --log-file is passed', async () => { + const logFilePath = path.join(app.getPath('temp'), 'test-log-file-' + uuid.v4()); + const preloadPath = path.resolve(__dirname, 'fixtures', 'log-test.js'); + const rc = await startRemoteControlApp([ + '--enable-logging', + `--log-file=${logFilePath}`, + `--boot-eval=preloadPath=${JSON.stringify(preloadPath)}` + ]); + rc.remotely(() => { + process._linkedBinding('electron_common_testing').log(0, 'MAIN_PROCESS_TEST_LOG'); + const { app, BrowserWindow } = require('electron'); + const w = new BrowserWindow({ + show: false, + webPreferences: { + preload: preloadPath, + additionalArguments: ['--unsafely-expose-electron-internals-for-testing'] + } + }); + w.loadURL('about:blank'); + w.webContents.once('did-finish-load', () => { + setTimeout(() => { + app.quit(); + }); + }); + }); + await once(rc.process, 'exit'); + const stat = await fs.stat(logFilePath); + expect(stat.isFile()).to.be.true(); + const contents = await fs.readFile(logFilePath, 'utf8'); + expect(contents).to.match(/MAIN_PROCESS_TEST_LOG/); + expect(contents).to.match(/CHILD_PROCESS_TEST_LOG/); + expect(contents).to.match(/CHILD_PROCESS_DESTINATION_handle/); + }); + + it('logs to the given file when ELECTRON_LOG_FILE is set', async () => { + const logFilePath = path.join(app.getPath('temp'), 'test-log-file-' + uuid.v4()); + const rc = await startRemoteControlApp([], { + env: { ...process.env, ELECTRON_ENABLE_LOGGING: '1', ELECTRON_LOG_FILE: logFilePath } + }); + rc.remotely(() => { + process._linkedBinding('electron_common_testing').log(0, 'TEST_LOG'); + setTimeout(() => { + require('electron').app.quit(); + }); + }); + await once(rc.process, 'exit'); + const stat = await fs.stat(logFilePath); + expect(stat.isFile()).to.be.true(); + const contents = await fs.readFile(logFilePath, 'utf8'); + expect(contents).to.match(/TEST_LOG/); + }); + + it('does not lose early log messages when logging to a given file with --log-file', async () => { + const logFilePath = path.join(app.getPath('temp'), 'test-log-file-' + uuid.v4()); + const rc = await startRemoteControlApp([ + '--enable-logging', + '--log-file=' + logFilePath, + "--boot-eval=process._linkedBinding('electron_common_testing').log(0, 'EARLY_LOG')" + ]); + rc.remotely(() => { + process._linkedBinding('electron_common_testing').log(0, 'LATER_LOG'); + setTimeout(() => { + require('electron').app.quit(); + }); + }); + await once(rc.process, 'exit'); + const stat = await fs.stat(logFilePath); + expect(stat.isFile()).to.be.true(); + const contents = await fs.readFile(logFilePath, 'utf8'); + expect(contents).to.match(/EARLY_LOG/); + expect(contents).to.match(/LATER_LOG/); + }); + + it('enables logging when switch is appended during first tick', async () => { + const rc = await startRemoteControlApp([ + "--boot-eval=require('electron').app.commandLine.appendSwitch('--enable-logging')" + ]); + const stderrComplete = new Promise((resolve) => { + let stderr = ''; + rc.process.stderr!.on('data', function listener(chunk) { + stderr += chunk.toString('utf8'); + }); + rc.process.on('close', () => { + resolve(stderr); + }); + }); + rc.remotely(() => { + process._linkedBinding('electron_common_testing').log(0, 'TEST_LOG'); + setTimeout(() => { + require('electron').app.quit(); + }); + }); + const stderr = await stderrComplete; + expect(stderr).to.match(/TEST_LOG/); + }); + + it('respects --log-level', async () => { + const rc = await startRemoteControlApp(['--enable-logging', '--log-level=1']); + const stderrComplete = new Promise((resolve) => { + let stderr = ''; + rc.process.stderr!.on('data', function listener(chunk) { + stderr += chunk.toString('utf8'); + }); + rc.process.on('close', () => { + resolve(stderr); + }); + }); + rc.remotely(() => { + process._linkedBinding('electron_common_testing').log(0, 'TEST_INFO_LOG'); + process._linkedBinding('electron_common_testing').log(1, 'TEST_WARNING_LOG'); + setTimeout(() => { + require('electron').app.quit(); + }); + }); + const stderr = await stderrComplete; + expect(stderr).to.match(/TEST_WARNING_LOG/); + expect(stderr).not.to.match(/TEST_INFO_LOG/); + }); +}); diff --git a/spec/mas-spec.ts b/spec/mas-spec.ts new file mode 100644 index 0000000000000..bfecf75f19ef1 --- /dev/null +++ b/spec/mas-spec.ts @@ -0,0 +1,236 @@ +import * as cp from 'node:child_process'; +import * as path from 'node:path'; + +import { ifdescribe } from './lib/spec-helpers'; + +ifdescribe(process.platform === 'darwin' && process.mas)('Mac App Store build', () => { + describe('private API usage', () => { + // Get paths to all Electron binaries + const getElectronBinaries = () => { + const contentsPath = path.dirname(path.dirname(process.execPath)); + return { + mainProcess: process.execPath, + framework: path.join(contentsPath, 'Frameworks', 'Electron Framework.framework', 'Electron Framework'), + helpers: { + main: path.join(contentsPath, 'Frameworks', 'Electron Helper.app', 'Contents', 'MacOS', 'Electron Helper'), + gpu: path.join( + contentsPath, + 'Frameworks', + 'Electron Helper (GPU).app', + 'Contents', + 'MacOS', + 'Electron Helper (GPU)' + ), + plugin: path.join( + contentsPath, + 'Frameworks', + 'Electron Helper (Plugin).app', + 'Contents', + 'MacOS', + 'Electron Helper (Plugin)' + ), + renderer: path.join( + contentsPath, + 'Frameworks', + 'Electron Helper (Renderer).app', + 'Contents', + 'MacOS', + 'Electron Helper (Renderer)' + ) + } + }; + }; + + const checkBinaryForPrivateAPIs = (binaryPath: string, binaryName: string) => { + // Use nm without -U to get all symbols (both defined and undefined) + const nmResult = cp.spawnSync('nm', ['-g', binaryPath], { + encoding: 'utf-8', + maxBuffer: 50 * 1024 * 1024 + }); + + if (nmResult.error) { + throw new Error(`Failed to run nm on ${binaryName}: ${nmResult.error.message}`); + } + + const symbols = nmResult.stdout; + + // List of known private APIs that should not be present in MAS builds + // These are from the mas_avoid_private_macos_api_usage.patch + const privateAPIs = [ + 'abort_report_np', + 'pthread_fchdir_np', + 'pthread_chdir_np', + 'SetApplicationIsDaemon', + '_LSSetApplicationLaunchServicesServerConnectionStatus', + 'CGSSetWindowCaptureExcludeShape', + 'CGRegionCreateWithRect', + 'CTFontCopyVariationAxesInternal', + 'AudioDeviceDuck', + 'CGSMainConnectionID', + 'IOBluetoothPreferenceSetControllerPowerState', + 'CGSSetDenyWindowServerConnections', + 'CGFontRenderingGetFontSmoothingDisabled', + 'CTFontDescriptorIsSystemUIFont', + 'sandbox_init_with_parameters', + 'sandbox_create_params', + 'sandbox_set_param', + 'sandbox_free_params', + 'sandbox_compile_string', + 'sandbox_apply', + 'sandbox_free_profile', + 'sandbox_extension_issue_file', + 'sandbox_extension_consume', + 'sandbox_extension_release', + '_CSCheckFixDisable', + 'responsibility_get_pid_responsible_for_pid', + '_NSAppendToKillRing', + '_NSPrependToKillRing', + '_NSYankFromKillRing', + '__NSNewKillRingSequence', + '__NSInitializeKillRing', + '_NSSetKillRingToYankedState' + ]; + + const foundPrivateAPIs: string[] = []; + + for (const api of privateAPIs) { + // Check if the symbol appears in the nm output + // Look for ' U ' (undefined) or ' T ' (defined in text section) followed by the API + // nm output format is like: " U _symbol_name" + const regex = new RegExp(`\\s+[UT]\\s+(_${api})\\b`); + const match = symbols.match(regex); + if (match) { + // Keep the full symbol name including the underscore + foundPrivateAPIs.push(match[1]); + } + } + + return foundPrivateAPIs; + }; + + it('should not use private macOS APIs in main process', function () { + this.timeout(60000); + + const binaries = getElectronBinaries(); + const foundPrivateAPIs = checkBinaryForPrivateAPIs(binaries.mainProcess, 'Electron main process'); + + if (foundPrivateAPIs.length > 0) { + throw new Error( + `Found private macOS APIs in main process:\n${foundPrivateAPIs.join('\n')}\n\n` + + 'These APIs are not allowed in Mac App Store builds and will cause rejection.' + ); + } + + // Also check for private framework linkage + const otoolResult = cp.spawnSync('otool', ['-L', binaries.mainProcess], { + encoding: 'utf-8' + }); + + if (otoolResult.error) { + throw new Error(`Failed to run otool: ${otoolResult.error.message}`); + } + + const frameworks = otoolResult.stdout; + + if (frameworks.includes('PrivateFrameworks')) { + throw new Error( + 'Found linkage to PrivateFrameworks which is not allowed in Mac App Store builds:\n' + frameworks + ); + } + }); + + it('should not use private macOS APIs in Electron Framework', function () { + this.timeout(60000); + + // Check the Electron Framework binary (mentioned in issue #49616) + const binaries = getElectronBinaries(); + const foundAPIs = checkBinaryForPrivateAPIs(binaries.framework, 'Electron Framework'); + + if (foundAPIs.length > 0) { + throw new Error( + `Found private macOS APIs in Electron Framework:\n${foundAPIs.join('\n')}\n\n` + + 'These APIs are not allowed in Mac App Store builds and will cause rejection.\n' + + 'See patches/chromium/mas_avoid_private_macos_api_usage.patch.patch' + ); + } + }); + + it('should not use private macOS APIs in helper processes', function () { + this.timeout(60000); + + const binaries = getElectronBinaries(); + const allFoundAPIs: Record = {}; + + for (const [helperName, helperPath] of Object.entries(binaries.helpers)) { + const displayName = `Electron Helper${helperName !== 'main' ? ` (${helperName.charAt(0).toUpperCase() + helperName.slice(1)})` : ''}`; + const foundAPIs = checkBinaryForPrivateAPIs(helperPath, displayName); + + if (foundAPIs.length > 0) { + allFoundAPIs[displayName] = foundAPIs; + } + } + + if (Object.keys(allFoundAPIs).length > 0) { + const errorLines = Object.entries(allFoundAPIs).map(([helper, apis]) => `${helper}:\n ${apis.join('\n ')}`); + + throw new Error( + `Found private macOS APIs in helper processes:\n\n${errorLines.join('\n\n')}\n\n` + + 'These APIs are not allowed in Mac App Store builds and will cause rejection.' + ); + } + }); + + it('should not reference private Objective-C classes', function () { + this.timeout(60000); + + // Check for private Objective-C classes (appear as _OBJC_CLASS_$_ClassName) + const privateClasses = ['NSAccessibilityRemoteUIElement', 'CAContext']; + + const binaries = getElectronBinaries(); + const binariesToCheck = [ + { path: binaries.mainProcess, name: 'Electron main process' }, + { path: binaries.framework, name: 'Electron Framework' }, + { path: binaries.helpers.main, name: 'Electron Helper' }, + { path: binaries.helpers.renderer, name: 'Electron Helper (Renderer)' } + ]; + + const foundClasses: Record = {}; + + for (const binary of binariesToCheck) { + const nmResult = cp.spawnSync('nm', ['-g', binary.path], { + encoding: 'utf-8', + maxBuffer: 50 * 1024 * 1024 + }); + + if (nmResult.error) { + throw new Error(`Failed to run nm on ${binary.name}: ${nmResult.error.message}`); + } + + const symbols = nmResult.stdout; + const foundInBinary: string[] = []; + + for (const className of privateClasses) { + // Look for _OBJC_CLASS_$_ClassName pattern + if (symbols.includes(`_OBJC_CLASS_$_${className}`)) { + foundInBinary.push(className); + } + } + + if (foundInBinary.length > 0) { + foundClasses[binary.name] = foundInBinary; + } + } + + if (Object.keys(foundClasses).length > 0) { + const errorLines = Object.entries(foundClasses).map( + ([binary, classes]) => `${binary}:\n ${classes.join('\n ')}` + ); + + throw new Error( + `Found references to private Objective-C classes:\n\n${errorLines.join('\n\n')}\n\n` + + 'These are not allowed in Mac App Store builds and will cause rejection.' + ); + } + }); + }); +}); diff --git a/spec/modules-spec.ts b/spec/modules-spec.ts new file mode 100644 index 0000000000000..8b4eb9aa8580c --- /dev/null +++ b/spec/modules-spec.ts @@ -0,0 +1,325 @@ +import { BrowserWindow, utilityProcess } from 'electron/main'; + +import { expect } from 'chai'; + +import * as childProcess from 'node:child_process'; +import { once } from 'node:events'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; + +import { ifdescribe, ifit } from './lib/spec-helpers'; +import { closeAllWindows } from './lib/window-helpers'; + +const Module = require('node:module') as NodeJS.ModuleInternal; + +const nativeModulesEnabled = !process.env.ELECTRON_SKIP_NATIVE_MODULE_TESTS; + +describe('modules support', () => { + const fixtures = path.join(__dirname, 'fixtures'); + + describe('third-party module', () => { + ifdescribe(nativeModulesEnabled)('echo', () => { + afterEach(closeAllWindows); + it('can be required in renderer', async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { nodeIntegration: true, contextIsolation: false } + }); + w.loadURL('about:blank'); + await expect(w.webContents.executeJavaScript("{ require('@electron-ci/echo'); null }")).to.be.fulfilled(); + }); + + it('can be required in node binary', async function () { + const child = childProcess.fork(path.join(fixtures, 'module', 'echo.js')); + const [msg] = await once(child, 'message'); + expect(msg).to.equal('ok'); + }); + + ifit(process.platform === 'win32')('can be required if electron.exe is renamed', () => { + const testExecPath = path.join(path.dirname(process.execPath), 'test.exe'); + fs.copyFileSync(process.execPath, testExecPath); + try { + const fixture = path.join(fixtures, 'module', 'echo-renamed.js'); + expect(fs.existsSync(fixture)).to.be.true(); + const child = childProcess.spawnSync(testExecPath, [fixture]); + expect(child.status).to.equal(0); + } finally { + fs.unlinkSync(testExecPath); + } + }); + }); + + const enablePlatforms: NodeJS.Platform[] = ['linux', 'darwin', 'win32']; + ifdescribe(nativeModulesEnabled && enablePlatforms.includes(process.platform))('module that use uv_dlopen', () => { + it('can be required in renderer', async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { nodeIntegration: true, contextIsolation: false } + }); + w.loadURL('about:blank'); + await expect(w.webContents.executeJavaScript("{ require('@electron-ci/uv-dlopen'); null }")).to.be.fulfilled(); + }); + + it('can be required in node binary', async function () { + const child = childProcess.fork(path.join(fixtures, 'module', 'uv-dlopen.js')); + const [exitCode] = await once(child, 'exit'); + expect(exitCode).to.equal(0); + }); + }); + + describe('q', () => { + describe('Q.when', () => { + it('emits the fulfil callback', (done) => { + const Q = require('q'); + Q(true).then((val: boolean) => { + expect(val).to.be.true(); + done(); + }); + }); + }); + }); + + describe("require('electron/...')", () => { + const utilityProcessFixturesPath = path.resolve( + __dirname, + 'fixtures', + 'api', + 'utility-process', + 'electron-modules' + ); + + it("require('electron/lol') should throw in the main process", () => { + expect(() => { + require('electron/lol'); + }).to.throw(/Cannot find module 'electron\/lol'/); + }); + + it("require('electron/lol') should throw in the renderer process", async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { nodeIntegration: true, contextIsolation: false } + }); + w.loadURL('about:blank'); + await expect(w.webContents.executeJavaScript("{ require('electron/lol'); null }")).to.eventually.be.rejected(); + }); + + it("require('electron/lol') should throw in the utility process", async () => { + const child = utilityProcess.fork(path.join(utilityProcessFixturesPath, 'require-lol.js'), [], { + stdio: ['ignore', 'ignore', 'pipe'] + }); + let stderr = ''; + child.stderr!.on('data', (data) => { + stderr += data.toString('utf8'); + }); + const [code] = await once(child, 'exit'); + expect(code).to.equal(1); + expect(stderr).to.match(/Cannot find module 'electron\/lol'/); + }); + + it("require('electron') should not throw in the main process", () => { + expect(() => { + require('electron'); + }).to.not.throw(); + }); + + it("require('electron') should not throw in the renderer process", async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { nodeIntegration: true, contextIsolation: false } + }); + w.loadURL('about:blank'); + await expect(w.webContents.executeJavaScript("{ require('electron'); null }")).to.be.fulfilled(); + }); + + it("require('electron/main') should not throw in the main process", () => { + expect(() => { + require('electron/main'); + }).to.not.throw(); + }); + + it("require('electron/main') should not throw in the renderer process", async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { nodeIntegration: true, contextIsolation: false } + }); + w.loadURL('about:blank'); + await expect(w.webContents.executeJavaScript("{ require('electron/main'); null }")).to.be.fulfilled(); + }); + + it("require('electron/main') should not throw in the utility process", async () => { + const child = utilityProcess.fork(path.join(utilityProcessFixturesPath, 'require-main.js')); + const [code] = await once(child, 'exit'); + expect(code).to.equal(0); + }); + + it("require('electron/renderer') should not throw in the main process", () => { + expect(() => { + require('electron/renderer'); + }).to.not.throw(); + }); + + it("require('electron/renderer') should not throw in the renderer process", async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { nodeIntegration: true, contextIsolation: false } + }); + w.loadURL('about:blank'); + await expect(w.webContents.executeJavaScript("{ require('electron/renderer'); null }")).to.be.fulfilled(); + }); + + it("require('electron/renderer') should not throw in the utility process", async () => { + const child = utilityProcess.fork(path.join(utilityProcessFixturesPath, 'require-renderer.js')); + const [code] = await once(child, 'exit'); + expect(code).to.equal(0); + }); + + it("require('electron/common') should not throw in the main process", () => { + expect(() => { + require('electron/common'); + }).to.not.throw(); + }); + + it("require('electron/common') should not throw in the renderer process", async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { nodeIntegration: true, contextIsolation: false } + }); + w.loadURL('about:blank'); + await expect(w.webContents.executeJavaScript("{ require('electron/common'); null }")).to.be.fulfilled(); + }); + + it("require('electron/common') should not throw in the utility process", async () => { + const child = utilityProcess.fork(path.join(utilityProcessFixturesPath, 'require-common.js')); + const [code] = await once(child, 'exit'); + expect(code).to.equal(0); + }); + + it("require('electron/utility') should not throw in the main process", () => { + expect(() => { + require('electron/utility'); + }).to.not.throw(); + }); + + it("require('electron/utility') should not throw in the renderer process", async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { nodeIntegration: true, contextIsolation: false } + }); + w.loadURL('about:blank'); + await expect(w.webContents.executeJavaScript("{ require('electron/utility'); null }")).to.be.fulfilled(); + }); + + it("require('electron/utility') should not throw in the utility process", async () => { + const child = utilityProcess.fork(path.join(utilityProcessFixturesPath, 'require-utility.js')); + const [code] = await once(child, 'exit'); + expect(code).to.equal(0); + }); + }); + + describe('coffeescript', () => { + it('can be registered and used to require .coffee files', () => { + expect(() => { + require('coffeescript').register(); + }).to.not.throw(); + expect(require('./fixtures/module/test.coffee')).to.be.true(); + }); + }); + }); + + describe('global variables', () => { + describe('process', () => { + it('can be declared in a module', () => { + expect(require('./fixtures/module/declare-process')).to.equal('declared process'); + }); + }); + + describe('global', () => { + it('can be declared in a module', () => { + expect(require('./fixtures/module/declare-global')).to.equal('declared global'); + }); + }); + + describe('Buffer', () => { + it('can be declared in a module', () => { + expect(require('./fixtures/module/declare-buffer')).to.equal('declared Buffer'); + }); + }); + }); + + describe('Module._nodeModulePaths', () => { + describe('when the path is inside the resources path', () => { + it('does not include paths outside of the resources path', () => { + let modulePath = process.resourcesPath; + expect(Module._nodeModulePaths(modulePath)).to.deep.equal([path.join(process.resourcesPath, 'node_modules')]); + + modulePath = process.resourcesPath + '-foo'; + const nodeModulePaths = Module._nodeModulePaths(modulePath); + expect(nodeModulePaths).to.include(path.join(modulePath, 'node_modules')); + expect(nodeModulePaths).to.include(path.join(modulePath, '..', 'node_modules')); + + modulePath = path.join(process.resourcesPath, 'foo'); + expect(Module._nodeModulePaths(modulePath)).to.deep.equal([ + path.join(process.resourcesPath, 'foo', 'node_modules'), + path.join(process.resourcesPath, 'node_modules') + ]); + + modulePath = path.join(process.resourcesPath, 'node_modules', 'foo'); + expect(Module._nodeModulePaths(modulePath)).to.deep.equal([ + path.join(process.resourcesPath, 'node_modules', 'foo', 'node_modules'), + path.join(process.resourcesPath, 'node_modules') + ]); + + modulePath = path.join(process.resourcesPath, 'node_modules', 'foo', 'bar'); + expect(Module._nodeModulePaths(modulePath)).to.deep.equal([ + path.join(process.resourcesPath, 'node_modules', 'foo', 'bar', 'node_modules'), + path.join(process.resourcesPath, 'node_modules', 'foo', 'node_modules'), + path.join(process.resourcesPath, 'node_modules') + ]); + + modulePath = path.join(process.resourcesPath, 'node_modules', 'foo', 'node_modules', 'bar'); + expect(Module._nodeModulePaths(modulePath)).to.deep.equal([ + path.join(process.resourcesPath, 'node_modules', 'foo', 'node_modules', 'bar', 'node_modules'), + path.join(process.resourcesPath, 'node_modules', 'foo', 'node_modules'), + path.join(process.resourcesPath, 'node_modules') + ]); + }); + }); + + describe('when the path is outside the resources path', () => { + it('includes paths outside of the resources path', () => { + const modulePath = path.resolve('/foo'); + expect(Module._nodeModulePaths(modulePath)).to.deep.equal([ + path.join(modulePath, 'node_modules'), + path.resolve('/node_modules') + ]); + }); + }); + }); + + describe('require', () => { + describe('when loaded URL is not file: protocol', () => { + afterEach(closeAllWindows); + it('searches for module under app directory', async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { nodeIntegration: true, contextIsolation: false } + }); + w.loadURL('about:blank'); + const result = await w.webContents.executeJavaScript('typeof require("q").when'); + expect(result).to.equal('function'); + }); + }); + }); + + describe('esm', () => { + it('can load the built-in "electron" module via ESM import', async () => { + await expect(import('electron')).to.eventually.be.ok(); + }); + + it('the built-in "electron" module loaded via ESM import has the same exports as the CJS module', async () => { + const esmElectron = await import('electron'); + const cjsElectron = require('electron'); + expect(Object.keys(esmElectron)).to.deep.equal(Object.keys(cjsElectron)); + }); + }); +}); diff --git a/spec/node-spec.js b/spec/node-spec.js deleted file mode 100644 index 8bda6569b6a0e..0000000000000 --- a/spec/node-spec.js +++ /dev/null @@ -1,416 +0,0 @@ -const ChildProcess = require('child_process'); -const { expect } = require('chai'); -const fs = require('fs'); -const path = require('path'); -const os = require('os'); -const { ipcRenderer } = require('electron'); -const features = process._linkedBinding('electron_common_features'); - -const { emittedOnce } = require('./events-helpers'); -const { ifit } = require('./spec-helpers'); - -describe('node feature', () => { - const fixtures = path.join(__dirname, 'fixtures'); - - describe('child_process', () => { - beforeEach(function () { - if (!features.isRunAsNodeEnabled()) { - this.skip(); - } - }); - - describe('child_process.fork', () => { - it('works in current process', async () => { - const child = ChildProcess.fork(path.join(fixtures, 'module', 'ping.js')); - const message = emittedOnce(child, 'message'); - child.send('message'); - const [msg] = await message; - expect(msg).to.equal('message'); - }); - - it('preserves args', async () => { - const args = ['--expose_gc', '-test', '1']; - const child = ChildProcess.fork(path.join(fixtures, 'module', 'process_args.js'), args); - const message = emittedOnce(child, 'message'); - child.send('message'); - const [msg] = await message; - expect(args).to.deep.equal(msg.slice(2)); - }); - - it('works in forked process', async () => { - const child = ChildProcess.fork(path.join(fixtures, 'module', 'fork_ping.js')); - const message = emittedOnce(child, 'message'); - child.send('message'); - const [msg] = await message; - expect(msg).to.equal('message'); - }); - - it('works in forked process when options.env is specifed', async () => { - const child = ChildProcess.fork(path.join(fixtures, 'module', 'fork_ping.js'), [], { - path: process.env.PATH - }); - const message = emittedOnce(child, 'message'); - child.send('message'); - const [msg] = await message; - expect(msg).to.equal('message'); - }); - - it('has String::localeCompare working in script', async () => { - const child = ChildProcess.fork(path.join(fixtures, 'module', 'locale-compare.js')); - const message = emittedOnce(child, 'message'); - child.send('message'); - const [msg] = await message; - expect(msg).to.deep.equal([0, -1, 1]); - }); - - it('has setImmediate working in script', async () => { - const child = ChildProcess.fork(path.join(fixtures, 'module', 'set-immediate.js')); - const message = emittedOnce(child, 'message'); - child.send('message'); - const [msg] = await message; - expect(msg).to.equal('ok'); - }); - - it('pipes stdio', async () => { - const child = ChildProcess.fork(path.join(fixtures, 'module', 'process-stdout.js'), { silent: true }); - let data = ''; - child.stdout.on('data', (chunk) => { - data += String(chunk); - }); - const [code] = await emittedOnce(child, 'close'); - expect(code).to.equal(0); - expect(data).to.equal('pipes stdio'); - }); - - it('works when sending a message to a process forked with the --eval argument', async () => { - const source = "process.on('message', (message) => { process.send(message) })"; - const forked = ChildProcess.fork('--eval', [source]); - const message = emittedOnce(forked, 'message'); - forked.send('hello'); - const [msg] = await message; - expect(msg).to.equal('hello'); - }); - - it('has the electron version in process.versions', async () => { - const source = 'process.send(process.versions)'; - const forked = ChildProcess.fork('--eval', [source]); - const [message] = await emittedOnce(forked, 'message'); - expect(message) - .to.have.own.property('electron') - .that.is.a('string') - .and.matches(/^\d+\.\d+\.\d+(\S*)?$/); - }); - }); - - describe('child_process.spawn', () => { - let child; - - afterEach(() => { - if (child != null) child.kill(); - }); - - it('supports spawning Electron as a node process via the ELECTRON_RUN_AS_NODE env var', async () => { - child = ChildProcess.spawn(process.execPath, [path.join(__dirname, 'fixtures', 'module', 'run-as-node.js')], { - env: { - ELECTRON_RUN_AS_NODE: true - } - }); - - let output = ''; - child.stdout.on('data', data => { - output += data; - }); - await emittedOnce(child.stdout, 'close'); - expect(JSON.parse(output)).to.deep.equal({ - stdoutType: 'pipe', - processType: 'undefined', - window: 'undefined' - }); - }); - }); - - describe('child_process.exec', () => { - (process.platform === 'linux' ? it : it.skip)('allows executing a setuid binary from non-sandboxed renderer', () => { - // Chrome uses prctl(2) to set the NO_NEW_PRIVILEGES flag on Linux (see - // https://github.com/torvalds/linux/blob/40fde647cc/Documentation/userspace-api/no_new_privs.rst). - // We disable this for unsandboxed processes, which the renderer tests - // are running in. If this test fails with an error like 'effective uid - // is not 0', then it's likely that our patch to prevent the flag from - // being set has become ineffective. - const stdout = ChildProcess.execSync('sudo --help'); - expect(stdout).to.not.be.empty(); - }); - }); - }); - - describe('contexts', () => { - describe('setTimeout in fs callback', () => { - it('does not crash', (done) => { - fs.readFile(__filename, () => { - setTimeout(done, 0); - }); - }); - }); - - describe('error thrown in renderer process node context', () => { - it('gets emitted as a process uncaughtException event', (done) => { - const error = new Error('boo!'); - const listeners = process.listeners('uncaughtException'); - process.removeAllListeners('uncaughtException'); - process.on('uncaughtException', (thrown) => { - try { - expect(thrown).to.equal(error); - done(); - } catch (e) { - done(e); - } finally { - process.removeAllListeners('uncaughtException'); - listeners.forEach((listener) => process.on('uncaughtException', listener)); - } - }); - fs.readFile(__filename, () => { - throw error; - }); - }); - }); - - describe('URL handling in the renderer process', () => { - it('can successfully handle WHATWG URLs constructed by Blink', () => { - const url = new URL('file://' + path.resolve(fixtures, 'pages', 'base-page.html')); - expect(() => { - fs.createReadStream(url); - }).to.not.throw(); - }); - }); - - describe('error thrown in main process node context', () => { - it('gets emitted as a process uncaughtException event', () => { - const error = ipcRenderer.sendSync('handle-uncaught-exception', 'hello'); - expect(error).to.equal('hello'); - }); - }); - - describe('promise rejection in main process node context', () => { - it('gets emitted as a process unhandledRejection event', () => { - const error = ipcRenderer.sendSync('handle-unhandled-rejection', 'hello'); - expect(error).to.equal('hello'); - }); - }); - - describe('setTimeout called under blink env in renderer process', () => { - it('can be scheduled in time', (done) => { - setTimeout(done, 10); - }); - - it('works from the timers module', (done) => { - require('timers').setTimeout(done, 10); - }); - }); - - describe('setInterval called under blink env in renderer process', () => { - it('can be scheduled in time', (done) => { - const id = setInterval(() => { - clearInterval(id); - done(); - }, 10); - }); - - it('can be scheduled in time from timers module', (done) => { - const { setInterval, clearInterval } = require('timers'); - const id = setInterval(() => { - clearInterval(id); - done(); - }, 10); - }); - }); - }); - - describe('message loop', () => { - describe('process.nextTick', () => { - it('emits the callback', (done) => process.nextTick(done)); - - it('works in nested calls', (done) => { - process.nextTick(() => { - process.nextTick(() => process.nextTick(done)); - }); - }); - }); - - describe('setImmediate', () => { - it('emits the callback', (done) => setImmediate(done)); - - it('works in nested calls', (done) => { - setImmediate(() => { - setImmediate(() => setImmediate(done)); - }); - }); - }); - }); - - describe('net.connect', () => { - before(function () { - if (!features.isRunAsNodeEnabled() || process.platform !== 'darwin') { - this.skip(); - } - }); - - it('emit error when connect to a socket path without listeners', async () => { - const socketPath = path.join(os.tmpdir(), 'atom-shell-test.sock'); - const script = path.join(fixtures, 'module', 'create_socket.js'); - const child = ChildProcess.fork(script, [socketPath]); - const [code] = await emittedOnce(child, 'exit'); - expect(code).to.equal(0); - const client = require('net').connect(socketPath); - const [error] = await emittedOnce(client, 'error'); - expect(error.code).to.equal('ECONNREFUSED'); - }); - }); - - describe('Buffer', () => { - it('can be created from WebKit external string', () => { - const p = document.createElement('p'); - p.innerText = '闲云潭影日悠悠,物换星移几度秋'; - const b = Buffer.from(p.innerText); - expect(b.toString()).to.equal('闲云潭影日悠悠,物换星移几度秋'); - expect(Buffer.byteLength(p.innerText)).to.equal(45); - }); - - it('correctly parses external one-byte UTF8 string', () => { - const p = document.createElement('p'); - p.innerText = 'Jøhänñéß'; - const b = Buffer.from(p.innerText); - expect(b.toString()).to.equal('Jøhänñéß'); - expect(Buffer.byteLength(p.innerText)).to.equal(13); - }); - - it('does not crash when creating large Buffers', () => { - let buffer = Buffer.from(new Array(4096).join(' ')); - expect(buffer.length).to.equal(4095); - buffer = Buffer.from(new Array(4097).join(' ')); - expect(buffer.length).to.equal(4096); - }); - - it('does not crash for crypto operations', () => { - const crypto = require('crypto'); - const data = 'lG9E+/g4JmRmedDAnihtBD4Dfaha/GFOjd+xUOQI05UtfVX3DjUXvrS98p7kZQwY3LNhdiFo7MY5rGft8yBuDhKuNNag9vRx/44IuClDhdQ='; - const key = 'q90K9yBqhWZnAMCMTOJfPQ=='; - const cipherText = '{"error_code":114,"error_message":"Tham số không hợp lệ","data":null}'; - for (let i = 0; i < 10000; ++i) { - const iv = Buffer.from('0'.repeat(32), 'hex'); - const input = Buffer.from(data, 'base64'); - const decipher = crypto.createDecipheriv('aes-128-cbc', Buffer.from(key, 'base64'), iv); - const result = Buffer.concat([decipher.update(input), decipher.final()]).toString('utf8'); - expect(cipherText).to.equal(result); - } - }); - }); - - describe('process.stdout', () => { - it('does not throw an exception when accessed', () => { - expect(() => process.stdout).to.not.throw(); - }); - - it('does not throw an exception when calling write()', () => { - expect(() => { - process.stdout.write('test'); - }).to.not.throw(); - }); - - // TODO: figure out why process.stdout.isTTY is true on Darwin but not Linux/Win. - ifit(process.platform !== 'darwin')('isTTY should be undefined in the renderer process', function () { - expect(process.stdout.isTTY).to.be.undefined(); - }); - }); - - describe('process.stdin', () => { - it('does not throw an exception when accessed', () => { - expect(() => process.stdin).to.not.throw(); - }); - - it('returns null when read from', () => { - expect(process.stdin.read()).to.be.null(); - }); - }); - - describe('process.version', () => { - it('should not have -pre', () => { - expect(process.version.endsWith('-pre')).to.be.false(); - }); - }); - - describe('vm.runInNewContext', () => { - it('should not crash', () => { - require('vm').runInNewContext(''); - }); - }); - - describe('crypto', () => { - it('should list the ripemd160 hash in getHashes', () => { - expect(require('crypto').getHashes()).to.include('ripemd160'); - }); - - it('should be able to create a ripemd160 hash and use it', () => { - const hash = require('crypto').createHash('ripemd160'); - hash.update('electron-ripemd160'); - expect(hash.digest('hex')).to.equal('fa7fec13c624009ab126ebb99eda6525583395fe'); - }); - - it('should list aes-{128,256}-cfb in getCiphers', () => { - expect(require('crypto').getCiphers()).to.include.members(['aes-128-cfb', 'aes-256-cfb']); - }); - - it('should be able to create an aes-128-cfb cipher', () => { - require('crypto').createCipheriv('aes-128-cfb', '0123456789abcdef', '0123456789abcdef'); - }); - - it('should be able to create an aes-256-cfb cipher', () => { - require('crypto').createCipheriv('aes-256-cfb', '0123456789abcdef0123456789abcdef', '0123456789abcdef'); - }); - - it('should list des-ede-cbc in getCiphers', () => { - expect(require('crypto').getCiphers()).to.include('des-ede-cbc'); - }); - - it('should be able to create an des-ede-cbc cipher', () => { - const key = Buffer.from('0123456789abcdeff1e0d3c2b5a49786', 'hex'); - const iv = Buffer.from('fedcba9876543210', 'hex'); - require('crypto').createCipheriv('des-ede-cbc', key, iv); - }); - - it('should not crash when getting an ECDH key', () => { - const ecdh = require('crypto').createECDH('prime256v1'); - expect(ecdh.generateKeys()).to.be.an.instanceof(Buffer); - expect(ecdh.getPrivateKey()).to.be.an.instanceof(Buffer); - }); - - it('should not crash when generating DH keys or fetching DH fields', () => { - const dh = require('crypto').createDiffieHellman('modp15'); - expect(dh.generateKeys()).to.be.an.instanceof(Buffer); - expect(dh.getPublicKey()).to.be.an.instanceof(Buffer); - expect(dh.getPrivateKey()).to.be.an.instanceof(Buffer); - expect(dh.getPrime()).to.be.an.instanceof(Buffer); - expect(dh.getGenerator()).to.be.an.instanceof(Buffer); - }); - - it('should not crash when creating an ECDH cipher', () => { - const crypto = require('crypto'); - const dh = crypto.createECDH('prime256v1'); - dh.generateKeys(); - dh.setPrivateKey(dh.getPrivateKey()); - }); - }); - - it('includes the electron version in process.versions', () => { - expect(process.versions) - .to.have.own.property('electron') - .that.is.a('string') - .and.matches(/^\d+\.\d+\.\d+(\S*)?$/); - }); - - it('includes the chrome version in process.versions', () => { - expect(process.versions) - .to.have.own.property('chrome') - .that.is.a('string') - .and.matches(/^\d+\.\d+\.\d+\.\d+$/); - }); -}); diff --git a/spec/node-spec.ts b/spec/node-spec.ts new file mode 100644 index 0000000000000..7660fbe46c08b --- /dev/null +++ b/spec/node-spec.ts @@ -0,0 +1,1175 @@ +import { webContents } from 'electron/main'; + +import { expect } from 'chai'; + +import * as childProcess from 'node:child_process'; +import { once } from 'node:events'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import { EventEmitter } from 'node:stream'; +import * as util from 'node:util'; + +import { + copyMacOSFixtureApp, + getCodesignIdentity, + shouldRunCodesignTests, + signApp, + spawn +} from './lib/codesign-helpers'; +import { withTempDirectory } from './lib/fs-helpers'; +import { getRemoteContext, ifdescribe, ifit, itremote, useRemoteContext } from './lib/spec-helpers'; + +const mainFixturesPath = path.resolve(__dirname, 'fixtures'); + +describe('node feature', () => { + const fixtures = path.join(__dirname, 'fixtures'); + + describe('child_process', () => { + describe('child_process.fork', () => { + it('Works in browser process', async () => { + const child = childProcess.fork(path.join(fixtures, 'module', 'ping.js')); + const message = once(child, 'message'); + child.send('message'); + const [msg] = await message; + expect(msg).to.equal('message'); + }); + + it('Has its module search paths restricted', async () => { + const child = childProcess.fork(path.join(fixtures, 'module', 'module-paths.js')); + const [msg] = await once(child, 'message'); + expect(msg.length).to.equal(2); + }); + }); + }); + + describe('child_process in renderer', () => { + useRemoteContext(); + + describe('child_process.fork', () => { + itremote( + 'works in current process', + async (fixtures: string) => { + const child = require('node:child_process').fork(require('node:path').join(fixtures, 'module', 'ping.js')); + const message = new Promise((resolve) => child.once('message', resolve)); + child.send('message'); + const msg = await message; + expect(msg).to.equal('message'); + }, + [fixtures] + ); + + itremote( + 'preserves args', + async (fixtures: string) => { + const args = ['--expose_gc', '-test', '1']; + const child = require('node:child_process').fork( + require('node:path').join(fixtures, 'module', 'process_args.js'), + args + ); + const message = new Promise((resolve) => child.once('message', resolve)); + child.send('message'); + const msg = await message; + expect(args).to.deep.equal(msg.slice(2)); + }, + [fixtures] + ); + + itremote( + 'works in forked process', + async (fixtures: string) => { + const child = require('node:child_process').fork( + require('node:path').join(fixtures, 'module', 'fork_ping.js') + ); + const message = new Promise((resolve) => child.once('message', resolve)); + child.send('message'); + const msg = await message; + expect(msg).to.equal('message'); + }, + [fixtures] + ); + + itremote( + 'works in forked process when options.env is specified', + async (fixtures: string) => { + const child = require('node:child_process').fork( + require('node:path').join(fixtures, 'module', 'fork_ping.js'), + [], + { + path: process.env.PATH + } + ); + const message = new Promise((resolve) => child.once('message', resolve)); + child.send('message'); + const msg = await message; + expect(msg).to.equal('message'); + }, + [fixtures] + ); + + itremote( + 'has String::localeCompare working in script', + async (fixtures: string) => { + const child = require('node:child_process').fork( + require('node:path').join(fixtures, 'module', 'locale-compare.js') + ); + const message = new Promise((resolve) => child.once('message', resolve)); + child.send('message'); + const msg = await message; + expect(msg).to.deep.equal([0, -1, 1]); + }, + [fixtures] + ); + + itremote( + 'has setImmediate working in script', + async (fixtures: string) => { + const child = require('node:child_process').fork( + require('node:path').join(fixtures, 'module', 'set-immediate.js') + ); + const message = new Promise((resolve) => child.once('message', resolve)); + child.send('message'); + const msg = await message; + expect(msg).to.equal('ok'); + }, + [fixtures] + ); + + itremote( + 'pipes stdio', + async (fixtures: string) => { + const child = require('node:child_process').fork( + require('node:path').join(fixtures, 'module', 'process-stdout.js'), + { silent: true } + ); + let data = ''; + child.stdout.on('data', (chunk: any) => { + data += String(chunk); + }); + const code = await new Promise((resolve) => child.once('close', resolve)); + expect(code).to.equal(0); + expect(data).to.equal('pipes stdio'); + }, + [fixtures] + ); + + itremote('works when sending a message to a process forked with the --eval argument', async () => { + const source = "process.on('message', (message) => { process.send(message) })"; + const forked = require('node:child_process').fork('--eval', [source]); + const message = new Promise((resolve) => forked.once('message', resolve)); + forked.send('hello'); + const msg = await message; + expect(msg).to.equal('hello'); + }); + + it('has the electron version in process.versions', async () => { + const source = 'process.send(process.versions)'; + const forked = require('node:child_process').fork('--eval', [source]); + const [message] = await once(forked, 'message'); + expect(message) + .to.have.own.property('electron') + .that.is.a('string') + .and.matches(/^\d+\.\d+\.\d+(\S*)?$/); + }); + }); + + describe('child_process.spawn', () => { + itremote( + 'supports spawning Electron as a node process via the ELECTRON_RUN_AS_NODE env var', + async (fixtures: string) => { + const child = require('node:child_process').spawn( + process.execPath, + [require('node:path').join(fixtures, 'module', 'run-as-node.js')], + { + env: { + ELECTRON_RUN_AS_NODE: true + } + } + ); + + let output = ''; + child.stdout.on('data', (data: any) => { + output += data; + }); + try { + await new Promise((resolve) => child.stdout.once('close', resolve)); + expect(JSON.parse(output)).to.deep.equal({ + stdoutType: 'pipe', + processType: 'undefined', + window: 'undefined' + }); + } finally { + child.kill(); + } + }, + [fixtures] + ); + }); + + describe('child_process.exec', () => { + ifit(process.platform === 'linux')('allows executing a setuid binary from non-sandboxed renderer', async () => { + // Chrome uses prctl(2) to set the NO_NEW_PRIVILEGES flag on Linux (see + // https://github.com/torvalds/linux/blob/40fde647cc/Documentation/userspace-api/no_new_privs.rst). + // We disable this for unsandboxed processes, which the renderer tests + // are running in. If this test fails with an error like 'effective uid + // is not 0', then it's likely that our patch to prevent the flag from + // being set has become ineffective. + const w = await getRemoteContext(); + const stdout = await w.webContents.executeJavaScript("require('child_process').execSync('sudo --help')"); + expect(stdout).to.not.be.empty(); + }); + }); + }); + + describe('EventSource', () => { + itremote('works correctly when nodeIntegration is enabled in the renderer', () => { + const es = new EventSource('https://example.com'); + expect(es).to.have.property('url').that.is.a('string'); + expect(es).to.have.property('readyState').that.is.a('number'); + expect(es).to.have.property('withCredentials').that.is.a('boolean'); + }); + }); + + describe('fetch', () => { + itremote( + 'works correctly when nodeIntegration is enabled in the renderer', + async (fixtures: string) => { + const file = require('node:path').join(fixtures, 'hello.txt'); + expect(() => { + fetch('file://' + file); + }).to.not.throw(); + + expect(() => { + const formData = new FormData(); + formData.append('username', 'Groucho'); + }).not.to.throw(); + + expect(() => { + const request = new Request('https://example.com', { + method: 'POST', + body: JSON.stringify({ foo: 'bar' }) + }); + expect(request.method).to.equal('POST'); + }).not.to.throw(); + + expect(() => { + const response = new Response('Hello, world!'); + expect(response.status).to.equal(200); + }).not.to.throw(); + + expect(() => { + const headers = new Headers(); + headers.append('Content-Type', 'text/xml'); + }).not.to.throw(); + }, + [fixtures] + ); + }); + + it('does not hang when using the fs module in the renderer process', async () => { + const appPath = path.join(mainFixturesPath, 'apps', 'libuv-hang', 'main.js'); + const appProcess = childProcess.spawn(process.execPath, [appPath], { + cwd: path.join(mainFixturesPath, 'apps', 'libuv-hang'), + stdio: 'inherit' + }); + const [code] = await once(appProcess, 'close'); + expect(code).to.equal(0); + }); + + describe('contexts', () => { + describe('setTimeout called under Chromium event loop in browser process', () => { + it('Can be scheduled in time', (done) => { + setTimeout(done, 0); + }); + + it('Can be promisified', (done) => { + util.promisify(setTimeout)(0).then(done); + }); + }); + + describe('setInterval called under Chromium event loop in browser process', () => { + it('can be scheduled in time', (done) => { + let interval: any = null; + let clearing = false; + const clear = () => { + if (interval === null || clearing) return; + + // interval might trigger while clearing (remote is slow sometimes) + clearing = true; + clearInterval(interval); + clearing = false; + interval = null; + done(); + }; + interval = setInterval(clear, 10); + }); + }); + + const suspendListeners = (emitter: EventEmitter, eventName: string, callback: (...args: any[]) => void) => { + const listeners = emitter.listeners(eventName) as ((...args: any[]) => void)[]; + emitter.removeAllListeners(eventName); + emitter.once(eventName, (...args) => { + emitter.removeAllListeners(eventName); + for (const listener of listeners) { + emitter.on(eventName, listener); + } + + callback(...args); + }); + }; + describe('error thrown in main process node context', () => { + it('gets emitted as a process uncaughtException event', async () => { + fs.readFile(__filename, () => { + throw new Error('hello'); + }); + const result = await new Promise((resolve) => + suspendListeners(process, 'uncaughtException', (error) => { + resolve(error.message); + }) + ); + expect(result).to.equal('hello'); + }); + }); + + describe('promise rejection in main process node context', () => { + it('gets emitted as a process unhandledRejection event', async () => { + fs.readFile(__filename, () => { + Promise.reject(new Error('hello')); + }); + const result = await new Promise((resolve) => + suspendListeners(process, 'unhandledRejection', (error) => { + resolve(error.message); + }) + ); + expect(result).to.equal('hello'); + }); + + it('does not log the warning more than once when the rejection is unhandled', async () => { + const appPath = path.join(mainFixturesPath, 'api', 'unhandled-rejection.js'); + const appProcess = childProcess.spawn(process.execPath, [appPath]); + + let output = ''; + const out = (data: string) => { + output += data; + if (/UnhandledPromiseRejectionWarning/.test(data)) { + appProcess.kill(); + } + }; + appProcess.stdout!.on('data', out); + appProcess.stderr!.on('data', out); + + await once(appProcess, 'exit'); + expect(/UnhandledPromiseRejectionWarning/.test(output)).to.equal(true); + const matches = output.match(/Error: oops/gm); + expect(matches).to.have.lengthOf(1); + }); + + it('does not log the warning more than once when the rejection is handled', async () => { + const appPath = path.join(mainFixturesPath, 'api', 'unhandled-rejection-handled.js'); + const appProcess = childProcess.spawn(process.execPath, [appPath]); + + let output = ''; + const out = (data: string) => { + output += data; + }; + appProcess.stdout!.on('data', out); + appProcess.stderr!.on('data', out); + + const [code] = await once(appProcess, 'exit'); + expect(code).to.equal(0); + expect(/UnhandledPromiseRejectionWarning/.test(output)).to.equal(false); + const matches = output.match(/Error: oops/gm); + expect(matches).to.have.lengthOf(1); + }); + }); + }); + + describe('contexts in renderer', () => { + useRemoteContext(); + + describe('setTimeout in fs callback', () => { + itremote( + 'does not crash', + async (filename: string) => { + await new Promise((resolve) => + require('node:fs').readFile(filename, () => { + setTimeout(resolve, 0); + }) + ); + }, + [__filename] + ); + }); + + describe('error thrown in renderer process node context', () => { + itremote( + 'gets emitted as a process uncaughtException event', + async (filename: string) => { + const error = new Error('boo!'); + require('node:fs').readFile(filename, () => { + throw error; + }); + await new Promise((resolve, reject) => { + process.once('uncaughtException', (thrown) => { + try { + expect(thrown).to.equal(error); + resolve(); + } catch (e) { + reject(e); + } + }); + }); + }, + [__filename] + ); + }); + + describe('URL handling in the renderer process', () => { + itremote( + 'can successfully handle WHATWG URLs constructed by Blink', + (fixtures: string) => { + const url = new URL('file://' + require('node:path').resolve(fixtures, 'pages', 'base-page.html')); + expect(() => { + require('node:fs').createReadStream(url); + }).to.not.throw(); + }, + [fixtures] + ); + }); + + describe('setTimeout called under blink env in renderer process', () => { + itremote('can be scheduled in time', async () => { + await new Promise((resolve) => setTimeout(resolve, 10)); + }); + + itremote('works from the timers module', async () => { + await new Promise((resolve) => require('node:timers').setTimeout(resolve, 10)); + }); + }); + + describe('setInterval called under blink env in renderer process', () => { + itremote('can be scheduled in time', async () => { + await new Promise((resolve) => { + const id = setInterval(() => { + clearInterval(id); + resolve(); + }, 10); + }); + }); + + itremote('can be scheduled in time from timers module', async () => { + const { setInterval, clearInterval } = require('node:timers'); + await new Promise((resolve) => { + const id = setInterval(() => { + clearInterval(id); + resolve(); + }, 10); + }); + }); + }); + }); + + describe('message loop in renderer', () => { + useRemoteContext(); + + describe('process.nextTick', () => { + itremote('emits the callback', () => new Promise((resolve) => process.nextTick(resolve))); + + itremote( + 'works in nested calls', + () => + new Promise((resolve) => { + process.nextTick(() => { + process.nextTick(() => process.nextTick(resolve)); + }); + }) + ); + }); + + describe('setImmediate', () => { + itremote('emits the callback', () => new Promise((resolve) => setImmediate(resolve))); + + itremote( + 'works in nested calls', + () => + new Promise((resolve) => { + setImmediate(() => { + setImmediate(() => setImmediate(resolve)); + }); + }) + ); + }); + }); + + ifdescribe(process.platform === 'darwin')('net.connect', () => { + itremote( + 'emit error when connect to a socket path without listeners', + async (fixtures: string) => { + const socketPath = require('node:path').join(require('node:os').tmpdir(), 'electron-test.sock'); + const script = require('node:path').join(fixtures, 'module', 'create_socket.js'); + const child = require('node:child_process').fork(script, [socketPath]); + const code = await new Promise((resolve) => child.once('exit', resolve)); + expect(code).to.equal(0); + const client = require('node:net').connect(socketPath); + const error = await new Promise((resolve) => client.once('error', resolve)); + expect(error.code).to.equal('ECONNREFUSED'); + }, + [fixtures] + ); + }); + + describe('Buffer', () => { + useRemoteContext(); + + itremote('can be created from Blink external string', () => { + const p = document.createElement('p'); + p.innerText = '闲云潭影日悠悠,物换星移几度秋'; + const b = Buffer.from(p.innerText); + expect(b.toString()).to.equal('闲云潭影日悠悠,物换星移几度秋'); + expect(Buffer.byteLength(p.innerText)).to.equal(45); + }); + + itremote('correctly parses external one-byte UTF8 string', () => { + const p = document.createElement('p'); + p.innerText = 'Jøhänñéß'; + const b = Buffer.from(p.innerText); + expect(b.toString()).to.equal('Jøhänñéß'); + expect(Buffer.byteLength(p.innerText)).to.equal(13); + }); + + itremote('does not crash when creating large Buffers', () => { + let buffer = Buffer.from(new Array(4096).join(' ')); + expect(buffer.length).to.equal(4095); + buffer = Buffer.from(new Array(4097).join(' ')); + expect(buffer.length).to.equal(4096); + }); + + itremote('does not crash for crypto operations', () => { + const crypto = require('node:crypto'); + const data = + 'lG9E+/g4JmRmedDAnihtBD4Dfaha/GFOjd+xUOQI05UtfVX3DjUXvrS98p7kZQwY3LNhdiFo7MY5rGft8yBuDhKuNNag9vRx/44IuClDhdQ='; + const key = 'q90K9yBqhWZnAMCMTOJfPQ=='; + const cipherText = '{"error_code":114,"error_message":"Tham số không hợp lệ","data":null}'; + for (let i = 0; i < 10000; ++i) { + const iv = Buffer.from('0'.repeat(32), 'hex'); + const input = Buffer.from(data, 'base64'); + const decipher = crypto.createDecipheriv('aes-128-cbc', Buffer.from(key, 'base64'), iv); + const result = Buffer.concat([decipher.update(input), decipher.final()]).toString('utf8'); + expect(cipherText).to.equal(result); + } + }); + + itremote('does not crash when using crypto.diffieHellman() constructors', () => { + const crypto = require('node:crypto'); + + crypto.createDiffieHellman('abc'); + crypto.createDiffieHellman('abc', 2); + + // Needed to test specific DiffieHellman ctors. + + crypto.createDiffieHellman('abc', Buffer.from([2])); + crypto.createDiffieHellman('abc', '123'); + }); + + itremote('does not crash when calling crypto.createPrivateKey() with an unsupported algorithm', () => { + const crypto = require('node:crypto'); + + const ed448 = { + crv: 'Ed448', + x: 'KYWcaDwgH77xdAwcbzOgvCVcGMy9I6prRQBhQTTdKXUcr-VquTz7Fd5adJO0wT2VHysF3bk3kBoA', + d: 'UhC3-vN5vp_g9PnTknXZgfXUez7Xvw-OfuJ0pYkuwzpYkcTvacqoFkV_O05WMHpyXkzH9q2wzx5n', + kty: 'OKP' + }; + + expect(() => { + crypto.createPrivateKey({ key: ed448, format: 'jwk' }); + }).to.throw(/Invalid JWK data/); + }); + }); + + describe('process.stdout', () => { + useRemoteContext(); + + itremote('does not throw an exception when accessed', () => { + expect(() => process.stdout).to.not.throw(); + }); + + itremote('does not throw an exception when calling write()', () => { + expect(() => { + process.stdout.write('test'); + }).to.not.throw(); + }); + + // TODO: figure out why process.stdout.isTTY is true on Darwin but not Linux/Win. + ifdescribe(process.platform !== 'darwin')('isTTY', () => { + itremote('should be undefined in the renderer process', function () { + expect(process.stdout.isTTY).to.be.undefined(); + }); + }); + }); + + describe('process.stdin', () => { + useRemoteContext(); + + itremote('does not throw an exception when accessed', () => { + expect(() => process.stdin).to.not.throw(); + }); + + itremote('returns null when read from', () => { + expect(process.stdin.read()).to.be.null(); + }); + }); + + describe('process.version', () => { + itremote('should not have -pre', () => { + expect(process.version.endsWith('-pre')).to.be.false(); + }); + }); + + describe('vm.runInNewContext', () => { + itremote('should not crash', () => { + require('node:vm').runInNewContext(''); + }); + }); + + describe('crypto', () => { + useRemoteContext(); + itremote('should list the ripemd160 hash in getHashes', () => { + expect(require('node:crypto').getHashes()).to.include('ripemd160'); + }); + + itremote('should be able to create a ripemd160 hash and use it', () => { + const hash = require('node:crypto').createHash('ripemd160'); + hash.update('electron-ripemd160'); + expect(hash.digest('hex')).to.equal('fa7fec13c624009ab126ebb99eda6525583395fe'); + }); + + itremote('should list aes-{128,256}-cfb in getCiphers', () => { + expect(require('node:crypto').getCiphers()).to.include.members(['aes-128-cfb', 'aes-256-cfb']); + }); + + itremote('should be able to create an aes-128-cfb cipher', () => { + require('node:crypto').createCipheriv('aes-128-cfb', '0123456789abcdef', '0123456789abcdef'); + }); + + itremote('should be able to create an aes-256-cfb cipher', () => { + require('node:crypto').createCipheriv('aes-256-cfb', '0123456789abcdef0123456789abcdef', '0123456789abcdef'); + }); + + itremote('should be able to create a bf-{cbc,cfb,ecb} ciphers', () => { + require('node:crypto').createCipheriv('bf-cbc', Buffer.from('0123456789abcdef'), Buffer.from('01234567')); + require('node:crypto').createCipheriv('bf-cfb', Buffer.from('0123456789abcdef'), Buffer.from('01234567')); + require('node:crypto').createCipheriv('bf-ecb', Buffer.from('0123456789abcdef'), Buffer.from('01234567')); + }); + + itremote('should list des-ede-cbc in getCiphers', () => { + expect(require('node:crypto').getCiphers()).to.include('des-ede-cbc'); + }); + + itremote('should be able to create an des-ede-cbc cipher', () => { + const key = Buffer.from('0123456789abcdeff1e0d3c2b5a49786', 'hex'); + const iv = Buffer.from('fedcba9876543210', 'hex'); + require('node:crypto').createCipheriv('des-ede-cbc', key, iv); + }); + + itremote('should not crash when getting an ECDH key', () => { + const ecdh = require('node:crypto').createECDH('prime256v1'); + expect(ecdh.generateKeys()).to.be.an.instanceof(Buffer); + expect(ecdh.getPrivateKey()).to.be.an.instanceof(Buffer); + }); + + itremote('should not crash when generating DH keys or fetching DH fields', () => { + const dh = require('node:crypto').createDiffieHellman('modp15'); + expect(dh.generateKeys()).to.be.an.instanceof(Buffer); + expect(dh.getPublicKey()).to.be.an.instanceof(Buffer); + expect(dh.getPrivateKey()).to.be.an.instanceof(Buffer); + expect(dh.getPrime()).to.be.an.instanceof(Buffer); + expect(dh.getGenerator()).to.be.an.instanceof(Buffer); + }); + + itremote('should not crash when creating an ECDH cipher', () => { + const crypto = require('node:crypto'); + const dh = crypto.createECDH('prime256v1'); + dh.generateKeys(); + dh.setPrivateKey(dh.getPrivateKey()); + }); + }); + + itremote('includes the electron version in process.versions', () => { + expect(process.versions) + .to.have.own.property('electron') + .that.is.a('string') + .and.matches(/^\d+\.\d+\.\d+(\S*)?$/); + }); + + itremote('includes the chrome version in process.versions', () => { + expect(process.versions) + .to.have.own.property('chrome') + .that.is.a('string') + .and.matches(/^\d+\.\d+\.\d+\.\d+$/); + }); + + describe('NODE_OPTIONS', () => { + let child: childProcess.ChildProcessWithoutNullStreams; + let exitPromise: Promise; + + it('Fails for options disallowed by Node.js itself', (done) => { + after(async () => { + const [code, signal] = await exitPromise; + expect(signal).to.equal(null); + + // Exit code 9 indicates cli flag parsing failure + expect(code).to.equal(9); + child.kill(); + }); + + const env = { ...process.env, NODE_OPTIONS: '--v8-options' }; + child = childProcess.spawn(process.execPath, { env }); + exitPromise = once(child, 'exit'); + + let output = ''; + let success = false; + const cleanup = () => { + child.stderr.removeListener('data', listener); + child.stdout.removeListener('data', listener); + }; + + const listener = (data: Buffer) => { + output += data; + if (/electron: --v8-options is not allowed in NODE_OPTIONS/m.test(output)) { + success = true; + cleanup(); + done(); + } + }; + + child.stderr.on('data', listener); + child.stdout.on('data', listener); + child.on('exit', () => { + if (!success) { + cleanup(); + done(new Error(`Unexpected output: ${output.toString()}`)); + } + }); + }); + + it('Disallows crypto-related options', (done) => { + after(() => { + child.kill(); + }); + + const appPath = path.join(fixtures, 'module', 'noop.js'); + const env = { ...process.env, NODE_OPTIONS: '--use-openssl-ca' }; + child = childProcess.spawn(process.execPath, ['--enable-logging', appPath], { env }); + + let output = ''; + const cleanup = () => { + child.stderr.removeListener('data', listener); + child.stdout.removeListener('data', listener); + }; + + const listener = (data: Buffer) => { + output += data; + if (/The NODE_OPTION --use-openssl-ca is not supported in Electron/m.test(output)) { + cleanup(); + done(); + } + }; + + child.stderr.on('data', listener); + child.stdout.on('data', listener); + }); + + it('does allow --require in non-packaged apps', async () => { + const appPath = path.join(fixtures, 'module', 'noop.js'); + const env = { + ...process.env, + NODE_OPTIONS: `--require=${path.join(fixtures, 'module', 'fail.js')}` + }; + // App should exit with code 1. + const child = childProcess.spawn(process.execPath, [appPath], { env }); + const [code] = await once(child, 'exit'); + expect(code).to.equal(1); + }); + + it('does allow --require in utility process of non-packaged apps', async () => { + const appPath = path.join(fixtures, 'apps', 'node-options-utility-process'); + // App should exit with code 1. + const child = childProcess.spawn(process.execPath, [appPath]); + const [code] = await once(child, 'exit'); + expect(code).to.equal(1); + }); + + it('does not allow --require in utility process of packaged apps', async () => { + const appPath = path.join(fixtures, 'apps', 'node-options-utility-process'); + // App should exit with code 1. + const child = childProcess.spawn(process.execPath, [appPath], { + env: { + ...process.env, + ELECTRON_FORCE_IS_PACKAGED: 'true' + } + }); + const [code] = await once(child, 'exit'); + expect(code).to.equal(0); + }); + + it('does not allow --require in packaged apps', async () => { + const appPath = path.join(fixtures, 'module', 'noop.js'); + const env = { + ...process.env, + ELECTRON_FORCE_IS_PACKAGED: 'true', + NODE_OPTIONS: `--require=${path.join(fixtures, 'module', 'fail.js')}` + }; + // App should exit with code 0. + const child = childProcess.spawn(process.execPath, [appPath], { env }); + const [code] = await once(child, 'exit'); + expect(code).to.equal(0); + }); + }); + + ifdescribe(shouldRunCodesignTests)('NODE_OPTIONS in signed app', function () { + let identity = ''; + + beforeEach(function () { + const result = getCodesignIdentity(); + if (result === null) { + this.skip(); + } else { + identity = result; + } + }); + + const script = path.join(fixtures, 'api', 'fork-with-node-options.js'); + const nodeOptionsWarning = + 'Node.js environment variables are disabled because this process is invoked by other apps'; + + it('is disabled when invoked by other apps in ELECTRON_RUN_AS_NODE mode', async () => { + await withTempDirectory(async (dir) => { + const appPath = await copyMacOSFixtureApp(dir); + await signApp(appPath, identity); + // Invoke Electron by using the system node binary as middle layer, so + // the check of NODE_OPTIONS will think the process is started by other + // apps. + const { code, out } = await spawn('node', [script, path.join(appPath, 'Contents/MacOS/Electron')]); + expect(code).to.equal(0); + expect(out).to.include(nodeOptionsWarning); + }); + }); + + it('is disabled when invoked by alien binary in app bundle in ELECTRON_RUN_AS_NODE mode', async function () { + await withTempDirectory(async (dir) => { + const appPath = await copyMacOSFixtureApp(dir); + await signApp(appPath, identity); + // Find system node and copy it to app bundle. + const nodePath = process.env.PATH?.split(path.delimiter).find((dir) => fs.existsSync(path.join(dir, 'node'))); + if (!nodePath) { + this.skip(); + return; + } + const alienBinary = path.join(appPath, 'Contents/MacOS/node'); + await fs.promises.cp(path.join(nodePath, 'node'), alienBinary, { recursive: true }); + // Try to execute electron app from the alien node in app bundle. + const { code, out } = await spawn(alienBinary, [script, path.join(appPath, 'Contents/MacOS/Electron')]); + expect(code).to.equal(0); + expect(out).to.include(nodeOptionsWarning); + }); + }); + + it('is respected when invoked from self', async () => { + await withTempDirectory(async (dir) => { + const appPath = await copyMacOSFixtureApp(dir, null); + await signApp(appPath, identity); + const appExePath = path.join(appPath, 'Contents/MacOS/Electron'); + const { code, out } = await spawn(appExePath, [script, appExePath]); + expect(code).to.equal(1); + expect(out).to.not.include(nodeOptionsWarning); + expect(out).to.include('NODE_OPTIONS passed to child'); + }); + }); + }); + + describe('Node.js cli flags', () => { + let child: childProcess.ChildProcessWithoutNullStreams; + let exitPromise: Promise; + + it('Prohibits crypto-related flags in ELECTRON_RUN_AS_NODE mode', (done) => { + after(async () => { + const [code, signal] = await exitPromise; + expect(signal).to.equal(null); + expect(code).to.equal(9); + child.kill(); + }); + + child = childProcess.spawn(process.execPath, ['--force-fips'], { + env: { ELECTRON_RUN_AS_NODE: 'true' } + }); + exitPromise = once(child, 'exit'); + + let output = ''; + const cleanup = () => { + child.stderr.removeListener('data', listener); + child.stdout.removeListener('data', listener); + }; + + const listener = (data: Buffer) => { + output += data; + if (/.*The Node.js cli flag --force-fips is not supported in Electron/m.test(output)) { + cleanup(); + done(); + } + }; + + child.stderr.on('data', listener); + child.stdout.on('data', listener); + }); + }); + + describe('process.stdout', () => { + it('is a real Node stream', () => { + expect((process.stdout as any)._type).to.not.be.undefined(); + }); + }); + + describe('fs.readFile', () => { + it('can accept a FileHandle as the Path argument', async () => { + const filePathForHandle = path.resolve(mainFixturesPath, 'dogs-running.txt'); + const fileHandle = await fs.promises.open(filePathForHandle, 'r'); + + const file = await fs.promises.readFile(fileHandle, { encoding: 'utf8' }); + expect(file).to.not.be.empty(); + await fileHandle.close(); + }); + }); + + describe('inspector', () => { + let child: childProcess.ChildProcessWithoutNullStreams; + let exitPromise: Promise | null; + + afterEach(async () => { + if (child && exitPromise) { + const [code, signal] = await exitPromise; + expect(signal).to.equal(null); + expect(code).to.equal(0); + } else if (child) { + child.kill(); + } + child = null as any; + exitPromise = null as any; + }); + + it('Supports starting the v8 inspector with --inspect/--inspect-brk', (done) => { + child = childProcess.spawn(process.execPath, ['--inspect-brk', path.join(fixtures, 'module', 'run-as-node.js')], { + env: { ELECTRON_RUN_AS_NODE: 'true' } + }); + + let output = ''; + const cleanup = () => { + child.stderr.removeListener('data', listener); + child.stdout.removeListener('data', listener); + }; + + const listener = (data: Buffer) => { + output += data; + if (/Debugger listening on ws:/m.test(output)) { + cleanup(); + done(); + } + }; + + child.stderr.on('data', listener); + child.stdout.on('data', listener); + }); + + it('Supports starting the v8 inspector with --inspect and a provided port', async () => { + child = childProcess.spawn( + process.execPath, + ['--inspect=17364', path.join(fixtures, 'module', 'run-as-node.js')], + { + env: { ELECTRON_RUN_AS_NODE: 'true' } + } + ); + exitPromise = once(child, 'exit'); + + let output = ''; + const listener = (data: Buffer) => { + output += data; + }; + const cleanup = () => { + child.stderr.removeListener('data', listener); + child.stdout.removeListener('data', listener); + }; + + child.stderr.on('data', listener); + child.stdout.on('data', listener); + await once(child, 'exit'); + cleanup(); + if (/^Debugger listening on ws:/m.test(output)) { + expect(output.trim()).to.contain(':17364', 'should be listening on port 17364'); + } else { + throw new Error(`Unexpected output: ${output.toString()}`); + } + }); + + it('Does not start the v8 inspector when --inspect is after a -- argument', async () => { + child = childProcess.spawn(process.execPath, [path.join(fixtures, 'module', 'noop.js'), '--', '--inspect']); + exitPromise = once(child, 'exit'); + + let output = ''; + const listener = (data: Buffer) => { + output += data; + }; + child.stderr.on('data', listener); + child.stdout.on('data', listener); + await once(child, 'exit'); + if (output.trim().startsWith('Debugger listening on ws://')) { + throw new Error('Inspector was started when it should not have been'); + } + }); + + // IPC Electron child process not supported on Windows. + ifit(process.platform !== 'win32')('does not crash when quitting with the inspector connected', function (done) { + child = childProcess.spawn(process.execPath, [path.join(fixtures, 'module', 'delay-exit'), '--inspect=0'], { + stdio: ['ipc'] + }) as childProcess.ChildProcessWithoutNullStreams; + exitPromise = once(child, 'exit'); + + const cleanup = () => { + child.stderr.removeListener('data', listener); + child.stdout.removeListener('data', listener); + }; + + let output = ''; + const success = false; + function listener(data: Buffer) { + output += data; + console.log(data.toString()); // NOTE: temporary debug logging to try to catch flake. + const match = /^Debugger listening on (ws:\/\/.+:\d+\/.+)\n/m.exec(output.trim()); + if (match) { + cleanup(); + // NOTE: temporary debug logging to try to catch flake. + child.stderr.on('data', (m) => console.log(m.toString())); + child.stdout.on('data', (m) => console.log(m.toString())); + const w = (webContents as typeof ElectronInternal.WebContents).create(); + w.loadURL('about:blank') + .then(() => + w.executeJavaScript(`new Promise(resolve => { + const connection = new WebSocket(${JSON.stringify(match[1])}) + connection.onopen = () => { + connection.onclose = () => resolve() + connection.close() + } + })`) + ) + .then(() => { + w.destroy(); + child.send('plz-quit'); + done(); + }); + } + } + + child.stderr.on('data', listener); + child.stdout.on('data', listener); + child.on('exit', () => { + if (!success) cleanup(); + }); + }); + + it('Supports js binding', async () => { + child = childProcess.spawn( + process.execPath, + ['--inspect', path.join(fixtures, 'module', 'inspector-binding.js')], + { + env: { ELECTRON_RUN_AS_NODE: 'true' }, + stdio: ['ipc'] + } + ) as childProcess.ChildProcessWithoutNullStreams; + exitPromise = once(child, 'exit'); + + const [{ cmd, debuggerEnabled, success }] = await once(child, 'message'); + expect(cmd).to.equal('assert'); + expect(debuggerEnabled).to.be.true(); + expect(success).to.be.true(); + }); + }); + + itremote('handles assert module assertions as expected', () => { + const assert = require('node:assert'); + try { + assert.ok(false); + expect.fail('assert.ok(false) should throw'); + } catch (err) { + console.log(err); + expect(err).to.be.instanceOf(assert.AssertionError); + } + }); + + it('Can find a module using a package.json main field', () => { + const result = childProcess.spawnSync( + process.execPath, + [path.resolve(fixtures, 'api', 'electron-main-module', 'app.asar')], + { stdio: 'inherit' } + ); + expect(result.status).to.equal(0); + }); + + it('handles Promise timeouts correctly', async () => { + const scriptPath = path.join(fixtures, 'module', 'node-promise-timer.js'); + const child = childProcess.spawn(process.execPath, [scriptPath], { + env: { ELECTRON_RUN_AS_NODE: 'true' } + }); + const [code, signal] = await once(child, 'exit'); + expect(code).to.equal(0); + expect(signal).to.equal(null); + child.kill(); + }); + + it('performs microtask checkpoint correctly', (done) => { + let timer: NodeJS.Timeout; + const listener = () => { + done(new Error('catch block is delayed to next tick')); + }; + + const f3 = async () => { + return new Promise((resolve, reject) => { + timer = setTimeout(listener); + reject(new Error('oops')); + }); + }; + + setTimeout(() => { + f3().catch(() => { + clearTimeout(timer); + done(); + }); + }); + }); + + describe('type stripping', () => { + it('strips TypeScript types automatically in the main process', async () => { + const child = childProcess.spawn(process.execPath, [path.join(fixtures, 'type-stripping', 'basic.ts')]); + const [code] = await once(child, 'exit'); + expect(code).to.equal(0); + }); + + it('will not transform TypeScript types without --experimental-transform-types', async () => { + const child = childProcess.spawn( + process.execPath, + [path.join(fixtures, 'type-stripping', 'transform-types-node.ts')], + { + env: { ELECTRON_RUN_AS_NODE: 'true' } + } + ); + const [code] = await once(child, 'exit'); + expect(code).to.not.equal(0); + }); + + it('transforms TypeScript types with --experimental-transform-types', async () => { + const child = childProcess.spawn(process.execPath, [ + '--experimental-transform-types', + path.join(fixtures, 'type-stripping', 'transform-types.ts') + ]); + const [code] = await once(child, 'exit'); + expect(code).to.equal(0); + }); + }); +}); diff --git a/spec/package.json b/spec/package.json index 332c780008a26..7e582b52b63f8 100644 --- a/spec/package.json +++ b/spec/package.json @@ -1,34 +1,54 @@ { - "name": "electron-test", - "productName": "Electron Test", - "main": "static/main.js", + "name": "electron-test-main", + "productName": "Electron Test Main", + "main": "index.js", "version": "0.1.0", "scripts": { - "postinstall": "node ../script/run-if-exists.js node_modules/robotjs node-gyp rebuild" + "node-gyp-install": "node-gyp install" }, "devDependencies": { + "@electron-ci/dialog-helper": "*", + "@electron-ci/echo": "*", + "@electron-ci/external-ab": "*", + "@electron-ci/is-valid-window": "*", + "@electron-ci/osr-gpu": "*", + "@electron-ci/uv-dlopen": "*", + "@electron/fuses": "^1.8.0", + "@electron/packager": "^18.3.2", + "@types/basic-auth": "^1.1.8", + "@types/busboy": "^1.5.4", + "@types/chai": "^4.3.19", + "@types/chai-as-promised": "^7.1.3", + "@types/dirty-chai": "^2.0.5", + "@types/express": "^4.17.13", + "@types/mocha": "^7.0.2", + "@types/send": "^0.14.5", + "@types/sinon": "^9.0.4", + "@types/uuid": "^3.4.6", + "@types/w3c-web-serial": "^1.0.7", + "@types/ws": "^7.2.0", + "abstract-socket": "github:deepak1556/node-abstractsocket#928cc591decd12aff7dad96449da8afc29832c19", "basic-auth": "^2.0.1", + "busboy": "^1.6.0", "chai": "^4.2.0", "chai-as-promised": "^7.1.1", "coffeescript": "^2.4.1", - "dbus-native": "github:jkleinsc/dbus-native#master", + "dbus-native": "github:nornagon/dbus-native#master", "dirty-chai": "^2.0.1", + "express": "^4.20.0", "graceful-fs": "^4.1.15", - "is-valid-window": "0.0.5", "mkdirp": "^0.5.1", - "mocha": "^5.2.0", + "mocha": "^10.0.0", "mocha-junit-reporter": "^1.18.0", "mocha-multi-reporters": "^1.1.7", - "send": "^0.16.2", - "split": "^1.0.1", - "temp": "^0.9.0", + "pdfjs-dist": "4.2.67", + "ps-list": "^7.0.0", + "q": "^1.5.1", + "send": "^0.19.0", + "sinon": "^9.0.1", "uuid": "^3.3.3", - "walkdir": "^0.3.2", - "winreg": "^1.2.4", - "ws": "^6.1.4", + "winreg": "1.2.4", + "ws": "^7.5.10", "yargs": "^16.0.3" - }, - "dependencies": { - "mocha-appveyor-reporter": "^0.4.2" } } diff --git a/spec/parse-features-string-spec.ts b/spec/parse-features-string-spec.ts new file mode 100644 index 0000000000000..25a9490f7eefb --- /dev/null +++ b/spec/parse-features-string-spec.ts @@ -0,0 +1,66 @@ +import { expect } from 'chai'; + +import { parseCommaSeparatedKeyValue, parseFeatures } from '../lib/browser/parse-features-string'; + +describe('feature-string parsing', () => { + it('is indifferent to whitespace around keys and values', () => { + const checkParse = (string: string, parsed: Record) => { + const features = parseCommaSeparatedKeyValue(string); + expect(features).to.deep.equal(parsed); + }; + checkParse('a=yes,c=d', { a: true, c: 'd' }); + checkParse('a=yes ,c=d', { a: true, c: 'd' }); + checkParse('a=yes, c=d', { a: true, c: 'd' }); + checkParse('a=yes , c=d', { a: true, c: 'd' }); + checkParse(' a=yes , c=d', { a: true, c: 'd' }); + checkParse(' a= yes , c=d', { a: true, c: 'd' }); + checkParse(' a = yes , c=d', { a: true, c: 'd' }); + checkParse(' a = yes , c =d', { a: true, c: 'd' }); + checkParse(' a = yes , c = d', { a: true, c: 'd' }); + checkParse(' a = yes , c = d ', { a: true, c: 'd' }); + }); + + describe('parseFeatures allowlist', () => { + it('passes through allowlisted presentational options', () => { + const { options } = parseFeatures( + 'width=400,height=300,show=no,frame=no,title=hi,backgroundColor=#fff,left=10,top=20' + ); + expect(options).to.deep.equal({ + width: 400, + height: 300, + show: false, + frame: false, + title: 'hi', + backgroundColor: '#fff', + left: 10, + top: 20, + x: 10, + y: 20 + }); + }); + + it('drops non-allowlisted options that would be unsafe to pass to BrowserWindow', () => { + const { options } = parseFeatures('icon=/etc/passwd,width=400'); + expect(options).to.deep.equal({ width: 400 }); + expect(options).to.not.have.property('icon'); + }); + + it('drops non-allowlisted options even when paired with UNC paths', () => { + const { options } = parseFeatures('icon=\\\\attacker.example\\share\\x.png,show=no'); + expect(options).to.deep.equal({ show: false }); + expect(options).to.not.have.property('icon'); + }); + + it('drops unknown options', () => { + const { options } = parseFeatures('something-unknown=foo,width=400'); + expect(options).to.deep.equal({ width: 400 }); + expect(options).to.not.have.property('something-unknown'); + }); + + it('still extracts allowlisted webPreferences', () => { + const { options, webPreferences } = parseFeatures('icon=/etc/passwd,nodeIntegration=no,width=400'); + expect(options).to.deep.equal({ width: 400 }); + expect(webPreferences).to.deep.equal({ nodeIntegration: false }); + }); + }); +}); diff --git a/spec/pipe-transport.ts b/spec/pipe-transport.ts new file mode 100644 index 0000000000000..2384a09f20e44 --- /dev/null +++ b/spec/pipe-transport.ts @@ -0,0 +1,41 @@ +// A small pipe transport for talking to Electron over CDP. +export class PipeTransport { + private _pipeWrite: NodeJS.WritableStream | null; + private _pendingMessage = ''; + + onmessage?: (message: string) => void; + + constructor(pipeWrite: NodeJS.WritableStream, pipeRead: NodeJS.ReadableStream) { + this._pipeWrite = pipeWrite; + pipeRead.on('data', (buffer) => this._dispatch(buffer)); + } + + send(message: Object) { + this._pipeWrite!.write(JSON.stringify(message)); + this._pipeWrite!.write('\0'); + } + + _dispatch(buffer: Buffer) { + let end = buffer.indexOf('\0'); + if (end === -1) { + this._pendingMessage += buffer.toString(); + return; + } + const message = this._pendingMessage + buffer.toString(undefined, 0, end); + if (this.onmessage) { + this.onmessage.call(null, JSON.parse(message)); + } + + let start = end + 1; + end = buffer.indexOf('\0', start); + while (end !== -1) { + const message = buffer.toString(undefined, start, end); + if (this.onmessage) { + this.onmessage.call(null, JSON.parse(message)); + } + start = end + 1; + end = buffer.indexOf('\0', start); + } + this._pendingMessage = buffer.toString(undefined, start); + } +} diff --git a/spec/process-binding-spec.ts b/spec/process-binding-spec.ts new file mode 100644 index 0000000000000..a2de8c9edf4e5 --- /dev/null +++ b/spec/process-binding-spec.ts @@ -0,0 +1,47 @@ +import { BrowserWindow } from 'electron/main'; + +import { expect } from 'chai'; + +import { closeAllWindows } from './lib/window-helpers'; + +describe('process._linkedBinding', () => { + describe('in the main process', () => { + it('can access electron_browser bindings', () => { + process._linkedBinding('electron_browser_app'); + }); + + it('can access electron_common bindings', () => { + process._linkedBinding('electron_common_v8_util'); + }); + + it('cannot access electron_renderer bindings', () => { + expect(() => { + process._linkedBinding('electron_renderer_ipc'); + }).to.throw(/No such binding was linked: electron_renderer_ipc/); + }); + }); + + describe('in the renderer process', () => { + afterEach(closeAllWindows); + + it('cannot access electron_browser bindings', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL('about:blank'); + await expect( + w.webContents.executeJavaScript("void process._linkedBinding('electron_browser_app')") + ).to.eventually.be.rejectedWith(/Script failed to execute/); + }); + + it('can access electron_common bindings', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL('about:blank'); + await w.webContents.executeJavaScript("void process._linkedBinding('electron_common_v8_util')"); + }); + + it('can access electron_renderer bindings', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL('about:blank'); + await w.webContents.executeJavaScript("void process._linkedBinding('electron_renderer_ipc')"); + }); + }); +}); diff --git a/spec/release-notes-spec.ts b/spec/release-notes-spec.ts new file mode 100644 index 0000000000000..8b4063247f95e --- /dev/null +++ b/spec/release-notes-spec.ts @@ -0,0 +1,301 @@ +import { expect } from 'chai'; +import * as sinon from 'sinon'; + +import { SpawnSyncReturns } from 'node:child_process'; +import * as path from 'node:path'; + +import * as notes from '../script/release/notes/notes'; + +/* Fake a git spawnSync that only returns the specific + commits that we want to test */ + +class Commit { + sha1: string; + subject: string; + constructor(sha1: string, subject: string) { + this.sha1 = sha1; + this.subject = subject; + } +} + +class GitFake { + branches: { + [key: string]: Commit[]; + }; + + constructor() { + this.branches = {}; + } + + setBranch(name: string, commits: Array): void { + this.branches[name] = commits; + } + + // find the newest shared commit between branches a and b + mergeBase(a: string, b: string): string { + for (const commit of [...this.branches[a].reverse()]) { + if (this.branches[b].map((commit: Commit) => commit.sha1).includes(commit.sha1)) { + return commit.sha1; + } + } + console.error('test error: branches not related'); + return ''; + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + exec(command: string, args: string[], options?: any): SpawnSyncReturns { + let stdout = ''; + const stderr = ''; + const status = 0; + + if (args.length === 3 && args[0] === 'merge-base') { + // expected form: `git merge-base branchName1 branchName2` + const a: string = args[1]!; + const b: string = args[2]!; + stdout = this.mergeBase(a, b); + } else if (args.length === 3 && args[0] === 'log' && args[1] === '--format=%H') { + // expected form: `git log --format=%H branchName + const branch: string = args[2]!; + stdout = this.branches[branch].map((commit: Commit) => commit.sha1).join('\n'); + } else if (args.length > 1 && args[0] === 'log' && args.includes('--format=%H,%s')) { + // expected form: `git log --format=%H,%s sha1..branchName + const [start, branch] = args[args.length - 1].split('..'); + const lines: string[] = []; + let started = false; + for (const commit of this.branches[branch]) { + started = started || commit.sha1 === start; + if (started) { + lines.push(`${commit.sha1},${commit.subject}` /* %H,%s */); + } + } + stdout = lines.join('\n'); + } else if ( + args.length === 6 && + args[0] === 'branch' && + args[1] === '--all' && + args[2] === '--contains' && + args[3].endsWith('-x-y') + ) { + // "what branch is this tag in?" + // git branch --all --contains ${ref} --sort version:refname + stdout = args[3]; + } else { + console.error('unhandled git spawnSync():', args); + } + + return { status, stdout, stderr, pid: 0, output: [null, stdout, stderr], signal: null }; + } +} + +describe('release notes', () => { + const sandbox = sinon.createSandbox(); + const gitFake = new GitFake(); + + const oldBranch = '8-x-y'; + const newBranch = '9-x-y'; + + // commits shared by both oldBranch and newBranch + const sharedHistory = [ + new Commit( + '2abea22b4bffa1626a521711bacec7cd51425818', + "fix: explicitly cancel redirects when mode is 'error' (#20686)" + ), + new Commit('467409458e716c68b35fa935d556050ca6bed1c4', 'build: add support for automated minor releases (#20620)') // merge-base + ]; + + // these commits came after newBranch was created + const newBreaking = new Commit( + '2fad53e66b1a2cb6f7dad88fe9bb62d7a461fe98', + 'refactor: use v8 serialization for ipc (#20214)' + ); + const newFeat = new Commit( + '89eb309d0b22bd4aec058ffaf983e81e56a5c378', + 'feat: allow GUID parameter to avoid systray demotion on Windows (#21891)' + ); + const newFix = new Commit( + '0600420bac25439fc2067d51c6aaa4ee11770577', + "fix: don't allow window to go behind menu bar on mac (#22828)" + ); + const oldFix = new Commit('f77bd19a70ac2d708d17ddbe4dc12745ca3a8577', 'fix: prevent menu gc during popup (#20785)'); + + // a bug that's fixed in both branches by separate PRs + const newTropFix = new Commit( + 'a6ff42c190cb5caf8f3e217748e49183a951491b', + 'fix: workaround for hang when preventDefault-ing nativeWindowOpen (#22750)' + ); + const oldTropFix = new Commit( + '8751f485c5a6c8c78990bfd55a4350700f81f8cd', + 'fix: workaround for hang when preventDefault-ing nativeWindowOpen (#22749)' + ); + + // a PR that has unusual note formatting + const sublist = new Commit( + '61dc1c88fd34a3e8fff80c80ed79d0455970e610', + 'fix: client area inset calculation when maximized for frameless windows (#25052) (#25216)' + ); + + before(() => { + // location of release-notes' octokit reply cache + const fixtureDir = path.resolve(__dirname, 'fixtures', 'release-notes'); + process.env.NOTES_CACHE_PATH = path.resolve(fixtureDir, 'cache'); + }); + + beforeEach(() => { + const wrapper = (command: unknown, args: unknown, options?: unknown) => { + if (command === 'git' && Array.isArray(args)) { + return gitFake.exec(command as string, args as string[], options); + } + // Default behavior for non-git commands + return { status: 0, stdout: '', stderr: '', pid: 0, output: [null, '', ''], signal: null }; + }; + sandbox.stub(require('node:child_process'), 'spawnSync').callsFake(wrapper); + + gitFake.setBranch(oldBranch, [...sharedHistory, oldFix]); + }); + + afterEach(() => { + sandbox.restore(); + }); + + describe('trop annotations', () => { + it('shows sibling branches', async function () { + const version = 'v9.0.0'; + gitFake.setBranch(oldBranch, [...sharedHistory, oldTropFix]); + gitFake.setBranch(newBranch, [...sharedHistory, newTropFix]); + const results: any = await notes.get(oldBranch, newBranch, version); + expect(results.fix).to.have.lengthOf(1); + console.log(results.fix); + expect(results.fix[0].trops).to.have.keys('8-x-y', '9-x-y'); + }); + }); + + // use case: A malicious contributor could edit the text of their 'Notes:' + // in the PR body after a PR's been merged and the maintainers have moved on. + // So instead always use the release-clerk PR comment + it('uses the release-clerk text', async function () { + // realText source: ${fixtureDir}/electron-electron-issue-21891-comments + const realText = 'Added GUID parameter to Tray API to avoid system tray icon demotion on Windows'; + const testCommit = new Commit('89eb309d0b22bd4aec058ffaf983e81e56a5c378', 'feat: lole u got troled hard (#21891)'); + const version = 'v9.0.0'; + + gitFake.setBranch(newBranch, [...sharedHistory, testCommit]); + const results: any = await notes.get(oldBranch, newBranch, version); + expect(results.feat).to.have.lengthOf(1); + expect(results.feat[0].hash).to.equal(testCommit.sha1); + expect(results.feat[0].note).to.equal(realText); + }); + + describe('rendering', () => { + it('removes redundant bullet points', async function () { + const testCommit = sublist; + const version = 'v10.1.1'; + + gitFake.setBranch(newBranch, [...sharedHistory, testCommit]); + const results: any = await notes.get(oldBranch, newBranch, version); + const rendered: any = await notes.render(results); + + expect(rendered).to.not.include('* *'); + }); + + it('indents sublists', async function () { + const testCommit = sublist; + const version = 'v10.1.1'; + + gitFake.setBranch(newBranch, [...sharedHistory, testCommit]); + const results: any = await notes.get(oldBranch, newBranch, version); + const rendered: any = await notes.render(results); + + expect(rendered).to.include( + [ + '* Fixed the following issues for frameless when maximized on Windows:', + ' * fix unreachable task bar when auto hidden with position top', + ' * fix 1px extending to secondary monitor', + ' * fix 1px overflowing into taskbar at certain resolutions', + ' * fix white line on top of window under 4k resolutions. [#25216]' + ].join('\n') + ); + }); + }); + // test that when you feed in different semantic commit types, + // the parser returns them in the results' correct category + describe('semantic commit', () => { + const version = 'v9.0.0'; + + it("honors 'feat' type", async function () { + const testCommit = newFeat; + gitFake.setBranch(newBranch, [...sharedHistory, testCommit]); + const results: any = await notes.get(oldBranch, newBranch, version); + expect(results.feat).to.have.lengthOf(1); + expect(results.feat[0].hash).to.equal(testCommit.sha1); + }); + + it("honors 'fix' type", async function () { + const testCommit = newFix; + gitFake.setBranch(newBranch, [...sharedHistory, testCommit]); + const results: any = await notes.get(oldBranch, newBranch, version); + expect(results.fix).to.have.lengthOf(1); + expect(results.fix[0].hash).to.equal(testCommit.sha1); + }); + + it("honors 'BREAKING CHANGE' message", async function () { + const testCommit = newBreaking; + gitFake.setBranch(newBranch, [...sharedHistory, testCommit]); + const results: any = await notes.get(oldBranch, newBranch, version); + expect(results.breaking).to.have.lengthOf(1); + expect(results.breaking[0].hash).to.equal(testCommit.sha1); + }); + }); + // test that when you have multiple stack updates only the + // latest will be kept + describe('superseding stack updates', () => { + const oldBranch = '27-x-y'; + const newBranch = '28-x-y'; + + const version = 'v28.0.0'; + + it('with different major versions', async function () { + const mostRecentCommit = new Commit( + '9d0e6d09f0be0abbeae46dd3d66afd96d2daacaa', + 'chore: bump chromium to 119.0.6043.0' + ); + + const sharedChromiumHistory = [ + new Commit('029127a8b6f7c511fca4612748ad5b50e43aadaa', 'chore: bump chromium to 118.0.5993.0') // merge-base + ]; + const chromiumPatchUpdates = [ + new Commit('d9ba26273ad3e7a34c905eccbd5dabda4eb7b402', 'chore: bump chromium to 118.0.5991.0'), + mostRecentCommit, + new Commit('d6c8ff2e7050f30dffd784915bcbd2a9f993cdb2', 'chore: bump chromium to 119.0.6029.0') + ]; + + gitFake.setBranch(oldBranch, sharedChromiumHistory); + gitFake.setBranch(newBranch, [...sharedChromiumHistory, ...chromiumPatchUpdates]); + + const results: any = await notes.get(oldBranch, newBranch, version); + expect(results.other).to.have.lengthOf(1); + expect(results.other[0].hash).to.equal(mostRecentCommit.sha1); + }); + it('with different build versions', async function () { + const mostRecentCommit = new Commit( + '8f7a48879ef8633a76279803637cdee7f7c6cd4f', + 'chore: bump chromium to 119.0.6045.0' + ); + + const sharedChromiumHistory = [ + new Commit('029127a8b6f7c511fca4612748ad5b50e43aadaa', 'chore: bump chromium to 118.0.5993.0') // merge-base + ]; + const chromiumPatchUpdates = [ + mostRecentCommit, + new Commit('9d0e6d09f0be0abbeae46dd3d66afd96d2daacaa', 'chore: bump chromium to 119.0.6043.0'), + new Commit('d6c8ff2e7050f30dffd784915bcbd2a9f993cdb2', 'chore: bump chromium to 119.0.6029.0') + ]; + + gitFake.setBranch(oldBranch, sharedChromiumHistory); + gitFake.setBranch(newBranch, [...sharedChromiumHistory, ...chromiumPatchUpdates]); + + const results: any = await notes.get(oldBranch, newBranch, version); + expect(results.other).to.have.lengthOf(1); + expect(results.other[0].hash).to.equal(mostRecentCommit.sha1); + }); + }); +}); diff --git a/spec/security-warnings-spec.ts b/spec/security-warnings-spec.ts new file mode 100644 index 0000000000000..ff074f0a25dc8 --- /dev/null +++ b/spec/security-warnings-spec.ts @@ -0,0 +1,216 @@ +import { BrowserWindow, WebPreferences } from 'electron/main'; + +import { expect } from 'chai'; + +import * as fs from 'node:fs/promises'; +import * as http from 'node:http'; +import * as path from 'node:path'; +import { setTimeout } from 'node:timers/promises'; + +import { emittedUntil } from './lib/events-helpers'; +import { listen } from './lib/spec-helpers'; +import { closeWindow } from './lib/window-helpers'; + +const messageContainsSecurityWarning = (event: Event, level: number, message: string) => { + return message.includes('Electron Security Warning'); +}; + +const isLoaded = (event: Event, level: number, message: string) => { + return message === 'loaded'; +}; + +describe('security warnings', () => { + let server: http.Server; + let w: BrowserWindow; + let useCsp = true; + let serverUrl: string; + + before(async () => { + // Create HTTP Server + server = http.createServer(async (request, response) => { + const uri = new URL(request.url!, `http://${request.headers.host}`).pathname!; + let filename = path.join(__dirname, 'fixtures', 'pages', uri); + + try { + const stats = await fs.stat(filename); + if (stats.isDirectory()) { + filename += '/index.html'; + } + + const file = await fs.readFile(filename, 'binary'); + const cspHeaders = [...(useCsp ? ["script-src 'self' 'unsafe-inline'"] : [])]; + response.writeHead(200, { 'Content-Security-Policy': cspHeaders }); + response.write(file, 'binary'); + } catch { + response.writeHead(404, { 'Content-Type': 'text/plain' }); + } + + response.end(); + }); + + serverUrl = `http://localhost2:${(await listen(server)).port}`; + }); + + after(() => { + // Close server + server.close(); + server = null as unknown as any; + }); + + afterEach(async () => { + useCsp = true; + await closeWindow(w); + w = null as unknown as any; + }); + + it('should warn about Node.js integration with remote content', async () => { + w = new BrowserWindow({ + show: false, + webPreferences: { + nodeIntegration: true, + contextIsolation: false + } + }); + + w.loadURL(`${serverUrl}/base-page-security.html`); + const [{ message }] = await emittedUntil(w.webContents, 'console-message', messageContainsSecurityWarning); + expect(message).to.include('Node.js Integration with Remote Content'); + }); + + it('should not warn about Node.js integration with remote content from localhost', async () => { + w = new BrowserWindow({ + show: false, + webPreferences: { + nodeIntegration: true + } + }); + + w.loadURL(`${serverUrl}/base-page-security-onload-message.html`); + const [{ message }] = await emittedUntil(w.webContents, 'console-message', isLoaded); + expect(message).to.not.include('Node.js Integration with Remote Content'); + }); + + const generateSpecs = (description: string, webPreferences: WebPreferences) => { + describe(description, () => { + it('should warn about disabled webSecurity', async () => { + w = new BrowserWindow({ + show: false, + webPreferences: { + webSecurity: false, + ...webPreferences + } + }); + + w.loadURL(`${serverUrl}/base-page-security.html`); + const [{ message }] = await emittedUntil(w.webContents, 'console-message', messageContainsSecurityWarning); + expect(message).to.include('Disabled webSecurity'); + }); + + it('should warn about insecure Content-Security-Policy', async () => { + w = new BrowserWindow({ + show: false, + webPreferences + }); + + useCsp = false; + w.loadURL(`${serverUrl}/base-page-security.html`); + const [{ message }] = await emittedUntil(w.webContents, 'console-message', messageContainsSecurityWarning); + expect(message).to.include('Insecure Content-Security-Policy'); + }); + + it('should not warn about secure Content-Security-Policy', async () => { + w = new BrowserWindow({ + show: false, + webPreferences + }); + + useCsp = true; + w.loadURL(`${serverUrl}/base-page-security.html`); + let didNotWarn = true; + w.webContents.on('console-message', () => { + didNotWarn = false; + }); + await setTimeout(500); + expect(didNotWarn).to.equal(true); + }); + + it('should warn about allowRunningInsecureContent', async () => { + w = new BrowserWindow({ + show: false, + webPreferences: { + allowRunningInsecureContent: true, + ...webPreferences + } + }); + + w.loadURL(`${serverUrl}/base-page-security.html`); + const [{ message }] = await emittedUntil(w.webContents, 'console-message', messageContainsSecurityWarning); + expect(message).to.include('allowRunningInsecureContent'); + }); + + it('should warn about experimentalFeatures', async () => { + w = new BrowserWindow({ + show: false, + webPreferences: { + experimentalFeatures: true, + ...webPreferences + } + }); + + w.loadURL(`${serverUrl}/base-page-security.html`); + const [{ message }] = await emittedUntil(w.webContents, 'console-message', messageContainsSecurityWarning); + expect(message).to.include('experimentalFeatures'); + }); + + it('should warn about enableBlinkFeatures', async () => { + w = new BrowserWindow({ + show: false, + webPreferences: { + enableBlinkFeatures: 'my-cool-feature', + ...webPreferences + } + }); + + w.loadURL(`${serverUrl}/base-page-security.html`); + const [{ message }] = await emittedUntil(w.webContents, 'console-message', messageContainsSecurityWarning); + expect(message).to.include('enableBlinkFeatures'); + }); + + it('should warn about allowpopups', async () => { + w = new BrowserWindow({ + show: false, + webPreferences + }); + + w.loadURL(`${serverUrl}/webview-allowpopups.html`); + const [{ message }] = await emittedUntil(w.webContents, 'console-message', messageContainsSecurityWarning); + expect(message).to.include('allowpopups'); + }); + + it('should warn about insecure resources', async () => { + w = new BrowserWindow({ + show: false, + webPreferences + }); + + w.loadURL(`${serverUrl}/insecure-resources.html`); + const [{ message }] = await emittedUntil(w.webContents, 'console-message', messageContainsSecurityWarning); + expect(message).to.include('Insecure Resources'); + }); + + it('should not warn about loading insecure-resources.html from localhost', async () => { + w = new BrowserWindow({ + show: false, + webPreferences + }); + + w.loadURL(`${serverUrl}/insecure-resources.html`); + const [{ message }] = await emittedUntil(w.webContents, 'console-message', messageContainsSecurityWarning); + expect(message).to.not.include('insecure-resources.html'); + }); + }); + }; + + generateSpecs('without sandbox', { contextIsolation: false }); + generateSpecs('with sandbox', { sandbox: true, contextIsolation: false }); +}); diff --git a/spec/spec-helpers.js b/spec/spec-helpers.js deleted file mode 100644 index 893049a095a52..0000000000000 --- a/spec/spec-helpers.js +++ /dev/null @@ -1,4 +0,0 @@ -exports.ifit = (condition) => (condition ? it : it.skip); -exports.ifdescribe = (condition) => (condition ? describe : describe.skip); - -exports.delay = (time = 0) => new Promise(resolve => setTimeout(resolve, time)); diff --git a/spec/spellchecker-spec.ts b/spec/spellchecker-spec.ts new file mode 100644 index 0000000000000..8aaad0b271246 --- /dev/null +++ b/spec/spellchecker-spec.ts @@ -0,0 +1,287 @@ +import { BrowserWindow, Session, session } from 'electron/main'; + +import { expect } from 'chai'; + +import { once } from 'node:events'; +import * as fs from 'node:fs/promises'; +import * as http from 'node:http'; +import * as path from 'node:path'; +import { setTimeout } from 'node:timers/promises'; + +import { ifit, ifdescribe, listen } from './lib/spec-helpers'; +import { closeWindow } from './lib/window-helpers'; + +const features = process._linkedBinding('electron_common_features'); +const v8Util = process._linkedBinding('electron_common_v8_util'); + +ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', function () { + this.timeout((process.env.IS_ASAN ? 200 : 20) * 1000); + + let w: BrowserWindow; + + async function rightClick() { + const contextMenuPromise = once(w.webContents, 'context-menu'); + w.webContents.sendInputEvent({ + type: 'mouseDown', + button: 'right', + x: 43, + y: 42 + }); + return (await contextMenuPromise)[1] as Electron.ContextMenuParams; + } + + // When the page is just loaded, the spellchecker might not be ready yet. Since + // there is no event to know the state of spellchecker, the only reliable way + // to detect spellchecker is to keep checking with a busy loop. + async function rightClickUntil(fn: (params: Electron.ContextMenuParams) => boolean) { + const now = Date.now(); + const timeout = (process.env.IS_ASAN ? 180 : 10) * 1000; + let contextMenuParams = await rightClick(); + while (!fn(contextMenuParams) && Date.now() - now < timeout) { + await setTimeout(100); + contextMenuParams = await rightClick(); + } + return contextMenuParams; + } + + // Setup a server to download hunspell dictionary. + const server = http.createServer(async (req, res) => { + // The provided is minimal dict for testing only, full list of words can + // be found at src/third_party/hunspell_dictionaries/xx_XX.dic. + try { + const data = await fs.readFile(path.join(__dirname, '/../../third_party/hunspell_dictionaries/xx-XX-3-0.bdic')); + res.writeHead(200); + res.end(data); + } catch (err) { + console.error('Failed to read dictionary file'); + res.writeHead(404); + res.end(JSON.stringify(err)); + } + }); + let serverUrl: string; + before(async () => { + serverUrl = (await listen(server)).url; + }); + after(() => server.close()); + + const fixtures = path.resolve(__dirname, 'fixtures'); + const preload = path.join(fixtures, 'module', 'preload-electron.js'); + + const generateSpecs = (description: string, sandbox: boolean) => { + describe(description, () => { + beforeEach(async () => { + w = new BrowserWindow({ + show: false, + webPreferences: { + partition: `unique-spell-${Date.now()}`, + contextIsolation: false, + preload, + sandbox + } + }); + w.webContents.session.setSpellCheckerDictionaryDownloadURL(serverUrl); + w.webContents.session.setSpellCheckerLanguages(['en-US']); + await w.loadFile(path.resolve(__dirname, './fixtures/chromium/spellchecker.html')); + }); + + afterEach(async () => { + await closeWindow(w); + }); + + // Context menu test can not run on Windows or Linux (https://github.com/electron/electron/pull/48657 broke linux). + const shouldRun = process.platform !== 'win32' && process.platform !== 'linux'; + + ifit(shouldRun)('should detect correctly spelled words as correct', async () => { + await w.webContents.executeJavaScript('document.body.querySelector("textarea").value = "typography"'); + await w.webContents.executeJavaScript('document.body.querySelector("textarea").focus()'); + const contextMenuParams = await rightClickUntil( + (contextMenuParams) => contextMenuParams.selectionText.length > 0 + ); + expect(contextMenuParams.misspelledWord).to.eq(''); + expect(contextMenuParams.dictionarySuggestions).to.have.lengthOf(0); + }); + + ifit(shouldRun)('should detect incorrectly spelled words as incorrect', async () => { + await w.webContents.executeJavaScript('document.body.querySelector("textarea").value = "typograpy"'); + await w.webContents.executeJavaScript('document.body.querySelector("textarea").focus()'); + const contextMenuParams = await rightClickUntil( + (contextMenuParams) => contextMenuParams.misspelledWord.length > 0 + ); + expect(contextMenuParams.misspelledWord).to.eq('typograpy'); + expect(contextMenuParams.dictionarySuggestions).to.have.length.of.at.least(1); + }); + + ifit(shouldRun)( + 'should detect incorrectly spelled words as incorrect after disabling all languages and re-enabling', + async () => { + w.webContents.session.setSpellCheckerLanguages([]); + await setTimeout(500); + w.webContents.session.setSpellCheckerLanguages(['en-US']); + await w.webContents.executeJavaScript('document.body.querySelector("textarea").value = "typograpy"'); + await w.webContents.executeJavaScript('document.body.querySelector("textarea").focus()'); + const contextMenuParams = await rightClickUntil( + (contextMenuParams) => contextMenuParams.misspelledWord.length > 0 + ); + expect(contextMenuParams.misspelledWord).to.eq('typograpy'); + expect(contextMenuParams.dictionarySuggestions).to.have.length.of.at.least(1); + } + ); + + ifit(shouldRun)('should expose webFrame spellchecker correctly', async () => { + await w.webContents.executeJavaScript('document.body.querySelector("textarea").value = "typograpy"'); + await w.webContents.executeJavaScript('document.body.querySelector("textarea").focus()'); + await rightClickUntil((contextMenuParams) => contextMenuParams.misspelledWord.length > 0); + + const callWebFrameFn = (expr: string) => w.webContents.executeJavaScript(`electron.webFrame.${expr}`); + + expect(await callWebFrameFn('isWordMisspelled("typography")')).to.equal(false); + expect(await callWebFrameFn('isWordMisspelled("typograpy")')).to.equal(true); + expect(await callWebFrameFn('getWordSuggestions("typography")')).to.be.empty(); + expect(await callWebFrameFn('getWordSuggestions("typograpy")')).to.not.be.empty(); + }); + + describe('spellCheckerEnabled', () => { + it('is enabled by default', async () => { + expect(w.webContents.session.spellCheckerEnabled).to.be.true(); + }); + + ifit(shouldRun)('can be dynamically changed', async () => { + await w.webContents.executeJavaScript('document.body.querySelector("textarea").value = "typograpy"'); + await w.webContents.executeJavaScript('document.body.querySelector("textarea").focus()'); + await rightClickUntil((contextMenuParams) => contextMenuParams.misspelledWord.length > 0); + + const callWebFrameFn = (expr: string) => w.webContents.executeJavaScript(`electron.webFrame.${expr}`); + + w.webContents.session.spellCheckerEnabled = false; + v8Util.runUntilIdle(); + expect(w.webContents.session.spellCheckerEnabled).to.be.false(); + // spellCheckerEnabled is sent to renderer asynchronously and there is + // no event notifying when it is finished, so wait a little while to + // ensure the setting has been changed in renderer. + await setTimeout(500); + expect(await callWebFrameFn('isWordMisspelled("typograpy")')).to.equal(false); + + w.webContents.session.spellCheckerEnabled = true; + v8Util.runUntilIdle(); + expect(w.webContents.session.spellCheckerEnabled).to.be.true(); + await setTimeout(500); + expect(await callWebFrameFn('isWordMisspelled("typograpy")')).to.equal(true); + }); + }); + + describe('custom dictionary word list API', () => { + let ses: Session; + + beforeEach(async () => { + // ensure a new session runs on each test run + ses = session.fromPartition(`persist:customdictionary-test-${Date.now()}`); + }); + + afterEach(async () => { + if (ses) { + await ses.clearStorageData(); + ses = null as any; + } + }); + + describe('ses.listWordsFromSpellCheckerDictionary', () => { + it('should successfully list words in custom dictionary', async () => { + const words = ['foo', 'bar', 'baz']; + const results = words.map((word) => ses.addWordToSpellCheckerDictionary(word)); + expect(results).to.eql([true, true, true]); + + const wordList = await ses.listWordsInSpellCheckerDictionary(); + expect(wordList).to.have.deep.members(words); + }); + + it('should return an empty array if no words are added', async () => { + const wordList = await ses.listWordsInSpellCheckerDictionary(); + expect(wordList).to.have.length(0); + }); + }); + + describe('ses.addWordToSpellCheckerDictionary', () => { + it('should successfully add word to custom dictionary', async () => { + const result = ses.addWordToSpellCheckerDictionary('foobar'); + expect(result).to.equal(true); + const wordList = await ses.listWordsInSpellCheckerDictionary(); + expect(wordList).to.eql(['foobar']); + }); + + it('should fail for an empty string', async () => { + const result = ses.addWordToSpellCheckerDictionary(''); + expect(result).to.equal(false); + const wordList = await ses.listWordsInSpellCheckerDictionary; + expect(wordList).to.have.length(0); + }); + + // remove API will always return false because we can't add words + it('should fail for non-persistent sessions', async () => { + const tempSes = session.fromPartition('temporary'); + const result = tempSes.addWordToSpellCheckerDictionary('foobar'); + expect(result).to.equal(false); + }); + }); + + describe('ses.setSpellCheckerLanguages', () => { + const isMac = process.platform === 'darwin'; + + ifit(isMac)('should be a no-op when setSpellCheckerLanguages is called on macOS', () => { + expect(() => { + w.webContents.session.setSpellCheckerLanguages(['i-am-a-nonexistent-language']); + }).to.not.throw(); + }); + + ifit(!isMac)('should throw when a bad language is passed', () => { + expect(() => { + w.webContents.session.setSpellCheckerLanguages(['i-am-a-nonexistent-language']); + }).to.throw(/Invalid language code provided: "i-am-a-nonexistent-language" is not a valid language code/); + }); + + ifit(!isMac)('should not throw when a recognized language is passed', () => { + expect(() => { + w.webContents.session.setSpellCheckerLanguages(['es']); + }).to.not.throw(); + }); + }); + + describe('SetSpellCheckerDictionaryDownloadURL', () => { + const isMac = process.platform === 'darwin'; + + ifit(isMac)('should be a no-op when a bad url is passed on macOS', () => { + expect(() => { + w.webContents.session.setSpellCheckerDictionaryDownloadURL('i-am-not-a-valid-url'); + }).to.not.throw(); + }); + + ifit(!isMac)('should throw when a bad url is passed', () => { + expect(() => { + w.webContents.session.setSpellCheckerDictionaryDownloadURL('i-am-not-a-valid-url'); + }).to.throw(/The URL you provided to setSpellCheckerDictionaryDownloadURL is not a valid URL/); + }); + }); + + describe('ses.removeWordFromSpellCheckerDictionary', () => { + it('should successfully remove words to custom dictionary', async () => { + const result1 = ses.addWordToSpellCheckerDictionary('foobar'); + expect(result1).to.equal(true); + const wordList1 = await ses.listWordsInSpellCheckerDictionary(); + expect(wordList1).to.eql(['foobar']); + const result2 = ses.removeWordFromSpellCheckerDictionary('foobar'); + expect(result2).to.equal(true); + const wordList2 = await ses.listWordsInSpellCheckerDictionary(); + expect(wordList2).to.have.length(0); + }); + + it('should fail for words not in custom dictionary', () => { + const result2 = ses.removeWordFromSpellCheckerDictionary('foobar'); + expect(result2).to.equal(false); + }); + }); + }); + }); + }; + + generateSpecs('without sandbox', false); + generateSpecs('with sandbox', true); +}); diff --git a/spec/static/get-files.js b/spec/static/get-files.js deleted file mode 100644 index 9857d9742e89d..0000000000000 --- a/spec/static/get-files.js +++ /dev/null @@ -1,15 +0,0 @@ -async function getFiles (directoryPath, { filter = null } = {}) { - const files = []; - const walker = require('walkdir').walk(directoryPath, { - no_recurse: true - }); - walker.on('file', (file) => { - if (!filter || filter(file)) { - files.push(file); - } - }); - await new Promise((resolve) => walker.on('end', resolve)); - return files; -} - -module.exports = getFiles; diff --git a/spec/static/index.html b/spec/static/index.html deleted file mode 100644 index 9497bbcf8b20e..0000000000000 --- a/spec/static/index.html +++ /dev/null @@ -1,102 +0,0 @@ - - - - diff --git a/spec/static/jquery-2.0.3.min.js b/spec/static/jquery-2.0.3.min.js deleted file mode 100644 index 2be209dd2233e..0000000000000 --- a/spec/static/jquery-2.0.3.min.js +++ /dev/null @@ -1,6 +0,0 @@ -/*! jQuery v2.0.3 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license -//@ sourceMappingURL=jquery-2.0.3.min.map -*/ -(function(e,undefined){var t,n,r=typeof undefined,i=e.location,o=e.document,s=o.documentElement,a=e.jQuery,u=e.$,l={},c=[],p="2.0.3",f=c.concat,h=c.push,d=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=p.trim,x=function(e,n){return new x.fn.init(e,n,t)},b=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^-ms-/,N=/-([\da-z])/gi,E=function(e,t){return t.toUpperCase()},S=function(){o.removeEventListener("DOMContentLoaded",S,!1),e.removeEventListener("load",S,!1),x.ready()};x.fn=x.prototype={jquery:p,constructor:x,init:function(e,t,n){var r,i;if(!e)return this;if("string"==typeof e){if(r="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:T.exec(e),!r||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof x?t[0]:t,x.merge(this,x.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:o,!0)),C.test(r[1])&&x.isPlainObject(t))for(r in t)x.isFunction(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return i=o.getElementById(r[2]),i&&i.parentNode&&(this.length=1,this[0]=i),this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?n.ready(e):(e.selector!==undefined&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return d.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,t,n,r,i,o,s=arguments[0]||{},a=1,u=arguments.length,l=!1;for("boolean"==typeof s&&(l=s,s=arguments[1]||{},a=2),"object"==typeof s||x.isFunction(s)||(s={}),u===a&&(s=this,--a);u>a;a++)if(null!=(e=arguments[a]))for(t in e)n=s[t],r=e[t],s!==r&&(l&&r&&(x.isPlainObject(r)||(i=x.isArray(r)))?(i?(i=!1,o=n&&x.isArray(n)?n:[]):o=n&&x.isPlainObject(n)?n:{},s[t]=x.extend(l,o,r)):r!==undefined&&(s[t]=r));return s},x.extend({expando:"jQuery"+(p+Math.random()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=a),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){(e===!0?--x.readyWait:x.isReady)||(x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(o,[x]),x.fn.trigger&&x(o).trigger("ready").off("ready")))},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray,isWindow:function(e){return null!=e&&e===e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if("object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(t){return!1}return!0},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:JSON.parse,parseXML:function(e){var t,n;if(!e||"string"!=typeof e)return null;try{n=new DOMParser,t=n.parseFromString(e,"text/xml")}catch(r){t=undefined}return(!t||t.getElementsByTagName("parsererror").length)&&x.error("Invalid XML: "+e),t},noop:function(){},globalEval:function(e){var t,n=eval;e=x.trim(e),e&&(1===e.indexOf("use strict")?(t=o.createElement("script"),t.text=e,o.head.appendChild(t).parentNode.removeChild(t)):n(e))},camelCase:function(e){return e.replace(k,"ms-").replace(N,E)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,s=j(e);if(n){if(s){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(s){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:function(e){return null==e?"":v.call(e)},makeArray:function(e,t){var n=t||[];return null!=e&&(j(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:g.call(t,e,n)},merge:function(e,t){var n=t.length,r=e.length,i=0;if("number"==typeof n)for(;n>i;i++)e[r++]=t[i];else while(t[i]!==undefined)e[r++]=t[i++];return e.length=r,e},grep:function(e,t,n){var r,i=[],o=0,s=e.length;for(n=!!n;s>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,s=j(e),a=[];if(s)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(a[a.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(a[a.length]=r);return f.apply([],a)},guid:1,proxy:function(e,t){var n,r,i;return"string"==typeof t&&(n=e[t],t=e,e=n),x.isFunction(e)?(r=d.call(arguments,2),i=function(){return e.apply(t||this,r.concat(d.call(arguments)))},i.guid=e.guid=e.guid||x.guid++,i):undefined},access:function(e,t,n,r,i,o,s){var a=0,u=e.length,l=null==n;if("object"===x.type(n)){i=!0;for(a in n)x.access(e,t,a,n[a],!0,o,s)}else if(r!==undefined&&(i=!0,x.isFunction(r)||(s=!0),l&&(s?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(x(e),n)})),t))for(;u>a;a++)t(e[a],n,s?r:r.call(e[a],a,t(e[a],n)));return i?e:l?t.call(e):u?t(e[0],n):o},now:Date.now,swap:function(e,t,n,r){var i,o,s={};for(o in t)s[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=s[o];return i}}),x.ready.promise=function(t){return n||(n=x.Deferred(),"complete"===o.readyState?setTimeout(x.ready):(o.addEventListener("DOMContentLoaded",S,!1),e.addEventListener("load",S,!1))),n.promise(t)},x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){l["[object "+t+"]"]=t.toLowerCase()});function j(e){var t=e.length,n=x.type(e);return x.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}t=x(o),function(e,undefined){var t,n,r,i,o,s,a,u,l,c,p,f,h,d,g,m,y,v="sizzle"+-new Date,b=e.document,w=0,T=0,C=st(),k=st(),N=st(),E=!1,S=function(e,t){return e===t?(E=!0,0):0},j=typeof undefined,D=1<<31,A={}.hasOwnProperty,L=[],q=L.pop,H=L.push,O=L.push,F=L.slice,P=L.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},R="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",W="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",$=W.replace("w","w#"),B="\\["+M+"*("+W+")"+M+"*(?:([*^$|!~]?=)"+M+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+$+")|)|)"+M+"*\\]",I=":("+W+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+B.replace(3,8)+")*)|.*)\\)|)",z=RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),_=RegExp("^"+M+"*,"+M+"*"),X=RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=RegExp(M+"*[+~]"),Y=RegExp("="+M+"*([^\\]'\"]*)"+M+"*\\]","g"),V=RegExp(I),G=RegExp("^"+$+"$"),J={ID:RegExp("^#("+W+")"),CLASS:RegExp("^\\.("+W+")"),TAG:RegExp("^("+W.replace("w","w*")+")"),ATTR:RegExp("^"+B),PSEUDO:RegExp("^"+I),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:RegExp("^(?:"+R+")$","i"),needsContext:RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Q=/^[^{]+\{\s*\[native \w/,K=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,Z=/^(?:input|select|textarea|button)$/i,et=/^h\d$/i,tt=/'|\\/g,nt=RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),rt=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:0>r?String.fromCharCode(r+65536):String.fromCharCode(55296|r>>10,56320|1023&r)};try{O.apply(L=F.call(b.childNodes),b.childNodes),L[b.childNodes.length].nodeType}catch(it){O={apply:L.length?function(e,t){H.apply(e,F.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function ot(e,t,r,i){var o,s,a,u,l,f,g,m,x,w;if((t?t.ownerDocument||t:b)!==p&&c(t),t=t||p,r=r||[],!e||"string"!=typeof e)return r;if(1!==(u=t.nodeType)&&9!==u)return[];if(h&&!i){if(o=K.exec(e))if(a=o[1]){if(9===u){if(s=t.getElementById(a),!s||!s.parentNode)return r;if(s.id===a)return r.push(s),r}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(a))&&y(t,s)&&s.id===a)return r.push(s),r}else{if(o[2])return O.apply(r,t.getElementsByTagName(e)),r;if((a=o[3])&&n.getElementsByClassName&&t.getElementsByClassName)return O.apply(r,t.getElementsByClassName(a)),r}if(n.qsa&&(!d||!d.test(e))){if(m=g=v,x=t,w=9===u&&e,1===u&&"object"!==t.nodeName.toLowerCase()){f=gt(e),(g=t.getAttribute("id"))?m=g.replace(tt,"\\$&"):t.setAttribute("id",m),m="[id='"+m+"'] ",l=f.length;while(l--)f[l]=m+mt(f[l]);x=U.test(e)&&t.parentNode||t,w=f.join(",")}if(w)try{return O.apply(r,x.querySelectorAll(w)),r}catch(T){}finally{g||t.removeAttribute("id")}}}return kt(e.replace(z,"$1"),t,r,i)}function st(){var e=[];function t(n,r){return e.push(n+=" ")>i.cacheLength&&delete t[e.shift()],t[n]=r}return t}function at(e){return e[v]=!0,e}function ut(e){var t=p.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function lt(e,t){var n=e.split("|"),r=e.length;while(r--)i.attrHandle[n[r]]=t}function ct(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||D)-(~e.sourceIndex||D);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function pt(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function ft(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function ht(e){return at(function(t){return t=+t,at(function(n,r){var i,o=e([],n.length,t),s=o.length;while(s--)n[i=o[s]]&&(n[i]=!(r[i]=n[i]))})})}s=ot.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},n=ot.support={},c=ot.setDocument=function(e){var t=e?e.ownerDocument||e:b,r=t.defaultView;return t!==p&&9===t.nodeType&&t.documentElement?(p=t,f=t.documentElement,h=!s(t),r&&r.attachEvent&&r!==r.top&&r.attachEvent("onbeforeunload",function(){c()}),n.attributes=ut(function(e){return e.className="i",!e.getAttribute("className")}),n.getElementsByTagName=ut(function(e){return e.appendChild(t.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=ut(function(e){return e.innerHTML="
",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),n.getById=ut(function(e){return f.appendChild(e).id=v,!t.getElementsByName||!t.getElementsByName(v).length}),n.getById?(i.find.ID=function(e,t){if(typeof t.getElementById!==j&&h){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},i.filter.ID=function(e){var t=e.replace(nt,rt);return function(e){return e.getAttribute("id")===t}}):(delete i.find.ID,i.filter.ID=function(e){var t=e.replace(nt,rt);return function(e){var n=typeof e.getAttributeNode!==j&&e.getAttributeNode("id");return n&&n.value===t}}),i.find.TAG=n.getElementsByTagName?function(e,t){return typeof t.getElementsByTagName!==j?t.getElementsByTagName(e):undefined}: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},i.find.CLASS=n.getElementsByClassName&&function(e,t){return typeof t.getElementsByClassName!==j&&h?t.getElementsByClassName(e):undefined},g=[],d=[],(n.qsa=Q.test(t.querySelectorAll))&&(ut(function(e){e.innerHTML="",e.querySelectorAll("[selected]").length||d.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll(":checked").length||d.push(":checked")}),ut(function(e){var n=t.createElement("input");n.setAttribute("type","hidden"),e.appendChild(n).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&d.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||d.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),d.push(",.*:")})),(n.matchesSelector=Q.test(m=f.webkitMatchesSelector||f.mozMatchesSelector||f.oMatchesSelector||f.msMatchesSelector))&&ut(function(e){n.disconnectedMatch=m.call(e,"div"),m.call(e,"[s!='']:x"),g.push("!=",I)}),d=d.length&&RegExp(d.join("|")),g=g.length&&RegExp(g.join("|")),y=Q.test(f.contains)||f.compareDocumentPosition?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},S=f.compareDocumentPosition?function(e,r){if(e===r)return E=!0,0;var i=r.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(r);return i?1&i||!n.sortDetached&&r.compareDocumentPosition(e)===i?e===t||y(b,e)?-1:r===t||y(b,r)?1:l?P.call(l,e)-P.call(l,r):0:4&i?-1:1:e.compareDocumentPosition?-1:1}:function(e,n){var r,i=0,o=e.parentNode,s=n.parentNode,a=[e],u=[n];if(e===n)return E=!0,0;if(!o||!s)return e===t?-1:n===t?1:o?-1:s?1:l?P.call(l,e)-P.call(l,n):0;if(o===s)return ct(e,n);r=e;while(r=r.parentNode)a.unshift(r);r=n;while(r=r.parentNode)u.unshift(r);while(a[i]===u[i])i++;return i?ct(a[i],u[i]):a[i]===b?-1:u[i]===b?1:0},t):p},ot.matches=function(e,t){return ot(e,null,null,t)},ot.matchesSelector=function(e,t){if((e.ownerDocument||e)!==p&&c(e),t=t.replace(Y,"='$1']"),!(!n.matchesSelector||!h||g&&g.test(t)||d&&d.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(i){}return ot(t,p,null,[e]).length>0},ot.contains=function(e,t){return(e.ownerDocument||e)!==p&&c(e),y(e,t)},ot.attr=function(e,t){(e.ownerDocument||e)!==p&&c(e);var r=i.attrHandle[t.toLowerCase()],o=r&&A.call(i.attrHandle,t.toLowerCase())?r(e,t,!h):undefined;return o===undefined?n.attributes||!h?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null:o},ot.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},ot.uniqueSort=function(e){var t,r=[],i=0,o=0;if(E=!n.detectDuplicates,l=!n.sortStable&&e.slice(0),e.sort(S),E){while(t=e[o++])t===e[o]&&(i=r.push(o));while(i--)e.splice(r[i],1)}return e},o=ot.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=o(t);return n},i=ot.selectors={cacheLength:50,createPseudo:at,match:J,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(nt,rt),e[3]=(e[4]||e[5]||"").replace(nt,rt),"~="===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]||ot.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]&&ot.error(e[0]),e},PSEUDO:function(e){var t,n=!e[5]&&e[2];return J.CHILD.test(e[0])?null:(e[3]&&e[4]!==undefined?e[2]=e[4]:n&&V.test(n)&&(t=gt(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(nt,rt).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=C[e+" "];return t||(t=RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&C(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==j&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=ot.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),s="last"!==e.slice(-4),a="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,p,f,h,d,g=o!==s?"nextSibling":"previousSibling",m=t.parentNode,y=a&&t.nodeName.toLowerCase(),x=!u&&!a;if(m){if(o){while(g){p=t;while(p=p[g])if(a?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;d=g="only"===e&&!d&&"nextSibling"}return!0}if(d=[s?m.firstChild:m.lastChild],s&&x){c=m[v]||(m[v]={}),l=c[e]||[],h=l[0]===w&&l[1],f=l[0]===w&&l[2],p=h&&m.childNodes[h];while(p=++h&&p&&p[g]||(f=h=0)||d.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[w,h,f];break}}else if(x&&(l=(t[v]||(t[v]={}))[e])&&l[0]===w)f=l[1];else while(p=++h&&p&&p[g]||(f=h=0)||d.pop())if((a?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(x&&((p[v]||(p[v]={}))[e]=[w,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||ot.error("unsupported pseudo: "+e);return r[v]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?at(function(e,n){var i,o=r(e,t),s=o.length;while(s--)i=P.call(e,o[s]),e[i]=!(n[i]=o[s])}):function(e){return r(e,0,n)}):r}},pseudos:{not:at(function(e){var t=[],n=[],r=a(e.replace(z,"$1"));return r[v]?at(function(e,t,n,i){var o,s=r(e,null,i,[]),a=e.length;while(a--)(o=s[a])&&(e[a]=!(t[a]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:at(function(e){return function(t){return ot(e,t).length>0}}),contains:at(function(e){return function(t){return(t.textContent||t.innerText||o(t)).indexOf(e)>-1}}),lang:at(function(e){return G.test(e||"")||ot.error("unsupported lang: "+e),e=e.replace(nt,rt).toLowerCase(),function(t){var n;do if(n=h?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===f},focus:function(e){return e===p.activeElement&&(!p.hasFocus||p.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!i.pseudos.empty(e)},header:function(e){return et.test(e.nodeName)},input:function(e){return Z.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:ht(function(){return[0]}),last:ht(function(e,t){return[t-1]}),eq:ht(function(e,t,n){return[0>n?n+t:n]}),even:ht(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:ht(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:ht(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:ht(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}},i.pseudos.nth=i.pseudos.eq;for(t in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})i.pseudos[t]=pt(t);for(t in{submit:!0,reset:!0})i.pseudos[t]=ft(t);function dt(){}dt.prototype=i.filters=i.pseudos,i.setFilters=new dt;function gt(e,t){var n,r,o,s,a,u,l,c=k[e+" "];if(c)return t?0:c.slice(0);a=e,u=[],l=i.preFilter;while(a){(!n||(r=_.exec(a)))&&(r&&(a=a.slice(r[0].length)||a),u.push(o=[])),n=!1,(r=X.exec(a))&&(n=r.shift(),o.push({value:n,type:r[0].replace(z," ")}),a=a.slice(n.length));for(s in i.filter)!(r=J[s].exec(a))||l[s]&&!(r=l[s](r))||(n=r.shift(),o.push({value:n,type:s,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?ot.error(e):k(e,u).slice(0)}function mt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function yt(e,t,n){var i=t.dir,o=n&&"parentNode"===i,s=T++;return t.first?function(t,n,r){while(t=t[i])if(1===t.nodeType||o)return e(t,n,r)}:function(t,n,a){var u,l,c,p=w+" "+s;if(a){while(t=t[i])if((1===t.nodeType||o)&&e(t,n,a))return!0}else while(t=t[i])if(1===t.nodeType||o)if(c=t[v]||(t[v]={}),(l=c[i])&&l[0]===p){if((u=l[1])===!0||u===r)return u===!0}else if(l=c[i]=[p],l[1]=e(t,n,a)||r,l[1]===!0)return!0}}function vt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function xt(e,t,n,r,i){var o,s=[],a=0,u=e.length,l=null!=t;for(;u>a;a++)(o=e[a])&&(!n||n(o,r,i))&&(s.push(o),l&&t.push(a));return s}function bt(e,t,n,r,i,o){return r&&!r[v]&&(r=bt(r)),i&&!i[v]&&(i=bt(i,o)),at(function(o,s,a,u){var l,c,p,f=[],h=[],d=s.length,g=o||Ct(t||"*",a.nodeType?[a]:a,[]),m=!e||!o&&t?g:xt(g,f,e,a,u),y=n?i||(o?e:d||r)?[]:s:m;if(n&&n(m,y,a,u),r){l=xt(y,h),r(l,[],a,u),c=l.length;while(c--)(p=l[c])&&(y[h[c]]=!(m[h[c]]=p))}if(o){if(i||e){if(i){l=[],c=y.length;while(c--)(p=y[c])&&l.push(m[c]=p);i(null,y=[],l,u)}c=y.length;while(c--)(p=y[c])&&(l=i?P.call(o,p):f[c])>-1&&(o[l]=!(s[l]=p))}}else y=xt(y===s?y.splice(d,y.length):y),i?i(null,s,y,u):O.apply(s,y)})}function wt(e){var t,n,r,o=e.length,s=i.relative[e[0].type],a=s||i.relative[" "],l=s?1:0,c=yt(function(e){return e===t},a,!0),p=yt(function(e){return P.call(t,e)>-1},a,!0),f=[function(e,n,r){return!s&&(r||n!==u)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;o>l;l++)if(n=i.relative[e[l].type])f=[yt(vt(f),n)];else{if(n=i.filter[e[l].type].apply(null,e[l].matches),n[v]){for(r=++l;o>r;r++)if(i.relative[e[r].type])break;return bt(l>1&&vt(f),l>1&&mt(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(z,"$1"),n,r>l&&wt(e.slice(l,r)),o>r&&wt(e=e.slice(r)),o>r&&mt(e))}f.push(n)}return vt(f)}function Tt(e,t){var n=0,o=t.length>0,s=e.length>0,a=function(a,l,c,f,h){var d,g,m,y=[],v=0,x="0",b=a&&[],T=null!=h,C=u,k=a||s&&i.find.TAG("*",h&&l.parentNode||l),N=w+=null==C?1:Math.random()||.1;for(T&&(u=l!==p&&l,r=n);null!=(d=k[x]);x++){if(s&&d){g=0;while(m=e[g++])if(m(d,l,c)){f.push(d);break}T&&(w=N,r=++n)}o&&((d=!m&&d)&&v--,a&&b.push(d))}if(v+=x,o&&x!==v){g=0;while(m=t[g++])m(b,y,l,c);if(a){if(v>0)while(x--)b[x]||y[x]||(y[x]=q.call(f));y=xt(y)}O.apply(f,y),T&&!a&&y.length>0&&v+t.length>1&&ot.uniqueSort(f)}return T&&(w=N,u=C),b};return o?at(a):a}a=ot.compile=function(e,t){var n,r=[],i=[],o=N[e+" "];if(!o){t||(t=gt(e)),n=t.length;while(n--)o=wt(t[n]),o[v]?r.push(o):i.push(o);o=N(e,Tt(i,r))}return o};function Ct(e,t,n){var r=0,i=t.length;for(;i>r;r++)ot(e,t[r],n);return n}function kt(e,t,r,o){var s,u,l,c,p,f=gt(e);if(!o&&1===f.length){if(u=f[0]=f[0].slice(0),u.length>2&&"ID"===(l=u[0]).type&&n.getById&&9===t.nodeType&&h&&i.relative[u[1].type]){if(t=(i.find.ID(l.matches[0].replace(nt,rt),t)||[])[0],!t)return r;e=e.slice(u.shift().value.length)}s=J.needsContext.test(e)?0:u.length;while(s--){if(l=u[s],i.relative[c=l.type])break;if((p=i.find[c])&&(o=p(l.matches[0].replace(nt,rt),U.test(u[0].type)&&t.parentNode||t))){if(u.splice(s,1),e=o.length&&mt(u),!e)return O.apply(r,o),r;break}}}return a(e,f)(o,t,!h,r,U.test(e)),r}n.sortStable=v.split("").sort(S).join("")===v,n.detectDuplicates=E,c(),n.sortDetached=ut(function(e){return 1&e.compareDocumentPosition(p.createElement("div"))}),ut(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||lt("type|href|height|width",function(e,t,n){return n?undefined:e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),n.attributes&&ut(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||lt("value",function(e,t,n){return n||"input"!==e.nodeName.toLowerCase()?undefined:e.defaultValue}),ut(function(e){return null==e.getAttribute("disabled")})||lt(R,function(e,t,n){var r;return n?undefined:(r=e.getAttributeNode(t))&&r.specified?r.value:e[t]===!0?t.toLowerCase():null}),x.find=ot,x.expr=ot.selectors,x.expr[":"]=x.expr.pseudos,x.unique=ot.uniqueSort,x.text=ot.getText,x.isXMLDoc=ot.isXML,x.contains=ot.contains}(e);var D={};function A(e){var t=D[e]={};return x.each(e.match(w)||[],function(e,n){t[n]=!0}),t}x.Callbacks=function(e){e="string"==typeof e?D[e]||A(e):x.extend({},e);var t,n,r,i,o,s,a=[],u=!e.once&&[],l=function(p){for(t=e.memory&&p,n=!0,s=i||0,i=0,o=a.length,r=!0;a&&o>s;s++)if(a[s].apply(p[0],p[1])===!1&&e.stopOnFalse){t=!1;break}r=!1,a&&(u?u.length&&l(u.shift()):t?a=[]:c.disable())},c={add:function(){if(a){var n=a.length;(function s(t){x.each(t,function(t,n){var r=x.type(n);"function"===r?e.unique&&c.has(n)||a.push(n):n&&n.length&&"string"!==r&&s(n)})})(arguments),r?o=a.length:t&&(i=n,l(t))}return this},remove:function(){return a&&x.each(arguments,function(e,t){var n;while((n=x.inArray(t,a,n))>-1)a.splice(n,1),r&&(o>=n&&o--,s>=n&&s--)}),this},has:function(e){return e?x.inArray(e,a)>-1:!(!a||!a.length)},empty:function(){return a=[],o=0,this},disable:function(){return a=u=t=undefined,this},disabled:function(){return!a},lock:function(){return u=undefined,t||c.disable(),this},locked:function(){return!u},fireWith:function(e,t){return!a||n&&!u||(t=t||[],t=[e,t.slice?t.slice():t],r?u.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!n}};return c},x.extend({Deferred:function(e){var t=[["resolve","done",x.Callbacks("once memory"),"resolved"],["reject","fail",x.Callbacks("once memory"),"rejected"],["notify","progress",x.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return x.Deferred(function(n){x.each(t,function(t,o){var s=o[0],a=x.isFunction(e[t])&&e[t];i[o[1]](function(){var e=a&&a.apply(this,arguments);e&&x.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===r?n.promise():this,a?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?x.extend(e,r):r}},i={};return r.pipe=r.then,x.each(t,function(e,o){var s=o[2],a=o[3];r[o[1]]=s.add,a&&s.add(function(){n=a},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=s.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=d.call(arguments),r=n.length,i=1!==r||e&&x.isFunction(e.promise)?r:0,o=1===i?e:x.Deferred(),s=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?d.call(arguments):r,n===a?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},a,u,l;if(r>1)for(a=Array(r),u=Array(r),l=Array(r);r>t;t++)n[t]&&x.isFunction(n[t].promise)?n[t].promise().done(s(t,l,n)).fail(o.reject).progress(s(t,u,a)):--i;return i||o.resolveWith(l,n),o.promise()}}),x.support=function(t){var n=o.createElement("input"),r=o.createDocumentFragment(),i=o.createElement("div"),s=o.createElement("select"),a=s.appendChild(o.createElement("option"));return n.type?(n.type="checkbox",t.checkOn=""!==n.value,t.optSelected=a.selected,t.reliableMarginRight=!0,t.boxSizingReliable=!0,t.pixelPosition=!1,n.checked=!0,t.noCloneChecked=n.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!a.disabled,n=o.createElement("input"),n.value="t",n.type="radio",t.radioValue="t"===n.value,n.setAttribute("checked","t"),n.setAttribute("name","t"),r.appendChild(n),t.checkClone=r.cloneNode(!0).cloneNode(!0).lastChild.checked,t.focusinBubbles="onfocusin"in e,i.style.backgroundClip="content-box",i.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===i.style.backgroundClip,x(function(){var n,r,s="padding:0;margin:0;border:0;display:block;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box",a=o.getElementsByTagName("body")[0];a&&(n=o.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",a.appendChild(n).appendChild(i),i.innerHTML="",i.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%",x.swap(a,null!=a.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===i.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(i,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(i,null)||{width:"4px"}).width,r=i.appendChild(o.createElement("div")),r.style.cssText=i.style.cssText=s,r.style.marginRight=r.style.width="0",i.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),a.removeChild(n))}),t):t}({});var L,q,H=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,O=/([A-Z])/g;function F(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=x.expando+Math.random()}F.uid=1,F.accepts=function(e){return e.nodeType?1===e.nodeType||9===e.nodeType:!0},F.prototype={key:function(e){if(!F.accepts(e))return 0;var t={},n=e[this.expando];if(!n){n=F.uid++;try{t[this.expando]={value:n},Object.defineProperties(e,t)}catch(r){t[this.expando]=n,x.extend(e,t)}}return this.cache[n]||(this.cache[n]={}),n},set:function(e,t,n){var r,i=this.key(e),o=this.cache[i];if("string"==typeof t)o[t]=n;else if(x.isEmptyObject(o))x.extend(this.cache[i],t);else for(r in t)o[r]=t[r];return o},get:function(e,t){var n=this.cache[this.key(e)];return t===undefined?n:n[t]},access:function(e,t,n){var r;return t===undefined||t&&"string"==typeof t&&n===undefined?(r=this.get(e,t),r!==undefined?r:this.get(e,x.camelCase(t))):(this.set(e,t,n),n!==undefined?n:t)},remove:function(e,t){var n,r,i,o=this.key(e),s=this.cache[o];if(t===undefined)this.cache[o]={};else{x.isArray(t)?r=t.concat(t.map(x.camelCase)):(i=x.camelCase(t),t in s?r=[t,i]:(r=i,r=r in s?[r]:r.match(w)||[])),n=r.length;while(n--)delete s[r[n]]}},hasData:function(e){return!x.isEmptyObject(this.cache[e[this.expando]]||{})},discard:function(e){e[this.expando]&&delete this.cache[e[this.expando]]}},L=new F,q=new F,x.extend({acceptData:F.accepts,hasData:function(e){return L.hasData(e)||q.hasData(e)},data:function(e,t,n){return L.access(e,t,n)},removeData:function(e,t){L.remove(e,t)},_data:function(e,t,n){return q.access(e,t,n)},_removeData:function(e,t){q.remove(e,t)}}),x.fn.extend({data:function(e,t){var n,r,i=this[0],o=0,s=null;if(e===undefined){if(this.length&&(s=L.get(i),1===i.nodeType&&!q.get(i,"hasDataAttrs"))){for(n=i.attributes;n.length>o;o++)r=n[o].name,0===r.indexOf("data-")&&(r=x.camelCase(r.slice(5)),P(i,r,s[r]));q.set(i,"hasDataAttrs",!0)}return s}return"object"==typeof e?this.each(function(){L.set(this,e)}):x.access(this,function(t){var n,r=x.camelCase(e);if(i&&t===undefined){if(n=L.get(i,e),n!==undefined)return n;if(n=L.get(i,r),n!==undefined)return n;if(n=P(i,r,undefined),n!==undefined)return n}else this.each(function(){var n=L.get(this,r);L.set(this,r,t),-1!==e.indexOf("-")&&n!==undefined&&L.set(this,e,t)})},null,t,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){L.remove(this,e)})}});function P(e,t,n){var r;if(n===undefined&&1===e.nodeType)if(r="data-"+t.replace(O,"-$1").toLowerCase(),n=e.getAttribute(r),"string"==typeof n){try{n="true"===n?!0:"false"===n?!1:"null"===n?null:+n+""===n?+n:H.test(n)?JSON.parse(n):n}catch(i){}L.set(e,t,n)}else n=undefined;return n}x.extend({queue:function(e,t,n){var r;return e?(t=(t||"fx")+"queue",r=q.get(e,t),n&&(!r||x.isArray(n)?r=q.access(e,t,x.makeArray(n)):r.push(n)),r||[]):undefined},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),s=function(){x.dequeue(e,t) -};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,s,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return q.get(e,n)||q.access(e,n,{empty:x.Callbacks("once memory").add(function(){q.remove(e,[t+"queue",n])})})}}),x.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),n>arguments.length?x.queue(this[0],e):t===undefined?this:this.each(function(){var n=x.queue(this,e,t);x._queueHooks(this,e),"fx"===e&&"inprogress"!==n[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=x.Deferred(),o=this,s=this.length,a=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=undefined),e=e||"fx";while(s--)n=q.get(o[s],e+"queueHooks"),n&&n.empty&&(r++,n.empty.add(a));return a(),i.promise(t)}});var R,M,W=/[\t\r\n\f]/g,$=/\r/g,B=/^(?:input|select|textarea|button)$/i;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[x.propFix[e]||e]})},addClass:function(e){var t,n,r,i,o,s=0,a=this.length,u="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];a>s;s++)if(n=this[s],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(W," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,s=0,a=this.length,u=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];a>s;s++)if(n=this[s],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(W," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var t,i=0,o=x(this),s=e.match(w)||[];while(t=s[i++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else(n===r||"boolean"===n)&&(this.className&&q.set(this,"__className__",this.className),this.className=this.className||e===!1?"":q.get(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(W," ").indexOf(t)>=0)return!0;return!1},val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=x.isFunction(e),this.each(function(n){var i;1===this.nodeType&&(i=r?e.call(this,n,x(this).val()):e,null==i?i="":"number"==typeof i?i+="":x.isArray(i)&&(i=x.map(i,function(e){return null==e?"":e+""})),t=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],t&&"set"in t&&t.set(this,i,"value")!==undefined||(this.value=i))});if(i)return t=x.valHooks[i.type]||x.valHooks[i.nodeName.toLowerCase()],t&&"get"in t&&(n=t.get(i,"value"))!==undefined?n:(n=i.value,"string"==typeof n?n.replace($,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,s=o?null:[],a=o?i+1:r.length,u=0>i?a:o?i:0;for(;a>u;u++)if(n=r[u],!(!n.selected&&u!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),s=i.length;while(s--)r=i[s],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,t,n){var i,o,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===r?x.prop(e,t,n):(1===s&&x.isXMLDoc(e)||(t=t.toLowerCase(),i=x.attrHooks[t]||(x.expr.match.bool.test(t)?M:R)),n===undefined?i&&"get"in i&&null!==(o=i.get(e,t))?o:(o=x.find.attr(e,t),null==o?undefined:o):null!==n?i&&"set"in i&&(o=i.set(e,n,t))!==undefined?o:(e.setAttribute(t,n+""),n):(x.removeAttr(e,t),undefined))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(w);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.bool.test(n)&&(e[r]=!1),e.removeAttribute(n)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,t,n){var r,i,o,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return o=1!==s||!x.isXMLDoc(e),o&&(t=x.propFix[t]||t,i=x.propHooks[t]),n!==undefined?i&&"set"in i&&(r=i.set(e,n,t))!==undefined?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){return e.hasAttribute("tabindex")||B.test(e.nodeName)||e.href?e.tabIndex:-1}}}}),M={set:function(e,t,n){return t===!1?x.removeAttr(e,n):e.setAttribute(n,n),n}},x.each(x.expr.match.bool.source.match(/\w+/g),function(e,t){var n=x.expr.attrHandle[t]||x.find.attr;x.expr.attrHandle[t]=function(e,t,r){var i=x.expr.attrHandle[t],o=r?undefined:(x.expr.attrHandle[t]=undefined)!=n(e,t,r)?t.toLowerCase():null;return x.expr.attrHandle[t]=i,o}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,t){return x.isArray(t)?e.checked=x.inArray(x(e).val(),t)>=0:undefined}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var I=/^key/,z=/^(?:mouse|contextmenu)|click/,_=/^(?:focusinfocus|focusoutblur)$/,X=/^([^.]*)(?:\.(.+)|)$/;function U(){return!0}function Y(){return!1}function V(){try{return o.activeElement}catch(e){}}x.event={global:{},add:function(e,t,n,i,o){var s,a,u,l,c,p,f,h,d,g,m,y=q.get(e);if(y){n.handler&&(s=n,n=s.handler,o=s.selector),n.guid||(n.guid=x.guid++),(l=y.events)||(l=y.events={}),(a=y.handle)||(a=y.handle=function(e){return typeof x===r||e&&x.event.triggered===e.type?undefined:x.event.dispatch.apply(a.elem,arguments)},a.elem=e),t=(t||"").match(w)||[""],c=t.length;while(c--)u=X.exec(t[c])||[],d=m=u[1],g=(u[2]||"").split(".").sort(),d&&(f=x.event.special[d]||{},d=(o?f.delegateType:f.bindType)||d,f=x.event.special[d]||{},p=x.extend({type:d,origType:m,data:i,handler:n,guid:n.guid,selector:o,needsContext:o&&x.expr.match.needsContext.test(o),namespace:g.join(".")},s),(h=l[d])||(h=l[d]=[],h.delegateCount=0,f.setup&&f.setup.call(e,i,g,a)!==!1||e.addEventListener&&e.addEventListener(d,a,!1)),f.add&&(f.add.call(e,p),p.handler.guid||(p.handler.guid=n.guid)),o?h.splice(h.delegateCount++,0,p):h.push(p),x.event.global[d]=!0);e=null}},remove:function(e,t,n,r,i){var o,s,a,u,l,c,p,f,h,d,g,m=q.hasData(e)&&q.get(e);if(m&&(u=m.events)){t=(t||"").match(w)||[""],l=t.length;while(l--)if(a=X.exec(t[l])||[],h=g=a[1],d=(a[2]||"").split(".").sort(),h){p=x.event.special[h]||{},h=(r?p.delegateType:p.bindType)||h,f=u[h]||[],a=a[2]&&RegExp("(^|\\.)"+d.join("\\.(?:.*\\.|)")+"(\\.|$)"),s=o=f.length;while(o--)c=f[o],!i&&g!==c.origType||n&&n.guid!==c.guid||a&&!a.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(f.splice(o,1),c.selector&&f.delegateCount--,p.remove&&p.remove.call(e,c));s&&!f.length&&(p.teardown&&p.teardown.call(e,d,m.handle)!==!1||x.removeEvent(e,h,m.handle),delete u[h])}else for(h in u)x.event.remove(e,h+t[l],n,r,!0);x.isEmptyObject(u)&&(delete m.handle,q.remove(e,"events"))}},trigger:function(t,n,r,i){var s,a,u,l,c,p,f,h=[r||o],d=y.call(t,"type")?t.type:t,g=y.call(t,"namespace")?t.namespace.split("."):[];if(a=u=r=r||o,3!==r.nodeType&&8!==r.nodeType&&!_.test(d+x.event.triggered)&&(d.indexOf(".")>=0&&(g=d.split("."),d=g.shift(),g.sort()),c=0>d.indexOf(":")&&"on"+d,t=t[x.expando]?t:new x.Event(d,"object"==typeof t&&t),t.isTrigger=i?2:3,t.namespace=g.join("."),t.namespace_re=t.namespace?RegExp("(^|\\.)"+g.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=undefined,t.target||(t.target=r),n=null==n?[t]:x.makeArray(n,[t]),f=x.event.special[d]||{},i||!f.trigger||f.trigger.apply(r,n)!==!1)){if(!i&&!f.noBubble&&!x.isWindow(r)){for(l=f.delegateType||d,_.test(l+d)||(a=a.parentNode);a;a=a.parentNode)h.push(a),u=a;u===(r.ownerDocument||o)&&h.push(u.defaultView||u.parentWindow||e)}s=0;while((a=h[s++])&&!t.isPropagationStopped())t.type=s>1?l:f.bindType||d,p=(q.get(a,"events")||{})[t.type]&&q.get(a,"handle"),p&&p.apply(a,n),p=c&&a[c],p&&x.acceptData(a)&&p.apply&&p.apply(a,n)===!1&&t.preventDefault();return t.type=d,i||t.isDefaultPrevented()||f._default&&f._default.apply(h.pop(),n)!==!1||!x.acceptData(r)||c&&x.isFunction(r[d])&&!x.isWindow(r)&&(u=r[c],u&&(r[c]=null),x.event.triggered=d,r[d](),x.event.triggered=undefined,u&&(r[c]=u)),t.result}},dispatch:function(e){e=x.event.fix(e);var t,n,r,i,o,s=[],a=d.call(arguments),u=(q.get(this,"events")||{})[e.type]||[],l=x.event.special[e.type]||{};if(a[0]=e,e.delegateTarget=this,!l.preDispatch||l.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),t=0;while((i=s[t++])&&!e.isPropagationStopped()){e.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(o.namespace))&&(e.handleObj=o,e.data=o.data,r=((x.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,a),r!==undefined&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return l.postDispatch&&l.postDispatch.call(this,e),e.result}},handlers:function(e,t){var n,r,i,o,s=[],a=t.delegateCount,u=e.target;if(a&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!==this;u=u.parentNode||this)if(u.disabled!==!0||"click"!==e.type){for(r=[],n=0;a>n;n++)o=t[n],i=o.selector+" ",r[i]===undefined&&(r[i]=o.needsContext?x(i,this).index(u)>=0:x.find(i,this,null,[u]).length),r[i]&&r.push(o);r.length&&s.push({elem:u,handlers:r})}return t.length>a&&s.push({elem:this,handlers:t.slice(a)}),s},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,t){var n,r,i,s=t.button;return null==e.pageX&&null!=t.clientX&&(n=e.target.ownerDocument||o,r=n.documentElement,i=n.body,e.pageX=t.clientX+(r&&r.scrollLeft||i&&i.scrollLeft||0)-(r&&r.clientLeft||i&&i.clientLeft||0),e.pageY=t.clientY+(r&&r.scrollTop||i&&i.scrollTop||0)-(r&&r.clientTop||i&&i.clientTop||0)),e.which||s===undefined||(e.which=1&s?1:2&s?3:4&s?2:0),e}},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,s=e,a=this.fixHooks[i];a||(this.fixHooks[i]=a=z.test(i)?this.mouseHooks:I.test(i)?this.keyHooks:{}),r=a.props?this.props.concat(a.props):this.props,e=new x.Event(s),t=r.length;while(t--)n=r[t],e[n]=s[n];return e.target||(e.target=o),3===e.target.nodeType&&(e.target=e.target.parentNode),a.filter?a.filter(e,s):e},special:{load:{noBubble:!0},focus:{trigger:function(){return this!==V()&&this.focus?(this.focus(),!1):undefined},delegateType:"focusin"},blur:{trigger:function(){return this===V()&&this.blur?(this.blur(),!1):undefined},delegateType:"focusout"},click:{trigger:function(){return"checkbox"===this.type&&this.click&&x.nodeName(this,"input")?(this.click(),!1):undefined},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==undefined&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)},x.Event=function(e,t){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.getPreventDefault&&e.getPreventDefault()?U:Y):this.type=e,t&&x.extend(this,t),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,undefined):new x.Event(e,t)},x.Event.prototype={isDefaultPrevented:Y,isPropagationStopped:Y,isImmediatePropagationStopped:Y,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=U,e&&e.preventDefault&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=U,e&&e.stopPropagation&&e.stopPropagation()},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=U,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,t,n,r,i){var o,s;if("object"==typeof e){"string"!=typeof t&&(n=n||t,t=undefined);for(s in e)this.on(s,t,n,e[s],i);return this}if(null==n&&null==r?(r=t,n=t=undefined):null==r&&("string"==typeof t?(r=n,n=undefined):(r=n,n=t,t=undefined)),r===!1)r=Y;else if(!r)return this;return 1===i&&(o=r,r=function(e){return x().off(e),o.apply(this,arguments)},r.guid=o.guid||(o.guid=x.guid++)),this.each(function(){x.event.add(this,e,r,n,t)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,x(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return(t===!1||"function"==typeof t)&&(n=t,t=undefined),n===!1&&(n=Y),this.each(function(){x.event.remove(this,e,n,t)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];return n?x.event.trigger(e,t,n,!0):undefined}});var G=/^.[^:#\[\.,]*$/,J=/^(?:parents|prev(?:Until|All))/,Q=x.expr.match.needsContext,K={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(x(e).filter(function(){for(t=0;i>t;t++)if(x.contains(r[t],this))return!0}));for(t=0;i>t;t++)x.find(e,r[t],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},has:function(e){var t=x(e,this),n=t.length;return this.filter(function(){var e=0;for(;n>e;e++)if(x.contains(this,t[e]))return!0})},not:function(e){return this.pushStack(et(this,e||[],!0))},filter:function(e){return this.pushStack(et(this,e||[],!1))},is:function(e){return!!et(this,"string"==typeof e&&Q.test(e)?x(e):e||[],!1).length},closest:function(e,t){var n,r=0,i=this.length,o=[],s=Q.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(s?s.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.length>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?g.call(x(e),this[0]):g.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function Z(e,t){while((e=e[t])&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return Z(e,"nextSibling")},prev:function(e){return Z(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},siblings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return e.contentDocument||x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(K[e]||x.unique(i),J.test(e)&&i.reverse()),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,t,n){var r=[],i=n!==undefined;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&x(e).is(n))break;r.push(e)}return r},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function et(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(G.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return g.call(t,e)>=0!==n})}var tt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,nt=/<([\w:]+)/,rt=/<|&#?\w+;/,it=/<(?:script|style|link)/i,ot=/^(?:checkbox|radio)$/i,st=/checked\s*(?:[^=]|=\s*.checked.)/i,at=/^$|\/(?:java|ecma)script/i,ut=/^true\/(.*)/,lt=/^\s*\s*$/g,ct={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ct.optgroup=ct.option,ct.tbody=ct.tfoot=ct.colgroup=ct.caption=ct.thead,ct.th=ct.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===undefined?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||o).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=pt(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=pt(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(mt(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&dt(mt(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++)1===e.nodeType&&(x.cleanData(mt(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var t=this[0]||{},n=0,r=this.length;if(e===undefined&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!it.test(e)&&!ct[(nt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(tt,"<$1>");try{for(;r>n;n++)t=this[n]||{},1===t.nodeType&&(x.cleanData(mt(t,!1)),t.innerHTML=e);t=0}catch(i){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(r&&r.parentNode!==i&&(r=this.nextSibling),x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=f.apply([],e);var r,i,o,s,a,u,l=0,c=this.length,p=this,h=c-1,d=e[0],g=x.isFunction(d);if(g||!(1>=c||"string"!=typeof d||x.support.checkClone)&&st.test(d))return this.each(function(r){var i=p.eq(r);g&&(e[0]=d.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(r=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),i=r.firstChild,1===r.childNodes.length&&(r=i),i)){for(o=x.map(mt(r,"script"),ft),s=o.length;c>l;l++)a=r,l!==h&&(a=x.clone(a,!0,!0),s&&x.merge(o,mt(a,"script"))),t.call(this[l],a,l);if(s)for(u=o[o.length-1].ownerDocument,x.map(o,ht),l=0;s>l;l++)a=o[l],at.test(a.type||"")&&!q.access(a,"globalEval")&&x.contains(u,a)&&(a.src?x._evalUrl(a.src):x.globalEval(a.textContent.replace(lt,"")))}return this}}),x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=[],i=x(e),o=i.length-1,s=0;for(;o>=s;s++)n=s===o?this:this.clone(!0),x(i[s])[t](n),h.apply(r,n.get());return this.pushStack(r)}}),x.extend({clone:function(e,t,n){var r,i,o,s,a=e.cloneNode(!0),u=x.contains(e.ownerDocument,e);if(!(x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(s=mt(a),o=mt(e),r=0,i=o.length;i>r;r++)yt(o[r],s[r]);if(t)if(n)for(o=o||mt(e),s=s||mt(a),r=0,i=o.length;i>r;r++)gt(o[r],s[r]);else gt(e,a);return s=mt(a,"script"),s.length>0&&dt(s,!u&&mt(e,"script")),a},buildFragment:function(e,t,n,r){var i,o,s,a,u,l,c=0,p=e.length,f=t.createDocumentFragment(),h=[];for(;p>c;c++)if(i=e[c],i||0===i)if("object"===x.type(i))x.merge(h,i.nodeType?[i]:i);else if(rt.test(i)){o=o||f.appendChild(t.createElement("div")),s=(nt.exec(i)||["",""])[1].toLowerCase(),a=ct[s]||ct._default,o.innerHTML=a[1]+i.replace(tt,"<$1>")+a[2],l=a[0];while(l--)o=o.lastChild;x.merge(h,o.childNodes),o=f.firstChild,o.textContent=""}else h.push(t.createTextNode(i));f.textContent="",c=0;while(i=h[c++])if((!r||-1===x.inArray(i,r))&&(u=x.contains(i.ownerDocument,i),o=mt(f.appendChild(i),"script"),u&&dt(o),n)){l=0;while(i=o[l++])at.test(i.type||"")&&n.push(i)}return f},cleanData:function(e){var t,n,r,i,o,s,a=x.event.special,u=0;for(;(n=e[u])!==undefined;u++){if(F.accepts(n)&&(o=n[q.expando],o&&(t=q.cache[o]))){if(r=Object.keys(t.events||{}),r.length)for(s=0;(i=r[s])!==undefined;s++)a[i]?x.event.remove(n,i):x.removeEvent(n,i,t.handle);q.cache[o]&&delete q.cache[o]}delete L.cache[n[L.expando]]}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})}});function pt(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function ft(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function ht(e){var t=ut.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function dt(e,t){var n=e.length,r=0;for(;n>r;r++)q.set(e[r],"globalEval",!t||q.get(t[r],"globalEval"))}function gt(e,t){var n,r,i,o,s,a,u,l;if(1===t.nodeType){if(q.hasData(e)&&(o=q.access(e),s=q.set(t,o),l=o.events)){delete s.handle,s.events={};for(i in l)for(n=0,r=l[i].length;r>n;n++)x.event.add(t,i,l[i][n])}L.hasData(e)&&(a=L.access(e),u=x.extend({},a),L.set(t,u))}}function mt(e,t){var n=e.getElementsByTagName?e.getElementsByTagName(t||"*"):e.querySelectorAll?e.querySelectorAll(t||"*"):[];return t===undefined||t&&x.nodeName(e,t)?x.merge([e],n):n}function yt(e,t){var n=t.nodeName.toLowerCase();"input"===n&&ot.test(e.type)?t.checked=e.checked:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}x.fn.extend({wrapAll:function(e){var t;return x.isFunction(e)?this.each(function(t){x(this).wrapAll(e.call(this,t))}):(this[0]&&(t=x(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this)},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var vt,xt,bt=/^(none|table(?!-c[ea]).+)/,wt=/^margin/,Tt=RegExp("^("+b+")(.*)$","i"),Ct=RegExp("^("+b+")(?!px)[a-z%]+$","i"),kt=RegExp("^([+-])=("+b+")","i"),Nt={BODY:"block"},Et={position:"absolute",visibility:"hidden",display:"block"},St={letterSpacing:0,fontWeight:400},jt=["Top","Right","Bottom","Left"],Dt=["Webkit","O","Moz","ms"];function At(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=Dt.length;while(i--)if(t=Dt[i]+n,t in e)return t;return r}function Lt(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function qt(t){return e.getComputedStyle(t,null)}function Ht(e,t){var n,r,i,o=[],s=0,a=e.length;for(;a>s;s++)r=e[s],r.style&&(o[s]=q.get(r,"olddisplay"),n=r.style.display,t?(o[s]||"none"!==n||(r.style.display=""),""===r.style.display&&Lt(r)&&(o[s]=q.access(r,"olddisplay",Rt(r.nodeName)))):o[s]||(i=Lt(r),(n&&"none"!==n||!i)&&q.set(r,"olddisplay",i?n:x.css(r,"display"))));for(s=0;a>s;s++)r=e[s],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[s]||"":"none"));return e}x.fn.extend({css:function(e,t){return x.access(this,function(e,t,n){var r,i,o={},s=0;if(x.isArray(t)){for(r=qt(e),i=t.length;i>s;s++)o[t[s]]=x.css(e,t[s],!1,r);return o}return n!==undefined?x.style(e,t,n):x.css(e,t)},e,t,arguments.length>1)},show:function(){return Ht(this,!0)},hide:function(){return Ht(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){Lt(this)?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=vt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,s,a=x.camelCase(t),u=e.style;return t=x.cssProps[a]||(x.cssProps[a]=At(u,a)),s=x.cssHooks[t]||x.cssHooks[a],n===undefined?s&&"get"in s&&(i=s.get(e,!1,r))!==undefined?i:u[t]:(o=typeof n,"string"===o&&(i=kt.exec(n))&&(n=(i[1]+1)*i[2]+parseFloat(x.css(e,t)),o="number"),null==n||"number"===o&&isNaN(n)||("number"!==o||x.cssNumber[a]||(n+="px"),x.support.clearCloneStyle||""!==n||0!==t.indexOf("background")||(u[t]="inherit"),s&&"set"in s&&(n=s.set(e,n,r))===undefined||(u[t]=n)),undefined)}},css:function(e,t,n,r){var i,o,s,a=x.camelCase(t);return t=x.cssProps[a]||(x.cssProps[a]=At(e.style,a)),s=x.cssHooks[t]||x.cssHooks[a],s&&"get"in s&&(i=s.get(e,!0,n)),i===undefined&&(i=vt(e,t,r)),"normal"===i&&t in St&&(i=St[t]),""===n||n?(o=parseFloat(i),n===!0||x.isNumeric(o)?o||0:i):i}}),vt=function(e,t,n){var r,i,o,s=n||qt(e),a=s?s.getPropertyValue(t)||s[t]:undefined,u=e.style;return s&&(""!==a||x.contains(e.ownerDocument,e)||(a=x.style(e,t)),Ct.test(a)&&wt.test(t)&&(r=u.width,i=u.minWidth,o=u.maxWidth,u.minWidth=u.maxWidth=u.width=a,a=s.width,u.width=r,u.minWidth=i,u.maxWidth=o)),a};function Ot(e,t,n){var r=Tt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function Ft(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,s=0;for(;4>o;o+=2)"margin"===n&&(s+=x.css(e,n+jt[o],!0,i)),r?("content"===n&&(s-=x.css(e,"padding"+jt[o],!0,i)),"margin"!==n&&(s-=x.css(e,"border"+jt[o]+"Width",!0,i))):(s+=x.css(e,"padding"+jt[o],!0,i),"padding"!==n&&(s+=x.css(e,"border"+jt[o]+"Width",!0,i)));return s}function Pt(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=qt(e),s=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=vt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Ct.test(i))return i;r=s&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+Ft(e,t,n||(s?"border":"content"),r,o)+"px"}function Rt(e){var t=o,n=Nt[e];return n||(n=Mt(e,t),"none"!==n&&n||(xt=(xt||x("